Message ID | 20201014140507.v3.2.I75c409497d4dea9daefa53ec5f93824081c4ecbe@changeid |
---|---|
State | New |
Headers | show |
Series | [v3,1/3] clk: qcom: lpasscc-sc7810: Use devm in probe | expand |
Quoting Douglas Anderson (2020-10-14 14:05:22) > diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c > index abcf36006926..48d370e2108e 100644 > --- a/drivers/clk/qcom/lpasscorecc-sc7180.c > +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c > @@ -356,12 +356,48 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = { > .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs), > }; > > +static void lpass_pm_runtime_disable(void *data) > +{ > + pm_runtime_disable(data); > +} > + > +static void lapss_pm_clk_destroy(void *data) > +{ > + pm_clk_destroy(data); > +} Why are these helpers added again? And do we even need them? Can't we just pass pm_runtime_disable or pm_clk_destroy to the devm_add_action_or_reset() second parameter?
Hi, On Wed, Oct 14, 2020 at 3:10 PM Stephen Boyd <sboyd@kernel.org> wrote: > > Quoting Douglas Anderson (2020-10-14 14:05:22) > > diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c > > index abcf36006926..48d370e2108e 100644 > > --- a/drivers/clk/qcom/lpasscorecc-sc7180.c > > +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c > > @@ -356,12 +356,48 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = { > > .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs), > > }; > > > > +static void lpass_pm_runtime_disable(void *data) > > +{ > > + pm_runtime_disable(data); > > +} > > + > > +static void lapss_pm_clk_destroy(void *data) > > +{ > > + pm_clk_destroy(data); > > +} > > Why are these helpers added again? And do we even need them? Can't we > just pass pm_runtime_disable or pm_clk_destroy to the > devm_add_action_or_reset() second parameter? Unfortunately, we can't due to the C specification. Take a look at all the other users of devm_add_action_or_reset() and they all have pretty much the same stupid thing. This is a pretty great grep, for instance: git grep devm_add_action_or_reset.*clk_disable_unprepare I did a quick Google search and the top hit was a stack overflow that explained it: https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type The net-net is that the answer there says: > Hence, since a void* is not compatible with a struct my_struct*, a > function pointer of type void (*)(void*) is not compatible with a > function pointer of type void (*)(struct my_struct*), so this > casting of function pointers is technically undefined behavior. I suppose I could try to add devm variants of these functions somewhere more general if you think it's a good idea, though there it seems like there's not a huge need since these two greps are zero: git grep devm_add_action_or_reset.*runtime_disable git grep devm_add_action_or_reset.*pm_clk_destroy ...actually, do we even need the runtime_disable in the error path? When the dev goes away does it matter if you left pm_runtime enabled on it? -Doug
Quoting Doug Anderson (2020-10-14 15:28:58) > Hi, > > On Wed, Oct 14, 2020 at 3:10 PM Stephen Boyd <sboyd@kernel.org> wrote: > > > > Quoting Douglas Anderson (2020-10-14 14:05:22) > > > diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c > > > index abcf36006926..48d370e2108e 100644 > > > --- a/drivers/clk/qcom/lpasscorecc-sc7180.c > > > +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c > > > @@ -356,12 +356,48 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = { > > > .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs), > > > }; > > > > > > +static void lpass_pm_runtime_disable(void *data) > > > +{ > > > + pm_runtime_disable(data); > > > +} > > > + > > > +static void lapss_pm_clk_destroy(void *data) > > > +{ > > > + pm_clk_destroy(data); > > > +} > > > > Why are these helpers added again? And do we even need them? Can't we > > just pass pm_runtime_disable or pm_clk_destroy to the > > devm_add_action_or_reset() second parameter? > > Unfortunately, we can't due to the C specification. Take a look at > all the other users of devm_add_action_or_reset() and they all have > pretty much the same stupid thing. Ok, but we don't need two of the same functions, right? > ...actually, do we even need the runtime_disable in the error path? > When the dev goes away does it matter if you left pm_runtime enabled > on it? > I don't know. The device isn't destroyed but maybe when the driver is unbound it resets the runtime PM counters?
diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c index abcf36006926..48d370e2108e 100644 --- a/drivers/clk/qcom/lpasscorecc-sc7180.c +++ b/drivers/clk/qcom/lpasscorecc-sc7180.c @@ -356,12 +356,48 @@ static const struct qcom_cc_desc lpass_audio_hm_sc7180_desc = { .num_gdscs = ARRAY_SIZE(lpass_audio_hm_sc7180_gdscs), }; +static void lpass_pm_runtime_disable(void *data) +{ + pm_runtime_disable(data); +} + +static void lapss_pm_clk_destroy(void *data) +{ + pm_clk_destroy(data); +} + +static int lpass_create_pm_clks(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); + if (ret) + return ret; + + ret = pm_clk_create(&pdev->dev); + if (ret) + return ret; + ret = devm_add_action_or_reset(&pdev->dev, lapss_pm_clk_destroy, &pdev->dev); + if (ret) + return ret; + + ret = pm_clk_add(&pdev->dev, "iface"); + if (ret < 0) + dev_err(&pdev->dev, "failed to acquire iface clock\n"); + return ret; +} + static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) { const struct qcom_cc_desc *desc; struct regmap *regmap; int ret; + ret = lpass_create_pm_clks(pdev); + if (ret) + return ret; + lpass_core_cc_sc7180_regmap_config.name = "lpass_audio_cc"; desc = &lpass_audio_hm_sc7180_desc; ret = qcom_cc_probe_by_index(pdev, 1, desc); @@ -392,6 +428,11 @@ static int lpass_core_cc_sc7180_probe(struct platform_device *pdev) static int lpass_hm_core_probe(struct platform_device *pdev) { const struct qcom_cc_desc *desc; + int ret; + + ret = lpass_create_pm_clks(pdev); + if (ret) + return ret; lpass_core_cc_sc7180_regmap_config.name = "lpass_hm_core"; desc = &lpass_core_hm_sc7180_desc; @@ -399,65 +440,28 @@ static int lpass_hm_core_probe(struct platform_device *pdev) return qcom_cc_probe_by_index(pdev, 0, desc); } -static const struct of_device_id lpass_core_cc_sc7180_match_table[] = { +static const struct of_device_id lpass_hm_sc7180_match_table[] = { { .compatible = "qcom,sc7180-lpasshm", - .data = lpass_hm_core_probe, }, + { } +}; +MODULE_DEVICE_TABLE(of, lpass_hm_sc7180_match_table); + +static const struct of_device_id lpass_core_cc_sc7180_match_table[] = { { .compatible = "qcom,sc7180-lpasscorecc", - .data = lpass_core_cc_sc7180_probe, }, { } }; MODULE_DEVICE_TABLE(of, lpass_core_cc_sc7180_match_table); -static void lpass_pm_runtime_disable(void *data) -{ - pm_runtime_disable(data); -} - -static void lapss_pm_clk_destroy(void *data) -{ - pm_clk_destroy(data); -} - -static int lpass_core_sc7180_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *p); - int ret; - - pm_runtime_enable(&pdev->dev); - ret = devm_add_action_or_reset(&pdev->dev, lpass_pm_runtime_disable, &pdev->dev); - if (ret) - return ret; - - ret = pm_clk_create(&pdev->dev); - if (ret) - return ret; - ret = devm_add_action_or_reset(&pdev->dev, lapss_pm_clk_destroy, &pdev->dev); - if (ret) - return ret; - - ret = pm_clk_add(&pdev->dev, "iface"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to acquire iface clock\n"); - return ret; - } - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - return clk_probe(pdev); -} - static const struct dev_pm_ops lpass_core_cc_pm_ops = { SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) }; static struct platform_driver lpass_core_cc_sc7180_driver = { - .probe = lpass_core_sc7180_probe, + .probe = lpass_core_cc_sc7180_probe, .driver = { .name = "lpass_core_cc-sc7180", .of_match_table = lpass_core_cc_sc7180_match_table, @@ -465,17 +469,36 @@ static struct platform_driver lpass_core_cc_sc7180_driver = { }, }; -static int __init lpass_core_cc_sc7180_init(void) +static const struct dev_pm_ops lpass_hm_pm_ops = { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static struct platform_driver lpass_hm_sc7180_driver = { + .probe = lpass_hm_core_probe, + .driver = { + .name = "lpass_hm-sc7180", + .of_match_table = lpass_hm_sc7180_match_table, + .pm = &lpass_hm_pm_ops, + }, +}; + +static int __init lpass_sc7180_init(void) { - return platform_driver_register(&lpass_core_cc_sc7180_driver); + int ret; + + ret = platform_driver_register(&lpass_core_cc_sc7180_driver); + if (ret) + return ret; + return platform_driver_register(&lpass_hm_sc7180_driver); } -subsys_initcall(lpass_core_cc_sc7180_init); +subsys_initcall(lpass_sc7180_init); -static void __exit lpass_core_cc_sc7180_exit(void) +static void __exit lpass_sc7180_exit(void) { + platform_driver_unregister(&lpass_hm_sc7180_driver); platform_driver_unregister(&lpass_core_cc_sc7180_driver); } -module_exit(lpass_core_cc_sc7180_exit); +module_exit(lpass_sc7180_exit); MODULE_DESCRIPTION("QTI LPASS_CORE_CC SC7180 Driver"); MODULE_LICENSE("GPL v2");
The sc7180 lpass clock driver manages two different devices. These two devices were tangled together, using one probe and a lookup to figure out the real probe. I think it's cleaner to really separate the probe for these two devices since they're really different things, just both managed by the same driver. Signed-off-by: Douglas Anderson <dianders@chromium.org> --- Changes in v3: - ("clk: qcom: lpass-sc7180: Disentangle the two clock devices") new for v3. drivers/clk/qcom/lpasscorecc-sc7180.c | 121 +++++++++++++++----------- 1 file changed, 72 insertions(+), 49 deletions(-)