Skip to content

Commit 2801b5e

Browse files
roliver-rpipopcornmix
authored andcommitted
clk: clk-gpio: Support acquire/release semantics
Add support for the 'gpio-gate-clock-releasing' compatible string. The behaviour is identical to that of 'gpio-gate-clock' but the gpio is acquired on 'enable' and released on 'disable'. Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
1 parent 5df26d9 commit 2801b5e

File tree

1 file changed

+123
-6
lines changed

1 file changed

+123
-6
lines changed

drivers/clk/clk-gpio.c

Lines changed: 123 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
*
3636
* @hw: handle between common and hardware-specific interfaces
3737
* @gpiod: gpio descriptor
38+
* @dev: device pointer for acquire/release operations
3839
*
3940
* Clock with a gpio control for enabling and disabling the parent clock
4041
* or switching between two parents by asserting or deasserting the gpio.
@@ -46,9 +47,41 @@
4647
struct clk_gpio {
4748
struct clk_hw hw;
4849
struct gpio_desc *gpiod;
50+
struct device *dev;
4951
};
5052

5153
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
54+
static int clk_gpio_gate_acquire(struct clk_hw *hw)
55+
{
56+
struct clk_gpio *clk = to_clk_gpio(hw);
57+
struct device *dev = clk->dev;
58+
59+
clk->gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
60+
if (IS_ERR(clk->gpiod)) {
61+
int ret = PTR_ERR(clk->gpiod);
62+
63+
clk->gpiod = NULL;
64+
return ret;
65+
}
66+
67+
return 0;
68+
}
69+
70+
static bool clk_gpio_gate_is_acquired(struct clk_hw *hw)
71+
{
72+
struct clk_gpio *clk = to_clk_gpio(hw);
73+
74+
return !!clk->gpiod;
75+
}
76+
77+
static void clk_gpio_gate_release(struct clk_hw *hw)
78+
{
79+
struct clk_gpio *clk = to_clk_gpio(hw);
80+
struct device *dev = clk->dev;
81+
82+
devm_gpiod_put(dev, clk->gpiod);
83+
clk->gpiod = NULL;
84+
}
5285

5386
static int clk_gpio_gate_enable(struct clk_hw *hw)
5487
{
@@ -79,6 +112,37 @@ static const struct clk_ops clk_gpio_gate_ops = {
79112
.is_enabled = clk_gpio_gate_is_enabled,
80113
};
81114

115+
static int clk_gpio_gate_releasing_enable(struct clk_hw *hw)
116+
{
117+
int ret;
118+
119+
ret = clk_gpio_gate_acquire(hw);
120+
if (ret)
121+
return ret;
122+
123+
return clk_gpio_gate_enable(hw);
124+
}
125+
126+
static void clk_gpio_gate_releasing_disable(struct clk_hw *hw)
127+
{
128+
clk_gpio_gate_disable(hw);
129+
clk_gpio_gate_release(hw);
130+
}
131+
132+
static int clk_gpio_gate_releasing_is_enabled(struct clk_hw *hw)
133+
{
134+
if (!clk_gpio_gate_is_acquired(hw))
135+
return 0;
136+
137+
return clk_gpio_gate_is_enabled(hw);
138+
}
139+
140+
static const struct clk_ops clk_gpio_gate_releasing_ops = {
141+
.enable = clk_gpio_gate_releasing_enable,
142+
.disable = clk_gpio_gate_releasing_disable,
143+
.is_enabled = clk_gpio_gate_releasing_is_enabled,
144+
};
145+
82146
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
83147
{
84148
struct clk_gpio *clk = to_clk_gpio(hw);
@@ -108,6 +172,37 @@ static const struct clk_ops clk_sleeping_gpio_gate_ops = {
108172
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
109173
};
110174

175+
static int clk_sleeping_gpio_gate_releasing_prepare(struct clk_hw *hw)
176+
{
177+
int ret;
178+
179+
ret = clk_gpio_gate_acquire(hw);
180+
if (ret)
181+
return ret;
182+
183+
return clk_sleeping_gpio_gate_prepare(hw);
184+
}
185+
186+
static void clk_sleeping_gpio_gate_releasing_unprepare(struct clk_hw *hw)
187+
{
188+
clk_sleeping_gpio_gate_unprepare(hw);
189+
clk_gpio_gate_release(hw);
190+
}
191+
192+
static int clk_sleeping_gpio_gate_releasing_is_prepared(struct clk_hw *hw)
193+
{
194+
if (!clk_gpio_gate_is_acquired(hw))
195+
return 0;
196+
197+
return clk_sleeping_gpio_gate_is_prepared(hw);
198+
}
199+
200+
static const struct clk_ops clk_sleeping_gpio_gate_releasing_ops = {
201+
.prepare = clk_sleeping_gpio_gate_releasing_prepare,
202+
.unprepare = clk_sleeping_gpio_gate_releasing_unprepare,
203+
.is_prepared = clk_sleeping_gpio_gate_releasing_is_prepared,
204+
};
205+
111206
/**
112207
* DOC: basic clock multiplexer which can be controlled with a gpio output
113208
* Traits of this clock:
@@ -162,6 +257,7 @@ static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
162257
init.flags = CLK_SET_RATE_PARENT;
163258

164259
clk_gpio->gpiod = gpiod;
260+
clk_gpio->dev = dev;
165261
clk_gpio->hw.init = &init;
166262

167263
hw = &clk_gpio->hw;
@@ -174,14 +270,29 @@ static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
174270

175271
static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
176272
int num_parents,
177-
struct gpio_desc *gpiod)
273+
struct gpio_desc *gpiod,
274+
bool releasing)
178275
{
179276
const struct clk_ops *ops;
180277

181-
if (gpiod_cansleep(gpiod))
182-
ops = &clk_sleeping_gpio_gate_ops;
183-
else
184-
ops = &clk_gpio_gate_ops;
278+
if (releasing) {
279+
/* For releasing variant, confirm GPIO works then release it
280+
* for acquire/release semantics
281+
*/
282+
if (gpiod_cansleep(gpiod))
283+
ops = &clk_sleeping_gpio_gate_releasing_ops;
284+
else
285+
ops = &clk_gpio_gate_releasing_ops;
286+
287+
devm_gpiod_put(dev, gpiod);
288+
gpiod = NULL;
289+
} else {
290+
/* Regular variant - keep GPIO and choose appropriate ops */
291+
if (gpiod_cansleep(gpiod))
292+
ops = &clk_sleeping_gpio_gate_ops;
293+
else
294+
ops = &clk_gpio_gate_ops;
295+
}
185296

186297
return clk_register_gpio(dev, num_parents, gpiod, ops);
187298
}
@@ -201,8 +312,11 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
201312
struct gpio_desc *gpiod;
202313
struct clk_hw *hw;
203314
bool is_mux;
315+
bool is_releasing;
204316

205317
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
318+
is_releasing =
319+
of_device_is_compatible(node, "gpio-gate-clock-releasing");
206320

207321
num_parents = of_clk_get_parent_count(node);
208322
if (is_mux && num_parents != 2) {
@@ -219,7 +333,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
219333
if (is_mux)
220334
hw = clk_hw_register_gpio_mux(dev, gpiod);
221335
else
222-
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
336+
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod,
337+
is_releasing);
338+
223339
if (IS_ERR(hw))
224340
return PTR_ERR(hw);
225341

@@ -229,6 +345,7 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
229345
static const struct of_device_id gpio_clk_match_table[] = {
230346
{ .compatible = "gpio-mux-clock" },
231347
{ .compatible = "gpio-gate-clock" },
348+
{ .compatible = "gpio-gate-clock-releasing" },
232349
{ }
233350
};
234351

0 commit comments

Comments
 (0)