• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 Maxime Ripard
4  * Maxime Ripard <maxime.ripard@free-electrons.com>
5  */
6 
7 #include <linux/clk-provider.h>
8 #include <linux/io.h>
9 
10 #include "ccu_gate.h"
11 
ccu_gate_helper_disable(struct ccu_common * common,u32 gate)12 void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
13 {
14 	unsigned long flags;
15 	u32 reg;
16 
17 	if (!gate)
18 		return;
19 
20 	spin_lock_irqsave(common->lock, flags);
21 
22 	reg = readl(common->base + common->reg);
23 	/* data reading result of the keyfield bits are always 0 */
24 	if (common->features & CCU_FEATURE_KEY_FIELD_MOD) {
25 		reg = reg | common->key_value;
26 	}
27 
28 	writel(reg & ~gate, common->base + common->reg);
29 
30 	spin_unlock_irqrestore(common->lock, flags);
31 }
32 
ccu_gate_disable(struct clk_hw * hw)33 static void ccu_gate_disable(struct clk_hw *hw)
34 {
35 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
36 
37 	return ccu_gate_helper_disable(&cg->common, cg->enable);
38 }
39 
ccu_gate_helper_enable(struct ccu_common * common,u32 gate)40 int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
41 {
42 	unsigned long flags;
43 	u32 reg;
44 
45 	if (!gate)
46 		return 0;
47 
48 	spin_lock_irqsave(common->lock, flags);
49 
50 	reg = readl(common->base + common->reg);
51 
52 	/* data reading result of the keyfield bits are always 0 */
53 	if (common->features & CCU_FEATURE_KEY_FIELD_MOD) {
54 		reg = reg | common->key_value;
55 	}
56 
57 	writel(reg | gate, common->base + common->reg);
58 
59 	spin_unlock_irqrestore(common->lock, flags);
60 
61 	return 0;
62 }
63 
ccu_gate_enable(struct clk_hw * hw)64 static int ccu_gate_enable(struct clk_hw *hw)
65 {
66 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
67 
68 	return ccu_gate_helper_enable(&cg->common, cg->enable);
69 }
70 
ccu_gate_helper_is_enabled(struct ccu_common * common,u32 gate)71 int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
72 {
73 	if (!gate)
74 		return 1;
75 
76 	return readl(common->base + common->reg) & gate;
77 }
78 
ccu_gate_is_enabled(struct clk_hw * hw)79 static int ccu_gate_is_enabled(struct clk_hw *hw)
80 {
81 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
82 
83 	return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
84 }
85 
ccu_gate_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)86 static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
87 					  unsigned long parent_rate)
88 {
89 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
90 	unsigned long rate = parent_rate;
91 
92 	if (cg->common.features & CCU_FEATURE_FIXED_RATE_GATE)
93 		return cg->fixed_rate;
94 
95 	if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
96 		rate /= cg->common.prediv;
97 
98 	return rate;
99 }
100 
ccu_gate_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)101 static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
102 				unsigned long *prate)
103 {
104 	struct ccu_gate *cg = hw_to_ccu_gate(hw);
105 	int div = 1;
106 
107 	if (cg->common.features & CCU_FEATURE_FIXED_RATE_GATE)
108 		return cg->fixed_rate;
109 
110 	if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
111 		div = cg->common.prediv;
112 
113 	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
114 		unsigned long best_parent = rate;
115 
116 		if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
117 			best_parent *= div;
118 		*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
119 	}
120 
121 	return *prate / div;
122 }
123 
ccu_gate_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)124 static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
125 			     unsigned long parent_rate)
126 {
127 	/*
128 	 * We must report success but we can do so unconditionally because
129 	 * clk_factor_round_rate returns values that ensure this call is a
130 	 * nop.
131 	 */
132 
133 	return 0;
134 }
135 
136 const struct clk_ops ccu_gate_ops = {
137 	.disable	= ccu_gate_disable,
138 	.enable		= ccu_gate_enable,
139 	.is_enabled	= ccu_gate_is_enabled,
140 	.round_rate	= ccu_gate_round_rate,
141 	.set_rate	= ccu_gate_set_rate,
142 	.recalc_rate	= ccu_gate_recalc_rate,
143 };
144 EXPORT_SYMBOL_GPL(ccu_gate_ops);
145