Commit 6a7bdd89 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

media: v4l2-mediabus: Use structures to describe bus configuration

The media bus configuration is specified through a set of flags, some of
which being mutually exclusive. This doesn't scale to express more
complex configurations. Improve the API by replacing the single flags
field in v4l2_mbus_config by a union of v4l2_mbus_config_* structures.
The flags themselves are still used in those structures, so they are
kept here. Drivers are however updated to use structure fields instead
of flags when already possible.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 44e756fa
...@@ -357,11 +357,11 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, ...@@ -357,11 +357,11 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
switch (mbus_cfg->type) { switch (mbus_cfg->type) {
case V4L2_MBUS_PARALLEL: case V4L2_MBUS_PARALLEL:
csicfg->ext_vsync = 1; csicfg->ext_vsync = 1;
csicfg->vsync_pol = (mbus_cfg->flags & csicfg->vsync_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0; V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
csicfg->hsync_pol = (mbus_cfg->flags & csicfg->hsync_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0; V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
csicfg->pixclk_pol = (mbus_cfg->flags & csicfg->pixclk_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0; V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
break; break;
......
...@@ -784,7 +784,8 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd, ...@@ -784,7 +784,8 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
cfg->type = V4L2_MBUS_CSI2_DPHY; cfg->type = V4L2_MBUS_CSI2_DPHY;
cfg->flags = V4L2_MBUS_CSI2_1_LANE | cfg->bus.mipi_csi2.num_data_lanes = 1;
cfg->bus.mipi_csi2.flags =
V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
} else { } else {
...@@ -792,8 +793,9 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd, ...@@ -792,8 +793,9 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
* The ADV7180 sensor supports BT.601/656 output modes. * The ADV7180 sensor supports BT.601/656 output modes.
* The BT.656 is default and not yet configurable by s/w. * The BT.656 is default and not yet configurable by s/w.
*/ */
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
V4L2_MBUS_DATA_ACTIVE_HIGH; V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_BT656; cfg->type = V4L2_MBUS_BT656;
} }
......
...@@ -222,23 +222,7 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad ...@@ -222,23 +222,7 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
return -EINVAL; return -EINVAL;
config->type = V4L2_MBUS_CSI2_DPHY; config->type = V4L2_MBUS_CSI2_DPHY;
switch (tx->active_lanes) { config->bus.mipi_csi2.num_data_lanes = tx->active_lanes;
case 1:
config->flags = V4L2_MBUS_CSI2_1_LANE;
break;
case 2:
config->flags = V4L2_MBUS_CSI2_2_LANE;
break;
case 3:
config->flags = V4L2_MBUS_CSI2_3_LANE;
break;
case 4:
config->flags = V4L2_MBUS_CSI2_4_LANE;
break;
}
return 0; return 0;
} }
......
...@@ -223,9 +223,10 @@ static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd, ...@@ -223,9 +223,10 @@ static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd,
unsigned int pad, unsigned int pad,
struct v4l2_mbus_config *cfg) struct v4l2_mbus_config *cfg)
{ {
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_BT656; cfg->type = V4L2_MBUS_BT656;
cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_DATA_ACTIVE_HIGH;
return 0; return 0;
} }
......
...@@ -695,10 +695,12 @@ static int mt9m001_get_mbus_config(struct v4l2_subdev *sd, ...@@ -695,10 +695,12 @@ static int mt9m001_get_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg) struct v4l2_mbus_config *cfg)
{ {
/* MT9M001 has all capture_format parameters fixed */ /* MT9M001 has all capture_format parameters fixed */
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
cfg->type = V4L2_MBUS_PARALLEL; cfg->type = V4L2_MBUS_PARALLEL;
cfg->bus.parallel.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH |
V4L2_MBUS_MASTER;
return 0; return 0;
} }
......
...@@ -1143,14 +1143,16 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd, ...@@ -1143,14 +1143,16 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
{ {
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
cfg->flags = V4L2_MBUS_MASTER | cfg->type = V4L2_MBUS_PARALLEL;
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->flags |= mt9m111->pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING : cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
V4L2_MBUS_PCLK_SAMPLE_FALLING; V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL; cfg->bus.parallel.flags |= mt9m111->pclk_sample ?
V4L2_MBUS_PCLK_SAMPLE_RISING :
V4L2_MBUS_PCLK_SAMPLE_FALLING;
return 0; return 0;
} }
......
...@@ -984,15 +984,15 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd, ...@@ -984,15 +984,15 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
if (ret) if (ret)
return ret; return ret;
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH
| ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH
: V4L2_MBUS_VSYNC_ACTIVE_LOW)
| ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW
: V4L2_MBUS_HSYNC_ACTIVE_HIGH)
| ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING
: V4L2_MBUS_PCLK_SAMPLE_FALLING);
cfg->type = V4L2_MBUS_PARALLEL; cfg->type = V4L2_MBUS_PARALLEL;
cfg->bus.parallel.flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH
| ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH
: V4L2_MBUS_VSYNC_ACTIVE_LOW)
| ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW
: V4L2_MBUS_HSYNC_ACTIVE_HIGH)
| ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING
: V4L2_MBUS_PCLK_SAMPLE_FALLING);
return 0; return 0;
} }
......
...@@ -652,10 +652,12 @@ static int ov9640_get_mbus_config(struct v4l2_subdev *sd, ...@@ -652,10 +652,12 @@ static int ov9640_get_mbus_config(struct v4l2_subdev *sd,
unsigned int pad, unsigned int pad,
struct v4l2_mbus_config *cfg) struct v4l2_mbus_config *cfg)
{ {
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL; cfg->type = V4L2_MBUS_PARALLEL;
cfg->bus.parallel.flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
return 0; return 0;
} }
......
...@@ -1613,24 +1613,8 @@ static int tc358743_get_mbus_config(struct v4l2_subdev *sd, ...@@ -1613,24 +1613,8 @@ static int tc358743_get_mbus_config(struct v4l2_subdev *sd,
cfg->type = V4L2_MBUS_CSI2_DPHY; cfg->type = V4L2_MBUS_CSI2_DPHY;
/* Support for non-continuous CSI-2 clock is missing in the driver */ /* Support for non-continuous CSI-2 clock is missing in the driver */
cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; cfg->bus.mipi_csi2.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
cfg->bus.mipi_csi2.num_data_lanes = state->csi_lanes_in_use;
switch (state->csi_lanes_in_use) {
case 1:
cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
break;
case 2:
cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
break;
case 3:
cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
break;
case 4:
cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
break;
default:
return -EINVAL;
}
return 0; return 0;
} }
......
...@@ -1198,8 +1198,10 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd, ...@@ -1198,8 +1198,10 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
struct tvp5150 *decoder = to_tvp5150(sd); struct tvp5150 *decoder = to_tvp5150(sd);
cfg->type = decoder->mbus_type; cfg->type = decoder->mbus_type;
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING cfg->bus.parallel.flags = V4L2_MBUS_MASTER
| V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; | V4L2_MBUS_PCLK_SAMPLE_RISING
| V4L2_MBUS_FIELD_EVEN_LOW
| V4L2_MBUS_DATA_ACTIVE_HIGH;
return 0; return 0;
} }
......
...@@ -359,7 +359,7 @@ static int csi2dc_get_mbus_config(struct csi2dc_device *csi2dc) ...@@ -359,7 +359,7 @@ static int csi2dc_get_mbus_config(struct csi2dc_device *csi2dc)
dev_dbg(csi2dc->dev, "subdev sending on channel %d\n", csi2dc->vc); dev_dbg(csi2dc->dev, "subdev sending on channel %d\n", csi2dc->vc);
csi2dc->clk_gated = mbus_config.flags & csi2dc->clk_gated = mbus_config.bus.parallel.flags &
V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
dev_dbg(csi2dc->dev, "mbus_config: %s clock\n", dev_dbg(csi2dc->dev, "mbus_config: %s clock\n",
......
...@@ -1587,24 +1587,26 @@ static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) ...@@ -1587,24 +1587,26 @@ static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
* PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering
* roles should match. * roles should match.
*/ */
if (cfg.flags != mbus_config) { if (cfg.bus.parallel.flags != mbus_config) {
unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER |
V4L2_MBUS_SLAVE); V4L2_MBUS_SLAVE);
if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER | unsigned int flags = cfg.bus.parallel.flags;
V4L2_MBUS_SLAVE))) {
if (pxa_mbus_role != (flags & (V4L2_MBUS_MASTER |
V4L2_MBUS_SLAVE))) {
dev_err(pcdev_to_dev(pcdev), dev_err(pcdev_to_dev(pcdev),
"Unsupported mbus configuration: bus mastering\n"); "Unsupported mbus configuration: bus mastering\n");
return -EINVAL; return -EINVAL;
} }
if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) { if (flags & V4L2_MBUS_DATA_ACTIVE_LOW) {
dev_err(pcdev_to_dev(pcdev), dev_err(pcdev_to_dev(pcdev),
"Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); "Unsupported mbus configuration: DATA_ACTIVE_LOW\n");
return -EINVAL; return -EINVAL;
} }
} }
pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt); pxa_camera_setup_cicr(pcdev, cfg.bus.parallel.flags, pixfmt);
return 0; return 0;
} }
......
...@@ -603,7 +603,6 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, ...@@ -603,7 +603,6 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
unsigned int *lanes) unsigned int *lanes)
{ {
struct v4l2_mbus_config mbus_config = { 0 }; struct v4l2_mbus_config mbus_config = { 0 };
unsigned int num_lanes = UINT_MAX;
int ret; int ret;
*lanes = priv->lanes; *lanes = priv->lanes;
...@@ -626,23 +625,14 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, ...@@ -626,23 +625,14 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
return -EINVAL; return -EINVAL;
} }
if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) {
num_lanes = 1;
else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE)
num_lanes = 2;
else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE)
num_lanes = 3;
else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE)
num_lanes = 4;
if (num_lanes > priv->lanes) {
dev_err(priv->dev, dev_err(priv->dev,
"Unsupported mbus config: too many data lanes %u\n", "Unsupported mbus config: too many data lanes %u\n",
num_lanes); mbus_config.bus.mipi_csi2.num_data_lanes);
return -EINVAL; return -EINVAL;
} }
*lanes = num_lanes; *lanes = mbus_config.bus.mipi_csi2.num_data_lanes;
return 0; return 0;
} }
......
...@@ -718,9 +718,10 @@ static int csi_setup(struct csi_priv *priv) ...@@ -718,9 +718,10 @@ static int csi_setup(struct csi_priv *priv)
/* compose mbus_config from the upstream endpoint */ /* compose mbus_config from the upstream endpoint */
mbus_cfg.type = priv->upstream_ep.bus_type; mbus_cfg.type = priv->upstream_ep.bus_type;
mbus_cfg.flags = is_parallel_bus(&priv->upstream_ep) ? if (is_parallel_bus(&priv->upstream_ep))
priv->upstream_ep.bus.parallel.flags : mbus_cfg.bus.parallel = priv->upstream_ep.bus.parallel;
priv->upstream_ep.bus.mipi_csi2.flags; else
mbus_cfg.bus.mipi_csi2 = priv->upstream_ep.bus.mipi_csi2;
if_fmt = *infmt; if_fmt = *infmt;
crop = priv->crop; crop = priv->crop;
......
...@@ -303,7 +303,6 @@ static void csi2ipu_gasket_init(struct csi2_dev *csi2) ...@@ -303,7 +303,6 @@ static void csi2ipu_gasket_init(struct csi2_dev *csi2)
static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes) static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes)
{ {
struct v4l2_mbus_config mbus_config = { 0 }; struct v4l2_mbus_config mbus_config = { 0 };
unsigned int num_lanes = UINT_MAX;
int ret; int ret;
*lanes = csi2->data_lanes; *lanes = csi2->data_lanes;
...@@ -326,32 +325,14 @@ static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes) ...@@ -326,32 +325,14 @@ static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes)
return -EINVAL; return -EINVAL;
} }
switch (mbus_config.flags & V4L2_MBUS_CSI2_LANES) { if (mbus_config.bus.mipi_csi2.num_data_lanes > csi2->data_lanes) {
case V4L2_MBUS_CSI2_1_LANE:
num_lanes = 1;
break;
case V4L2_MBUS_CSI2_2_LANE:
num_lanes = 2;
break;
case V4L2_MBUS_CSI2_3_LANE:
num_lanes = 3;
break;
case V4L2_MBUS_CSI2_4_LANE:
num_lanes = 4;
break;
default:
num_lanes = csi2->data_lanes;
break;
}
if (num_lanes > csi2->data_lanes) {
dev_err(csi2->dev, dev_err(csi2->dev,
"Unsupported mbus config: too many data lanes %u\n", "Unsupported mbus config: too many data lanes %u\n",
num_lanes); mbus_config.bus.mipi_csi2.num_data_lanes);
return -EINVAL; return -EINVAL;
} }
*lanes = num_lanes; *lanes = mbus_config.bus.mipi_csi2.num_data_lanes;
return 0; return 0;
} }
......
...@@ -166,12 +166,26 @@ enum v4l2_mbus_type { ...@@ -166,12 +166,26 @@ enum v4l2_mbus_type {
/** /**
* struct v4l2_mbus_config - media bus configuration * struct v4l2_mbus_config - media bus configuration
* @type: in: interface type * @type: interface type
* @flags: in / out: configuration flags, depending on @type * @bus: bus configuration data structure
* @bus.parallel: embedded &struct v4l2_mbus_config_parallel.
* Used if the bus is parallel or BT.656.
* @bus.mipi_csi1: embedded &struct v4l2_mbus_config_mipi_csi1.
* Used if the bus is MIPI Alliance's Camera Serial
* Interface version 1 (MIPI CSI1) or Standard
* Mobile Imaging Architecture's Compact Camera Port 2
* (SMIA CCP2).
* @bus.mipi_csi2: embedded &struct v4l2_mbus_config_mipi_csi2.
* Used if the bus is MIPI Alliance's Camera Serial
* Interface version 2 (MIPI CSI2).
*/ */
struct v4l2_mbus_config { struct v4l2_mbus_config {
enum v4l2_mbus_type type; enum v4l2_mbus_type type;
unsigned int flags; union {
struct v4l2_mbus_config_parallel parallel;
struct v4l2_mbus_config_mipi_csi1 mipi_csi1;
struct v4l2_mbus_config_mipi_csi2 mipi_csi2;
} bus;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment