xref: /openbmc/linux/drivers/clk/sunxi-ng/ccu_gate.c (revision 551b62b1)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21a7e7c38SMaxime Ripard /*
31a7e7c38SMaxime Ripard  * Copyright (C) 2016 Maxime Ripard
41a7e7c38SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
51a7e7c38SMaxime Ripard  */
61a7e7c38SMaxime Ripard 
71a7e7c38SMaxime Ripard #include <linux/clk-provider.h>
862e59c4eSStephen Boyd #include <linux/io.h>
91a7e7c38SMaxime Ripard 
101a7e7c38SMaxime Ripard #include "ccu_gate.h"
111a7e7c38SMaxime Ripard 
ccu_gate_helper_disable(struct ccu_common * common,u32 gate)121a7e7c38SMaxime Ripard void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
131a7e7c38SMaxime Ripard {
141a7e7c38SMaxime Ripard 	unsigned long flags;
151a7e7c38SMaxime Ripard 	u32 reg;
161a7e7c38SMaxime Ripard 
171a7e7c38SMaxime Ripard 	if (!gate)
181a7e7c38SMaxime Ripard 		return;
191a7e7c38SMaxime Ripard 
201a7e7c38SMaxime Ripard 	spin_lock_irqsave(common->lock, flags);
211a7e7c38SMaxime Ripard 
221a7e7c38SMaxime Ripard 	reg = readl(common->base + common->reg);
231a7e7c38SMaxime Ripard 	writel(reg & ~gate, common->base + common->reg);
241a7e7c38SMaxime Ripard 
251a7e7c38SMaxime Ripard 	spin_unlock_irqrestore(common->lock, flags);
261a7e7c38SMaxime Ripard }
27*551b62b1SSamuel Holland EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU);
281a7e7c38SMaxime Ripard 
ccu_gate_disable(struct clk_hw * hw)291a7e7c38SMaxime Ripard static void ccu_gate_disable(struct clk_hw *hw)
301a7e7c38SMaxime Ripard {
311a7e7c38SMaxime Ripard 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
321a7e7c38SMaxime Ripard 
331a7e7c38SMaxime Ripard 	return ccu_gate_helper_disable(&cg->common, cg->enable);
341a7e7c38SMaxime Ripard }
351a7e7c38SMaxime Ripard 
ccu_gate_helper_enable(struct ccu_common * common,u32 gate)361a7e7c38SMaxime Ripard int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
371a7e7c38SMaxime Ripard {
381a7e7c38SMaxime Ripard 	unsigned long flags;
391a7e7c38SMaxime Ripard 	u32 reg;
401a7e7c38SMaxime Ripard 
411a7e7c38SMaxime Ripard 	if (!gate)
421a7e7c38SMaxime Ripard 		return 0;
431a7e7c38SMaxime Ripard 
441a7e7c38SMaxime Ripard 	spin_lock_irqsave(common->lock, flags);
451a7e7c38SMaxime Ripard 
461a7e7c38SMaxime Ripard 	reg = readl(common->base + common->reg);
471a7e7c38SMaxime Ripard 	writel(reg | gate, common->base + common->reg);
481a7e7c38SMaxime Ripard 
491a7e7c38SMaxime Ripard 	spin_unlock_irqrestore(common->lock, flags);
501a7e7c38SMaxime Ripard 
511a7e7c38SMaxime Ripard 	return 0;
521a7e7c38SMaxime Ripard }
53*551b62b1SSamuel Holland EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU);
541a7e7c38SMaxime Ripard 
ccu_gate_enable(struct clk_hw * hw)551a7e7c38SMaxime Ripard static int ccu_gate_enable(struct clk_hw *hw)
561a7e7c38SMaxime Ripard {
571a7e7c38SMaxime Ripard 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
581a7e7c38SMaxime Ripard 
591a7e7c38SMaxime Ripard 	return ccu_gate_helper_enable(&cg->common, cg->enable);
601a7e7c38SMaxime Ripard }
611a7e7c38SMaxime Ripard 
ccu_gate_helper_is_enabled(struct ccu_common * common,u32 gate)621a7e7c38SMaxime Ripard int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
631a7e7c38SMaxime Ripard {
641a7e7c38SMaxime Ripard 	if (!gate)
651a7e7c38SMaxime Ripard 		return 1;
661a7e7c38SMaxime Ripard 
671a7e7c38SMaxime Ripard 	return readl(common->base + common->reg) & gate;
681a7e7c38SMaxime Ripard }
69*551b62b1SSamuel Holland EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU);
701a7e7c38SMaxime Ripard 
ccu_gate_is_enabled(struct clk_hw * hw)711a7e7c38SMaxime Ripard static int ccu_gate_is_enabled(struct clk_hw *hw)
721a7e7c38SMaxime Ripard {
731a7e7c38SMaxime Ripard 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
741a7e7c38SMaxime Ripard 
751a7e7c38SMaxime Ripard 	return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
761a7e7c38SMaxime Ripard }
771a7e7c38SMaxime Ripard 
ccu_gate_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)78845d6b0fSChen-Yu Tsai static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
79845d6b0fSChen-Yu Tsai 					  unsigned long parent_rate)
80845d6b0fSChen-Yu Tsai {
81845d6b0fSChen-Yu Tsai 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
82845d6b0fSChen-Yu Tsai 	unsigned long rate = parent_rate;
83845d6b0fSChen-Yu Tsai 
84845d6b0fSChen-Yu Tsai 	if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
85845d6b0fSChen-Yu Tsai 		rate /= cg->common.prediv;
86845d6b0fSChen-Yu Tsai 
87845d6b0fSChen-Yu Tsai 	return rate;
88845d6b0fSChen-Yu Tsai }
89845d6b0fSChen-Yu Tsai 
ccu_gate_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)90845d6b0fSChen-Yu Tsai static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
91845d6b0fSChen-Yu Tsai 				unsigned long *prate)
92845d6b0fSChen-Yu Tsai {
93845d6b0fSChen-Yu Tsai 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
94845d6b0fSChen-Yu Tsai 	int div = 1;
95845d6b0fSChen-Yu Tsai 
96845d6b0fSChen-Yu Tsai 	if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
97845d6b0fSChen-Yu Tsai 		div = cg->common.prediv;
98845d6b0fSChen-Yu Tsai 
99845d6b0fSChen-Yu Tsai 	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
100845d6b0fSChen-Yu Tsai 		unsigned long best_parent = rate;
101845d6b0fSChen-Yu Tsai 
102845d6b0fSChen-Yu Tsai 		if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
103845d6b0fSChen-Yu Tsai 			best_parent *= div;
104845d6b0fSChen-Yu Tsai 		*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
105845d6b0fSChen-Yu Tsai 	}
106845d6b0fSChen-Yu Tsai 
107845d6b0fSChen-Yu Tsai 	return *prate / div;
108845d6b0fSChen-Yu Tsai }
109845d6b0fSChen-Yu Tsai 
ccu_gate_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)110845d6b0fSChen-Yu Tsai static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
111845d6b0fSChen-Yu Tsai 			     unsigned long parent_rate)
112845d6b0fSChen-Yu Tsai {
113845d6b0fSChen-Yu Tsai 	/*
114845d6b0fSChen-Yu Tsai 	 * We must report success but we can do so unconditionally because
115845d6b0fSChen-Yu Tsai 	 * clk_factor_round_rate returns values that ensure this call is a
116845d6b0fSChen-Yu Tsai 	 * nop.
117845d6b0fSChen-Yu Tsai 	 */
118845d6b0fSChen-Yu Tsai 
119845d6b0fSChen-Yu Tsai 	return 0;
120845d6b0fSChen-Yu Tsai }
121845d6b0fSChen-Yu Tsai 
1221a7e7c38SMaxime Ripard const struct clk_ops ccu_gate_ops = {
1231a7e7c38SMaxime Ripard 	.disable	= ccu_gate_disable,
1241a7e7c38SMaxime Ripard 	.enable		= ccu_gate_enable,
1251a7e7c38SMaxime Ripard 	.is_enabled	= ccu_gate_is_enabled,
126845d6b0fSChen-Yu Tsai 	.round_rate	= ccu_gate_round_rate,
127845d6b0fSChen-Yu Tsai 	.set_rate	= ccu_gate_set_rate,
128845d6b0fSChen-Yu Tsai 	.recalc_rate	= ccu_gate_recalc_rate,
1291a7e7c38SMaxime Ripard };
130*551b62b1SSamuel Holland EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU);
131