[media] s5p-fimc: Add support for PIXELASYNCMx clocks

This patch ads handling of clocks for the CAMBLK subsystem which
is a glue logic for FIMC-IS or LCD controller and FIMC IP.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Sylwester Nawrocki 2013-03-21 14:43:17 -03:00 committed by Mauro Carvalho Chehab
parent 39bb6df6e3
commit 056f4f3036
2 changed files with 84 additions and 13 deletions

View file

@ -151,26 +151,48 @@ static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
* __fimc_pipeline_open - update the pipeline information, enable power
* of all pipeline subdevs and the sensor clock
* @me: media entity to start graph walk with
* @prep: true to acquire sensor (and csis) subdevs
* @prepare: true to walk the current pipeline and acquire all subdevs
*
* Called with the graph mutex held.
*/
static int __fimc_pipeline_open(struct fimc_pipeline *p,
struct media_entity *me, bool prep)
struct media_entity *me, bool prepare)
{
struct fimc_md *fmd = entity_to_fimc_mdev(me);
struct v4l2_subdev *sd;
int ret;
if (prep)
fimc_pipeline_prepare(p, me);
if (p->subdevs[IDX_SENSOR] == NULL)
if (WARN_ON(p == NULL || me == NULL))
return -EINVAL;
ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
if (ret)
return ret;
if (prepare)
fimc_pipeline_prepare(p, me);
return fimc_pipeline_s_power(p, 1);
sd = p->subdevs[IDX_SENSOR];
if (sd == NULL)
return -EINVAL;
/* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) {
ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]);
if (ret < 0)
return ret;
}
ret = fimc_md_set_camclk(sd, true);
if (ret < 0)
goto err_wbclk;
ret = fimc_pipeline_s_power(p, 1);
if (!ret)
return 0;
fimc_md_set_camclk(sd, false);
err_wbclk:
if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
return ret;
}
/**
@ -181,15 +203,24 @@ static int __fimc_pipeline_open(struct fimc_pipeline *p,
*/
static int __fimc_pipeline_close(struct fimc_pipeline *p)
{
struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL;
struct fimc_md *fmd;
int ret = 0;
if (!p || !p->subdevs[IDX_SENSOR])
if (WARN_ON(sd == NULL))
return -EINVAL;
if (p->subdevs[IDX_SENSOR]) {
ret = fimc_pipeline_s_power(p, 0);
fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
fimc_md_set_camclk(sd, false);
}
fmd = entity_to_fimc_mdev(&sd->entity);
/* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
return ret == -ENXIO ? 0 : ret;
}
@ -959,7 +990,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
}
/*
* The peripheral sensor clock management.
* The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management.
*/
static void fimc_md_put_clocks(struct fimc_md *fmd)
{
@ -972,6 +1003,14 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
clk_put(fmd->camclk[i].clock);
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
}
/* Writeback (PIXELASYNCMx) clocks */
for (i = 0; i < FIMC_MAX_WBCLKS; i++) {
if (IS_ERR(fmd->wbclk[i]))
continue;
clk_put(fmd->wbclk[i]);
fmd->wbclk[i] = ERR_PTR(-EINVAL);
}
}
static int fimc_md_get_clocks(struct fimc_md *fmd)
@ -1008,6 +1047,28 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
if (ret)
fimc_md_put_clocks(fmd);
if (!fmd->use_isp)
return 0;
/*
* For now get only PIXELASYNCM1 clock (Writeback B/ISP),
* leave PIXELASYNCM0 out for the LCD Writeback driver.
*/
fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL);
for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) {
snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i);
clock = clk_get(dev, clk_name);
if (IS_ERR(clock)) {
v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n",
clk_name);
ret = PTR_ERR(clock);
break;
}
fmd->wbclk[i] = clock;
}
if (ret)
fimc_md_put_clocks(fmd);
return ret;
}

View file

@ -41,6 +41,13 @@
#define FIMC_MAX_SENSORS 8
#define FIMC_MAX_CAMCLKS 2
/* LCD/ISP Writeback clocks (PIXELASYNCMx) */
enum {
CLK_IDX_WB_A,
CLK_IDX_WB_B,
FIMC_MAX_WBCLKS
};
struct fimc_csis_info {
struct v4l2_subdev *sd;
int id;
@ -73,6 +80,7 @@ struct fimc_sensor_info {
* @num_sensors: actual number of registered sensors
* @camclk: external sensor clock information
* @fimc: array of registered fimc devices
* @use_isp: set to true when FIMC-IS subsystem is used
* @media_dev: top level media device
* @v4l2_dev: top level v4l2_device holding up the subdevs
* @pdev: platform device this media device is hooked up into
@ -87,8 +95,10 @@ struct fimc_md {
struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
int num_sensors;
struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
struct clk *wbclk[FIMC_MAX_WBCLKS];
struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
struct fimc_dev *fimc[FIMC_MAX_DEVS];
bool use_isp;
struct media_device media_dev;
struct v4l2_device v4l2_dev;
struct platform_device *pdev;