-
Notifications
You must be signed in to change notification settings - Fork 5.2k
GPIO Acquire/Release Semantics for 'AI Camera' #6884
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
roliver-rpi
wants to merge
5
commits into
rpi-6.12.y
Choose a base branch
from
dev/roliver/ai_camera_gpio_acquire_release
base: rpi-6.12.y
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+213
−27
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1909e86
clk: clk-gpio: Support acquire/release semantics
roliver-rpi 0391186
dt-bindings: clock: Add gpio-gate-clock-releasing
roliver-rpi 2e94b59
dts: 'AI Camera' uses releasing gated clock
roliver-rpi c8c242b
media: i2c: imx500: pm_runtime error paths
roliver-rpi 52ecb02
media: i2c: imx500: GPIO acquire/release semantics
roliver-rpi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
* | ||
* @hw: handle between common and hardware-specific interfaces | ||
* @gpiod: gpio descriptor | ||
* @dev: device pointer for acquire/release operations | ||
* | ||
* Clock with a gpio control for enabling and disabling the parent clock | ||
* or switching between two parents by asserting or deasserting the gpio. | ||
|
@@ -44,9 +45,37 @@ | |
struct clk_gpio { | ||
struct clk_hw hw; | ||
struct gpio_desc *gpiod; | ||
struct device *dev; | ||
}; | ||
|
||
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) | ||
static int clk_gpio_gate_acquire(struct clk_hw *hw) | ||
{ | ||
struct clk_gpio *clk = to_clk_gpio(hw); | ||
struct device *dev = clk->dev; | ||
|
||
clk->gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); | ||
if (IS_ERR(clk->gpiod)) | ||
return PTR_ERR(clk->gpiod); | ||
|
||
return 0; | ||
} | ||
|
||
static bool clk_gpio_gate_is_acquired(struct clk_hw *hw) | ||
{ | ||
struct clk_gpio *clk = to_clk_gpio(hw); | ||
|
||
return clk->gpiod; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you are declaring non-zero to indicate success (although I'd have preferred |
||
} | ||
|
||
static void clk_gpio_gate_release(struct clk_hw *hw) | ||
{ | ||
struct clk_gpio *clk = to_clk_gpio(hw); | ||
struct device *dev = clk->dev; | ||
|
||
devm_gpiod_put(dev, clk->gpiod); | ||
clk->gpiod = NULL; | ||
} | ||
|
||
static int clk_gpio_gate_enable(struct clk_hw *hw) | ||
{ | ||
|
@@ -77,6 +106,39 @@ static const struct clk_ops clk_gpio_gate_ops = { | |
.is_enabled = clk_gpio_gate_is_enabled, | ||
}; | ||
|
||
static int clk_gpio_gate_releasing_enable(struct clk_hw *hw) | ||
{ | ||
int ret; | ||
|
||
if (!clk_gpio_gate_is_acquired(hw)) { | ||
ret = clk_gpio_gate_acquire(hw); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
return clk_gpio_gate_enable(hw); | ||
} | ||
|
||
static void clk_gpio_gate_releasing_disable(struct clk_hw *hw) | ||
{ | ||
clk_gpio_gate_disable(hw); | ||
clk_gpio_gate_release(hw); | ||
} | ||
|
||
static int clk_gpio_gate_releasing_is_enabled(struct clk_hw *hw) | ||
{ | ||
if (!clk_gpio_gate_is_acquired(hw)) | ||
return 0; | ||
|
||
return clk_gpio_gate_is_enabled(hw); | ||
} | ||
|
||
static const struct clk_ops clk_gpio_gate_releasing_ops = { | ||
.enable = clk_gpio_gate_releasing_enable, | ||
.disable = clk_gpio_gate_releasing_disable, | ||
.is_enabled = clk_gpio_gate_releasing_is_enabled, | ||
}; | ||
|
||
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw) | ||
{ | ||
struct clk_gpio *clk = to_clk_gpio(hw); | ||
|
@@ -106,6 +168,39 @@ static const struct clk_ops clk_sleeping_gpio_gate_ops = { | |
.is_prepared = clk_sleeping_gpio_gate_is_prepared, | ||
}; | ||
|
||
static int clk_sleeping_gpio_gate_releasing_prepare(struct clk_hw *hw) | ||
{ | ||
int ret; | ||
|
||
if (!clk_gpio_gate_is_acquired(hw)) { | ||
ret = clk_gpio_gate_acquire(hw); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
return clk_sleeping_gpio_gate_prepare(hw); | ||
} | ||
|
||
static void clk_sleeping_gpio_gate_releasing_unprepare(struct clk_hw *hw) | ||
{ | ||
clk_sleeping_gpio_gate_unprepare(hw); | ||
clk_gpio_gate_release(hw); | ||
} | ||
|
||
static int clk_sleeping_gpio_gate_releasing_is_prepared(struct clk_hw *hw) | ||
{ | ||
if (!clk_gpio_gate_is_acquired(hw)) | ||
return 0; | ||
|
||
return clk_sleeping_gpio_gate_is_prepared(hw); | ||
} | ||
|
||
static const struct clk_ops clk_sleeping_gpio_gate_releasing_ops = { | ||
.prepare = clk_sleeping_gpio_gate_releasing_prepare, | ||
.unprepare = clk_sleeping_gpio_gate_releasing_unprepare, | ||
.is_prepared = clk_sleeping_gpio_gate_releasing_is_prepared, | ||
}; | ||
|
||
/** | ||
* DOC: basic clock multiplexer which can be controlled with a gpio output | ||
* Traits of this clock: | ||
|
@@ -160,6 +255,7 @@ static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents, | |
init.flags = CLK_SET_RATE_PARENT; | ||
|
||
clk_gpio->gpiod = gpiod; | ||
clk_gpio->dev = dev; | ||
clk_gpio->hw.init = &init; | ||
|
||
hw = &clk_gpio->hw; | ||
|
@@ -172,14 +268,29 @@ static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents, | |
|
||
static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, | ||
int num_parents, | ||
struct gpio_desc *gpiod) | ||
struct gpio_desc *gpiod, | ||
bool releasing) | ||
{ | ||
const struct clk_ops *ops; | ||
|
||
if (gpiod_cansleep(gpiod)) | ||
ops = &clk_sleeping_gpio_gate_ops; | ||
else | ||
ops = &clk_gpio_gate_ops; | ||
if (releasing) { | ||
/* For releasing variant, confirm GPIO works then release it | ||
* for acquire/release semantics | ||
*/ | ||
if (gpiod_cansleep(gpiod)) | ||
ops = &clk_sleeping_gpio_gate_releasing_ops; | ||
else | ||
ops = &clk_gpio_gate_releasing_ops; | ||
|
||
devm_gpiod_put(dev, gpiod); | ||
gpiod = NULL; | ||
} else { | ||
/* Regular variant - keep GPIO and choose appropriate ops */ | ||
if (gpiod_cansleep(gpiod)) | ||
ops = &clk_sleeping_gpio_gate_ops; | ||
else | ||
ops = &clk_gpio_gate_ops; | ||
} | ||
|
||
return clk_register_gpio(dev, num_parents, gpiod, ops); | ||
} | ||
|
@@ -199,9 +310,12 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) | |
struct gpio_desc *gpiod; | ||
struct clk_hw *hw; | ||
bool is_mux; | ||
bool is_releasing; | ||
int ret; | ||
|
||
is_mux = of_device_is_compatible(node, "gpio-mux-clock"); | ||
is_releasing = | ||
of_device_is_compatible(node, "gpio-gate-clock-releasing"); | ||
|
||
num_parents = of_clk_get_parent_count(node); | ||
if (is_mux && num_parents != 2) { | ||
|
@@ -226,7 +340,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) | |
if (is_mux) | ||
hw = clk_hw_register_gpio_mux(dev, gpiod); | ||
else | ||
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod); | ||
hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod, | ||
is_releasing); | ||
|
||
if (IS_ERR(hw)) | ||
return PTR_ERR(hw); | ||
|
||
|
@@ -236,6 +352,7 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) | |
static const struct of_device_id gpio_clk_match_table[] = { | ||
{ .compatible = "gpio-mux-clock" }, | ||
{ .compatible = "gpio-gate-clock" }, | ||
{ .compatible = "gpio-gate-clock-releasing" }, | ||
{ } | ||
}; | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.