Commit 056f4f30 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 39bb6df6
Loading
Loading
Loading
Loading
+72 −11
Original line number Diff line number Diff line
@@ -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)
	if (WARN_ON(p == NULL || me == NULL))
		return -EINVAL;

	if (prepare)
		fimc_pipeline_prepare(p, me);

	if (p->subdevs[IDX_SENSOR] == NULL)
	sd = p->subdevs[IDX_SENSOR];
	if (sd == NULL)
		return -EINVAL;

	ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
	if (ret)
	/* 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;

	return fimc_pipeline_s_power(p, 1);
	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;
}

+10 −0
Original line number Diff line number Diff line
@@ -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;