From f2054ae01c96275abdc7c323c8adb03795e11c7d Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Mon, 3 Jun 2013 14:40:25 -0700 Subject: media: tegra_v4l2: pass platform_data via soc_camera_link soc_camera_link supports passing power on/off control callback to soc_camera stack. So the power control can be handled by soc_camera stack instead of our Tegra V4L2 host driver. Also pass other platform_data fields via soc_camera_link instead of a hacking nvhost_device_data struct. Bug 1240806 Bug 1369083 Change-Id: I443a7d28196cc8292805da70d2d5ff1c3cd50a5d Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/246267 (cherry picked from commit 9083d270bf93b583cd5bf5151a52ea250f8541a3) Reviewed-on: http://git-master/r/279986 Reviewed-by: Matthew Pedro Tested-by: Matthew Pedro --- drivers/media/video/tegra_v4l2_camera.c | 84 ++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index 739a56b85f3a..678e765512d4 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -960,6 +960,60 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev) return err; } +static void tegra_camera_activate(struct tegra_camera_dev *pcdev) +{ + nvhost_module_busy_ext(pcdev->ndev); + + /* Enable external power */ + regulator_enable(pcdev->reg); + + /* + * Powergating DIS must powergate VE partition. Camera + * module needs to increase the ref-count of disa to + * avoid itself powergated by DIS inadvertently. + */ + tegra_unpowergate_partition(TEGRA_POWERGATE_DISA); + /* Unpowergate VE */ + tegra_unpowergate_partition(TEGRA_POWERGATE_VENC); + + /* Turn on relevant clocks. */ + clk_set_rate(pcdev->clk_vi, 150000000); + clk_prepare_enable(pcdev->clk_vi); + clk_set_rate(pcdev->clk_vi_sensor, 24000000); + clk_prepare_enable(pcdev->clk_vi_sensor); + clk_prepare_enable(pcdev->clk_csi); + clk_prepare_enable(pcdev->clk_isp); + clk_prepare_enable(pcdev->clk_csus); + clk_set_rate(pcdev->clk_sclk, 80000000); + clk_prepare_enable(pcdev->clk_sclk); + clk_set_rate(pcdev->clk_sclk, 375000000); + clk_prepare_enable(pcdev->clk_emc); + + /* Save current syncpt values. */ + tegra_camera_save_syncpts(pcdev); +} + +static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev) +{ + /* Turn off relevant clocks. */ + clk_disable_unprepare(pcdev->clk_vi); + clk_disable_unprepare(pcdev->clk_vi_sensor); + clk_disable_unprepare(pcdev->clk_csi); + clk_disable_unprepare(pcdev->clk_isp); + clk_disable_unprepare(pcdev->clk_csus); + clk_disable_unprepare(pcdev->clk_sclk); + clk_disable_unprepare(pcdev->clk_emc); + + /* Powergate VE */ + tegra_powergate_partition(TEGRA_POWERGATE_VENC); + tegra_powergate_partition(TEGRA_POWERGATE_DISA); + + /* Disable external power */ + regulator_disable(pcdev->reg); + + nvhost_module_idle_ext(pcdev->ndev); +} + static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) { struct vb2_buffer *vb; @@ -1404,8 +1458,18 @@ static int tegra_camera_add_device(struct soc_camera_device *icd) struct tegra_camera_dev *pcdev = ici->priv; int err; - if (pcdev->icd) - return -EBUSY; + pcdev->pdata = icd->link->priv; + if (!pcdev->pdata) { + dev_err(icd->parent, "No platform data!\n"); + return -EINVAL; + } + + if (!tegra_camera_port_is_valid(pcdev->pdata->port)) { + dev_err(icd->parent, + "Invalid camera port %d in platform data\n", + pcdev->pdata->port); + return -EINVAL; + } pm_runtime_get_sync(ici->v4l2_dev.dev); @@ -1693,12 +1757,6 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, nvhost_set_drvdata(ndev, pcdev); - if (!tegra_camera_port_is_valid(pcdev->pdata->port)) { - dev_err(&ndev->dev, "Invalid camera port %d in platform data\n", - pcdev->pdata->port); - goto exit_free_pcdev; - } - pcdev->clk_vi = clk_get_sys("tegra_camera", "vi"); if (IS_ERR_OR_NULL(pcdev->clk_vi)) { dev_err(&ndev->dev, "Failed to get vi clock.\n"); @@ -1825,11 +1883,6 @@ static int tegra_camera_suspend(struct nvhost_device *ndev, pm_message_t state) /* Suspend the camera sensor. */ WARN_ON(!pcdev->icd->ops->suspend); pcdev->icd->ops->suspend(pcdev->icd, state); - - /* Power off the camera subsystem. */ - pcdev->pdata->disable_camera(pcdev->ndev); - - nvhost_module_idle_ext(nvhost_get_parent(ndev)); } return 0; @@ -1843,11 +1896,6 @@ static int tegra_camera_resume(struct nvhost_device *ndev) /* We only need to do something if a camera sensor is attached. */ if (pcdev->icd) { - nvhost_module_busy_ext(nvhost_get_parent(ndev)); - - /* Power on the camera subsystem. */ - pcdev->pdata->enable_camera(pcdev->ndev); - /* Resume the camera host. */ tegra_camera_save_syncpts(pcdev); tegra_camera_capture_setup(pcdev); -- cgit v1.2.3