Skip to content

Commit 75cda0e

Browse files
roliver-rpipelwell
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 85b196f commit 75cda0e

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
@@ -33,6 +33,7 @@
3333
*
3434
* @hw: handle between common and hardware-specific interfaces
3535
* @gpiod: gpio descriptor
36+
* @dev: device pointer for acquire/release operations
3637
*
3738
* Clock with a gpio control for enabling and disabling the parent clock
3839
* or switching between two parents by asserting or deasserting the gpio.
@@ -44,9 +45,41 @@
4445
struct clk_gpio {
4546
struct clk_hw hw;
4647
struct gpio_desc *gpiod;
48+
struct device *dev;
4749
};
4850

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

5184
static int clk_gpio_gate_enable(struct clk_hw *hw)
5285
{
@@ -77,6 +110,37 @@ static const struct clk_ops clk_gpio_gate_ops = {
77110
.is_enabled = clk_gpio_gate_is_enabled,
78111
};
79112

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

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

162257
clk_gpio->gpiod = gpiod;
258+
clk_gpio->dev = dev;
163259
clk_gpio->hw.init = &init;
164260

165261
hw = &clk_gpio->hw;
@@ -172,14 +268,29 @@ static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
172268

173269
static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
174270
int num_parents,
175-
struct gpio_desc *gpiod)
271+
struct gpio_desc *gpiod,
272+
bool releasing)
176273
{
177274
const struct clk_ops *ops;
178275

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

184295
return clk_register_gpio(dev, num_parents, gpiod, ops);
185296
}
@@ -199,9 +310,12 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
199310
struct gpio_desc *gpiod;
200311
struct clk_hw *hw;
201312
bool is_mux;
313+
bool is_releasing;
202314
int ret;
203315

204316
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
317+
is_releasing =
318+
of_device_is_compatible(node, "gpio-gate-clock-releasing");
205319

206320
num_parents = of_clk_get_parent_count(node);
207321
if (is_mux && num_parents != 2) {
@@ -226,7 +340,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
226340
if (is_mux)
227341
hw = clk_hw_register_gpio_mux(dev, gpiod);
228342
else
229-
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
343+
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod,
344+
is_releasing);
345+
230346
if (IS_ERR(hw))
231347
return PTR_ERR(hw);
232348

@@ -236,6 +352,7 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
236352
static const struct of_device_id gpio_clk_match_table[] = {
237353
{ .compatible = "gpio-mux-clock" },
238354
{ .compatible = "gpio-gate-clock" },
355+
{ .compatible = "gpio-gate-clock-releasing" },
239356
{ }
240357
};
241358

0 commit comments

Comments
 (0)