Message ID | 20220415152811.636419-7-paul.kocialkowski@bootlin.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Allwinner A31/A83T MIPI CSI-2 and A31 ISP / CSI Rework | expand |
Hi! Dne petek, 15. april 2022 ob 17:27:32 CEST je Paul Kocialkowski napisal(a): > Wrap the clock and reset preparation into runtime pm functions > for better organization of the code. Also fix the clock and > reset enable order to first deassert reset, as recommended in > Allwinner litterature. s/litterature/literature/ Otherwise, Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Best regards, Jernej > > Make the driver depend on PM while at it since runtime pm is > mandatory for the driver to work. > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> > --- > .../media/platform/sunxi/sun6i-csi/Kconfig | 2 +- > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++------ > 2 files changed, 60 insertions(+), 26 deletions(-) > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig > b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index > 0345901617d4..965fbd937841 100644 > --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig > +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig > @@ -2,7 +2,7 @@ > config VIDEO_SUN6I_CSI > tristate "Allwinner V3s Camera Sensor Interface driver" > depends on V4L_PLATFORM_DRIVERS > - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA > + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM > depends on ARCH_SUNXI || COMPILE_TEST > select MEDIA_CONTROLLER > select VIDEO_V4L2_SUBDEV_API > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c > b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index > 46d92b925cc8..dcc9e7a125e2 100644 > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c > @@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device > *csi_dev, bool enable) > > if (!enable) { > regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); > + pm_runtime_put(dev); > > - clk_disable_unprepare(csi_dev->clock_ram); > - clk_disable_unprepare(csi_dev->clock_mod); > - reset_control_assert(csi_dev->reset); > return 0; > } > > - ret = clk_prepare_enable(csi_dev->clock_mod); > - if (ret) { > - dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); > + ret = pm_runtime_resume_and_get(dev); > + if (ret < 0) > return ret; > - } > - > - ret = clk_prepare_enable(csi_dev->clock_ram); > - if (ret) { > - dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); > - goto clk_mod_disable; > - } > - > - ret = reset_control_deassert(csi_dev->reset); > - if (ret) { > - dev_err(csi_dev->dev, "reset err %d\n", ret); > - goto clk_ram_disable; > - } > > regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); > > return 0; > - > -clk_ram_disable: > - clk_disable_unprepare(csi_dev->clock_ram); > -clk_mod_disable: > - clk_disable_unprepare(csi_dev->clock_mod); > - return ret; > } > > static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device > *csi_dev, @@ -800,6 +778,56 @@ static irqreturn_t sun6i_csi_interrupt(int > irq, void *private) return IRQ_HANDLED; > } > > +static int sun6i_csi_suspend(struct device *dev) > +{ > + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); > + > + reset_control_assert(csi_dev->reset); > + clk_disable_unprepare(csi_dev->clock_ram); > + clk_disable_unprepare(csi_dev->clock_mod); > + > + return 0; > +} > + > +static int sun6i_csi_resume(struct device *dev) > +{ > + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); > + int ret; > + > + ret = reset_control_deassert(csi_dev->reset); > + if (ret) { > + dev_err(dev, "failed to deassert reset\n"); > + return ret; > + } > + > + ret = clk_prepare_enable(csi_dev->clock_mod); > + if (ret) { > + dev_err(dev, "failed to enable module clock\n"); > + goto error_reset; > + } > + > + ret = clk_prepare_enable(csi_dev->clock_ram); > + if (ret) { > + dev_err(dev, "failed to enable ram clock\n"); > + goto error_clock_mod; > + } > + > + return 0; > + > +error_clock_mod: > + clk_disable_unprepare(csi_dev->clock_mod); > + > +error_reset: > + reset_control_assert(csi_dev->reset); > + > + return ret; > +} > + > +static const struct dev_pm_ops sun6i_csi_pm_ops = { > + .runtime_suspend = sun6i_csi_suspend, > + .runtime_resume = sun6i_csi_resume, > +}; > + > static const struct regmap_config sun6i_csi_regmap_config = { > .reg_bits = 32, > .reg_stride = 4, > @@ -879,6 +907,10 @@ static int sun6i_csi_resources_setup(struct > sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive; > } > > + /* Runtime PM */ > + > + pm_runtime_enable(dev); > + > return 0; > > error_clock_rate_exclusive: > @@ -889,6 +921,7 @@ static int sun6i_csi_resources_setup(struct > sun6i_csi_device *csi_dev, > > static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) > { > + pm_runtime_disable(csi_dev->dev); > clk_rate_exclusive_put(csi_dev->clock_mod); > } > > @@ -971,6 +1004,7 @@ static struct platform_driver sun6i_csi_platform_driver > = { .driver = { > .name = SUN6I_CSI_NAME, > .of_match_table = of_match_ptr(sun6i_csi_of_match), > + .pm = &sun6i_csi_pm_ops, > }, > };
diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 0345901617d4..965fbd937841 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 46d92b925cc8..dcc9e7a125e2 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); + pm_runtime_put(dev); - clk_disable_unprepare(csi_dev->clock_ram); - clk_disable_unprepare(csi_dev->clock_mod); - reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clock_mod); - if (ret) { - dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } - - ret = clk_prepare_enable(csi_dev->clock_ram); - if (ret) { - dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); - goto clk_mod_disable; - } - - ret = reset_control_deassert(csi_dev->reset); - if (ret) { - dev_err(csi_dev->dev, "reset err %d\n", ret); - goto clk_ram_disable; - } regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); return 0; - -clk_ram_disable: - clk_disable_unprepare(csi_dev->clock_ram); -clk_mod_disable: - clk_disable_unprepare(csi_dev->clock_mod); - return ret; } static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, @@ -800,6 +778,56 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private) return IRQ_HANDLED; } +static int sun6i_csi_suspend(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + + reset_control_assert(csi_dev->reset); + clk_disable_unprepare(csi_dev->clock_ram); + clk_disable_unprepare(csi_dev->clock_mod); + + return 0; +} + +static int sun6i_csi_resume(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi_dev->clock_ram); + if (ret) { + dev_err(dev, "failed to enable ram clock\n"); + goto error_clock_mod; + } + + return 0; + +error_clock_mod: + clk_disable_unprepare(csi_dev->clock_mod); + +error_reset: + reset_control_assert(csi_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_csi_pm_ops = { + .runtime_suspend = sun6i_csi_suspend, + .runtime_resume = sun6i_csi_resume, +}; + static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -879,6 +907,10 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive; } + /* Runtime PM */ + + pm_runtime_enable(dev); + return 0; error_clock_rate_exclusive: @@ -889,6 +921,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) { + pm_runtime_disable(csi_dev->dev); clk_rate_exclusive_put(csi_dev->clock_mod); } @@ -971,6 +1004,7 @@ static struct platform_driver sun6i_csi_platform_driver = { .driver = { .name = SUN6I_CSI_NAME, .of_match_table = of_match_ptr(sun6i_csi_of_match), + .pm = &sun6i_csi_pm_ops, }, };
Wrap the clock and reset preparation into runtime pm functions for better organization of the code. Also fix the clock and reset enable order to first deassert reset, as recommended in Allwinner litterature. Make the driver depend on PM while at it since runtime pm is mandatory for the driver to work. Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> --- .../media/platform/sunxi/sun6i-csi/Kconfig | 2 +- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++------ 2 files changed, 60 insertions(+), 26 deletions(-)