summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/omap3isp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/omap3isp')
-rw-r--r--drivers/media/platform/omap3isp/isp.c161
-rw-r--r--drivers/media/platform/omap3isp/isp.h4
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c22
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c18
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c6
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c91
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.h7
-rw-r--r--drivers/media/platform/omap3isp/ispreg.h4
-rw-r--r--drivers/media/platform/omap3isp/omap3isp.h6
9 files changed, 198 insertions, 121 deletions
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 9df64c189883..1a428fe9f070 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1859,6 +1859,7 @@ static void isp_cleanup_modules(struct isp_device *isp)
omap3isp_ccdc_cleanup(isp);
omap3isp_ccp2_cleanup(isp);
omap3isp_csi2_cleanup(isp);
+ omap3isp_csiphy_cleanup(isp);
}
static int isp_initialize_modules(struct isp_device *isp)
@@ -1868,7 +1869,7 @@ static int isp_initialize_modules(struct isp_device *isp)
ret = omap3isp_csiphy_init(isp);
if (ret < 0) {
dev_err(isp->dev, "CSI PHY initialization failed\n");
- goto error_csiphy;
+ return ret;
}
ret = omap3isp_csi2_init(isp);
@@ -1879,7 +1880,8 @@ static int isp_initialize_modules(struct isp_device *isp)
ret = omap3isp_ccp2_init(isp);
if (ret < 0) {
- dev_err(isp->dev, "CCP2 initialization failed\n");
+ if (ret != -EPROBE_DEFER)
+ dev_err(isp->dev, "CCP2 initialization failed\n");
goto error_ccp2;
}
@@ -1936,7 +1938,8 @@ error_ccdc:
error_ccp2:
omap3isp_csi2_cleanup(isp);
error_csi2:
-error_csiphy:
+ omap3isp_csiphy_cleanup(isp);
+
return ret;
}
@@ -2015,13 +2018,14 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint vep;
unsigned int i;
int ret;
+ bool csi1 = false;
ret = v4l2_fwnode_endpoint_parse(fwnode, &vep);
if (ret)
return ret;
- dev_dbg(dev, "parsing endpoint %s, interface %u\n",
- to_of_node(fwnode)->full_name, vep.base.port);
+ dev_dbg(dev, "parsing endpoint %pOF, interface %u\n",
+ to_of_node(fwnode), vep.base.port);
switch (vep.base.port) {
case ISP_OF_PHY_PARALLEL:
@@ -2039,48 +2043,102 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
!!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
buscfg->bus.parallel.data_pol =
!!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
+ buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656;
break;
case ISP_OF_PHY_CSIPHY1:
case ISP_OF_PHY_CSIPHY2:
- /* FIXME: always assume CSI-2 for now. */
+ switch (vep.bus_type) {
+ case V4L2_MBUS_CCP2:
+ case V4L2_MBUS_CSI1:
+ dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
+ csi1 = true;
+ break;
+ case V4L2_MBUS_CSI2:
+ dev_dbg(dev, "CSI-2 configuration\n");
+ csi1 = false;
+ break;
+ default:
+ dev_err(dev, "unsupported bus type %u\n",
+ vep.bus_type);
+ return -EINVAL;
+ }
+
switch (vep.base.port) {
case ISP_OF_PHY_CSIPHY1:
- buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
+ if (csi1)
+ buscfg->interface = ISP_INTERFACE_CCP2B_PHY1;
+ else
+ buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
break;
case ISP_OF_PHY_CSIPHY2:
- buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
+ if (csi1)
+ buscfg->interface = ISP_INTERFACE_CCP2B_PHY2;
+ else
+ buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
break;
}
- buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane;
- buscfg->bus.csi2.lanecfg.clk.pol =
- vep.bus.mipi_csi2.lane_polarities[0];
- dev_dbg(dev, "clock lane polarity %u, pos %u\n",
- buscfg->bus.csi2.lanecfg.clk.pol,
- buscfg->bus.csi2.lanecfg.clk.pos);
-
- for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) {
- buscfg->bus.csi2.lanecfg.data[i].pos =
- vep.bus.mipi_csi2.data_lanes[i];
- buscfg->bus.csi2.lanecfg.data[i].pol =
- vep.bus.mipi_csi2.lane_polarities[i + 1];
- dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i,
- buscfg->bus.csi2.lanecfg.data[i].pol,
- buscfg->bus.csi2.lanecfg.data[i].pos);
+ if (csi1) {
+ buscfg->bus.ccp2.lanecfg.clk.pos =
+ vep.bus.mipi_csi1.clock_lane;
+ buscfg->bus.ccp2.lanecfg.clk.pol =
+ vep.bus.mipi_csi1.lane_polarity[0];
+ dev_dbg(dev, "clock lane polarity %u, pos %u\n",
+ buscfg->bus.ccp2.lanecfg.clk.pol,
+ buscfg->bus.ccp2.lanecfg.clk.pos);
+
+ buscfg->bus.ccp2.lanecfg.data[0].pos =
+ vep.bus.mipi_csi1.data_lane;
+ buscfg->bus.ccp2.lanecfg.data[0].pol =
+ vep.bus.mipi_csi1.lane_polarity[1];
+
+ dev_dbg(dev, "data lane polarity %u, pos %u\n",
+ buscfg->bus.ccp2.lanecfg.data[0].pol,
+ buscfg->bus.ccp2.lanecfg.data[0].pos);
+
+ buscfg->bus.ccp2.strobe_clk_pol =
+ vep.bus.mipi_csi1.clock_inv;
+ buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe;
+ buscfg->bus.ccp2.ccp2_mode =
+ vep.bus_type == V4L2_MBUS_CCP2;
+ buscfg->bus.ccp2.vp_clk_pol = 1;
+
+ buscfg->bus.ccp2.crc = 1;
+ } else {
+ buscfg->bus.csi2.lanecfg.clk.pos =
+ vep.bus.mipi_csi2.clock_lane;
+ buscfg->bus.csi2.lanecfg.clk.pol =
+ vep.bus.mipi_csi2.lane_polarities[0];
+ dev_dbg(dev, "clock lane polarity %u, pos %u\n",
+ buscfg->bus.csi2.lanecfg.clk.pol,
+ buscfg->bus.csi2.lanecfg.clk.pos);
+
+ buscfg->bus.csi2.num_data_lanes =
+ vep.bus.mipi_csi2.num_data_lanes;
+
+ for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
+ buscfg->bus.csi2.lanecfg.data[i].pos =
+ vep.bus.mipi_csi2.data_lanes[i];
+ buscfg->bus.csi2.lanecfg.data[i].pol =
+ vep.bus.mipi_csi2.lane_polarities[i + 1];
+ dev_dbg(dev,
+ "data lane %u polarity %u, pos %u\n", i,
+ buscfg->bus.csi2.lanecfg.data[i].pol,
+ buscfg->bus.csi2.lanecfg.data[i].pos);
+ }
+ /*
+ * FIXME: now we assume the CRC is always there.
+ * Implement a way to obtain this information from the
+ * sensor. Frame descriptors, perhaps?
+ */
+ buscfg->bus.csi2.crc = 1;
}
-
- /*
- * FIXME: now we assume the CRC is always there.
- * Implement a way to obtain this information from the
- * sensor. Frame descriptors, perhaps?
- */
- buscfg->bus.csi2.crc = 1;
break;
default:
- dev_warn(dev, "%s: invalid interface %u\n",
- to_of_node(fwnode)->full_name, vep.base.port);
- break;
+ dev_warn(dev, "%pOF: invalid interface %u\n",
+ to_of_node(fwnode), vep.base.port);
+ return -EINVAL;
}
return 0;
@@ -2105,10 +2163,12 @@ static int isp_fwnodes_parse(struct device *dev,
if (!isd)
goto error;
- notifier->subdevs[notifier->num_subdevs] = &isd->asd;
+ if (isp_fwnode_parse(dev, fwnode, isd)) {
+ devm_kfree(dev, isd);
+ continue;
+ }
- if (isp_fwnode_parse(dev, fwnode, isd))
- goto error;
+ notifier->subdevs[notifier->num_subdevs] = &isd->asd;
isd->asd.match.fwnode.fwnode =
fwnode_graph_get_remote_port_parent(fwnode);
@@ -2128,26 +2188,12 @@ error:
return -EINVAL;
}
-static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,
- struct v4l2_subdev *subdev,
- struct v4l2_async_subdev *asd)
-{
- struct isp_async_subdev *isd =
- container_of(asd, struct isp_async_subdev, asd);
-
- isd->sd = subdev;
- isd->sd->host_priv = &isd->bus;
-
- return 0;
-}
-
static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
{
struct isp_device *isp = container_of(async, struct isp_device,
notifier);
struct v4l2_device *v4l2_dev = &isp->v4l2_dev;
struct v4l2_subdev *sd;
- struct isp_bus_cfg *bus;
int ret;
ret = media_entity_enum_init(&isp->crashed, &isp->media_dev);
@@ -2155,13 +2201,13 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
return ret;
list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
- /* Only try to link entities whose interface was set on bound */
- if (sd->host_priv) {
- bus = (struct isp_bus_cfg *)sd->host_priv;
- ret = isp_link_entity(isp, &sd->entity, bus->interface);
- if (ret < 0)
- return ret;
- }
+ if (!sd->asd)
+ continue;
+
+ ret = isp_link_entity(isp, &sd->entity,
+ v4l2_subdev_to_bus_cfg(sd)->interface);
+ if (ret < 0)
+ return ret;
}
ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
@@ -2339,7 +2385,6 @@ static int isp_probe(struct platform_device *pdev)
if (ret < 0)
goto error_register_entities;
- isp->notifier.bound = isp_subdev_notifier_bound;
isp->notifier.complete = isp_subdev_notifier_complete;
ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier);
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 2f2ae609c548..e528df6efc09 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -226,11 +226,13 @@ struct isp_device {
};
struct isp_async_subdev {
- struct v4l2_subdev *sd;
struct isp_bus_cfg bus;
struct v4l2_async_subdev asd;
};
+#define v4l2_subdev_to_bus_cfg(sd) \
+ (&container_of((sd)->asd, struct isp_async_subdev, asd)->bus)
+
#define v4l2_dev_to_isp_device(dev) \
container_of(dev, struct isp_device, v4l2_dev)
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 7207558d722c..b66276ab5765 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1139,15 +1139,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
if (ccdc->input == CCDC_INPUT_PARALLEL) {
- struct v4l2_mbus_config cfg;
- int ret;
+ struct v4l2_subdev *sd =
+ to_isp_pipeline(&ccdc->subdev.entity)->external;
- ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg);
- if (!ret)
- ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
-
- parcfg = &((struct isp_bus_cfg *)sensor->host_priv)
- ->bus.parallel;
+ parcfg = &v4l2_subdev_to_bus_cfg(sd)->bus.parallel;
+ ccdc->bt656 = parcfg->bt656;
}
/* CCDC_PAD_SINK */
@@ -2418,11 +2414,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd,
/* We've got a parallel sensor here. */
if (ccdc->input == CCDC_INPUT_PARALLEL) {
- struct isp_parallel_cfg *parcfg =
- &((struct isp_bus_cfg *)
- media_entity_to_v4l2_subdev(link->source->entity)
- ->host_priv)->bus.parallel;
- parallel_shift = parcfg->data_lane_shift;
+ struct v4l2_subdev *sd =
+ media_entity_to_v4l2_subdev(link->source->entity);
+ struct isp_bus_cfg *bus_cfg = v4l2_subdev_to_bus_cfg(sd);
+
+ parallel_shift = bus_cfg->bus.parallel.data_lane_shift;
} else {
parallel_shift = 0;
}
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index ca095238510d..e062939d0d05 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -213,14 +213,17 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
struct isp_device *isp = to_isp_device(ccp2);
u32 val;
- /* CCP2B mode */
val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) |
- ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE;
+ ISPCCP2_CTRL_MODE;
/* Data/strobe physical layer */
BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK,
buscfg->phy_layer);
+ BIT_SET(val, ISPCCP2_CTRL_IO_OUT_SEL_SHIFT,
+ ISPCCP2_CTRL_IO_OUT_SEL_MASK, buscfg->ccp2_mode);
BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK,
buscfg->strobe_clk_pol);
+ BIT_SET(val, ISPCCP2_CTRL_VP_CLK_POL_SHIFT,
+ ISPCCP2_CTRL_VP_CLK_POL_MASK, buscfg->vp_clk_pol);
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
@@ -347,6 +350,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
*/
static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
{
+ struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
const struct isp_bus_cfg *buscfg;
struct v4l2_mbus_framefmt *format;
struct media_pad *pad;
@@ -358,7 +362,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
- buscfg = sensor->host_priv;
+ buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2);
if (ret < 0)
@@ -838,7 +842,7 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
switch (enable) {
case ISP_PIPELINE_STREAM_CONTINUOUS:
if (ccp2->phy) {
- ret = omap3isp_csiphy_acquire(ccp2->phy);
+ ret = omap3isp_csiphy_acquire(ccp2->phy, &sd->entity);
if (ret < 0)
return ret;
}
@@ -1137,10 +1141,16 @@ int omap3isp_ccp2_init(struct isp_device *isp)
if (isp->revision == ISP_REVISION_2_0) {
ccp2->vdds_csib = devm_regulator_get(isp->dev, "vdds_csib");
if (IS_ERR(ccp2->vdds_csib)) {
+ if (PTR_ERR(ccp2->vdds_csib) == -EPROBE_DEFER) {
+ dev_dbg(isp->dev,
+ "Can't get regulator vdds_csib, deferring probing\n");
+ return -EPROBE_DEFER;
+ }
dev_dbg(isp->dev,
"Could not get regulator vdds_csib\n");
ccp2->vdds_csib = NULL;
}
+ ccp2->phy = &isp->isp_csiphy2;
} else if (isp->revision == ISP_REVISION_15_0) {
ccp2->phy = &isp->isp_csiphy1;
}
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index 7dae2fe0d42d..a4d3d030e81e 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -490,7 +490,7 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
if (!csi2->available)
return -ENODEV;
- if (csi2->phy->phy_in_use)
+ if (csi2->phy->entity)
return -EBUSY;
isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
@@ -566,7 +566,7 @@ static int csi2_configure(struct isp_csi2_device *csi2)
pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
- buscfg = sensor->host_priv;
+ buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
csi2->frame_skip = 0;
v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
@@ -1053,7 +1053,7 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
switch (enable) {
case ISP_PIPELINE_STREAM_CONTINUOUS:
- if (omap3isp_csiphy_acquire(csi2->phy) < 0)
+ if (omap3isp_csiphy_acquire(csi2->phy, &sd->entity) < 0)
return -ENODEV;
if (csi2->output & CSI2_OUTPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index 871d4fe09c7f..a28fb79abaac 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -164,30 +164,28 @@ static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
static int omap3isp_csiphy_config(struct isp_csiphy *phy)
{
- struct isp_csi2_device *csi2 = phy->csi2;
- struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
- struct isp_bus_cfg *buscfg = pipe->external->host_priv;
+ struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
+ struct isp_bus_cfg *buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
struct isp_csiphy_lanes_cfg *lanes;
int csi2_ddrclk_khz;
- unsigned int used_lanes = 0;
+ unsigned int num_data_lanes, used_lanes = 0;
unsigned int i;
u32 reg;
- if (!buscfg) {
- struct isp_async_subdev *isd =
- container_of(pipe->external->asd,
- struct isp_async_subdev, asd);
- buscfg = &isd->bus;
- }
-
if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1
- || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2)
+ || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) {
lanes = &buscfg->bus.ccp2.lanecfg;
- else
+ num_data_lanes = 1;
+ } else {
lanes = &buscfg->bus.csi2.lanecfg;
+ num_data_lanes = buscfg->bus.csi2.num_data_lanes;
+ }
+
+ if (num_data_lanes > phy->num_data_lanes)
+ return -EINVAL;
/* Clock and data lanes verification */
- for (i = 0; i < phy->num_data_lanes; i++) {
+ for (i = 0; i < num_data_lanes; i++) {
if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
return -EINVAL;
@@ -216,7 +214,7 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
csi2_ddrclk_khz = pipe->external_rate / 1000
/ (2 * hweight32(used_lanes)) * pipe->external_width;
- reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG0);
+ reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
ISPCSIPHY_REG0_THS_SETTLE_MASK);
@@ -227,9 +225,9 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3)
<< ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
- isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
+ isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
- reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG1);
+ reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
ISPCSIPHY_REG1_TCLK_MISS_MASK |
@@ -238,12 +236,12 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
- isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
+ isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
/* DPHY lane configuration */
- reg = isp_reg_readl(csi2->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
+ reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
- for (i = 0; i < phy->num_data_lanes; i++) {
+ for (i = 0; i < num_data_lanes; i++) {
reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
reg |= (lanes->data[i].pol <<
@@ -257,12 +255,12 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy)
reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
- isp_reg_writel(csi2->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
+ isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
return 0;
}
-int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy, struct media_entity *entity)
{
int rval;
@@ -282,20 +280,25 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
if (rval < 0)
goto done;
+ phy->entity = entity;
+
rval = omap3isp_csiphy_config(phy);
if (rval < 0)
goto done;
- rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
- if (rval) {
- regulator_disable(phy->vdd);
- goto done;
- }
-
- csiphy_power_autoswitch_enable(phy, true);
- phy->phy_in_use = 1;
+ if (phy->isp->revision == ISP_REVISION_15_0) {
+ rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
+ if (rval) {
+ regulator_disable(phy->vdd);
+ goto done;
+ }
+ csiphy_power_autoswitch_enable(phy, true);
+ }
done:
+ if (rval < 0)
+ phy->entity = NULL;
+
mutex_unlock(&phy->mutex);
return rval;
}
@@ -303,18 +306,19 @@ done:
void omap3isp_csiphy_release(struct isp_csiphy *phy)
{
mutex_lock(&phy->mutex);
- if (phy->phy_in_use) {
- struct isp_csi2_device *csi2 = phy->csi2;
- struct isp_pipeline *pipe =
- to_isp_pipeline(&csi2->subdev.entity);
- struct isp_bus_cfg *buscfg = pipe->external->host_priv;
+ if (phy->entity) {
+ struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
+ struct isp_bus_cfg *buscfg =
+ v4l2_subdev_to_bus_cfg(pipe->external);
csiphy_routing_cfg(phy, buscfg->interface, false,
buscfg->bus.ccp2.phy_layer);
- csiphy_power_autoswitch_enable(phy, false);
- csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
+ if (phy->isp->revision == ISP_REVISION_15_0) {
+ csiphy_power_autoswitch_enable(phy, false);
+ csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
+ }
regulator_disable(phy->vdd);
- phy->phy_in_use = 0;
+ phy->entity = NULL;
}
mutex_unlock(&phy->mutex);
}
@@ -334,14 +338,21 @@ int omap3isp_csiphy_init(struct isp_device *isp)
phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
mutex_init(&phy2->mutex);
+ phy1->isp = isp;
+ mutex_init(&phy1->mutex);
+
if (isp->revision == ISP_REVISION_15_0) {
- phy1->isp = isp;
phy1->csi2 = &isp->isp_csi2c;
phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
- mutex_init(&phy1->mutex);
}
return 0;
}
+
+void omap3isp_csiphy_cleanup(struct isp_device *isp)
+{
+ mutex_destroy(&isp->isp_csiphy1.mutex);
+ mutex_destroy(&isp->isp_csiphy2.mutex);
+}
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h
index 28b63b28f9f7..91543a09b28a 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.h
+++ b/drivers/media/platform/omap3isp/ispcsiphy.h
@@ -25,9 +25,10 @@ struct regulator;
struct isp_csiphy {
struct isp_device *isp;
struct mutex mutex; /* serialize csiphy configuration */
- u8 phy_in_use;
struct isp_csi2_device *csi2;
struct regulator *vdd;
+ /* the entity that acquired the phy */
+ struct media_entity *entity;
/* mem resources - enums as defined in enum isp_mem_resources */
unsigned int cfg_regs;
@@ -36,8 +37,10 @@ struct isp_csiphy {
u8 num_data_lanes; /* number of CSI2 Data Lanes supported */
};
-int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy,
+ struct media_entity *entity);
void omap3isp_csiphy_release(struct isp_csiphy *phy);
int omap3isp_csiphy_init(struct isp_device *isp);
+void omap3isp_csiphy_cleanup(struct isp_device *isp);
#endif /* OMAP3_ISP_CSI_PHY_H */
diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
index b5ea8da0b904..d08483919a77 100644
--- a/drivers/media/platform/omap3isp/ispreg.h
+++ b/drivers/media/platform/omap3isp/ispreg.h
@@ -87,6 +87,8 @@
#define ISPCCP2_CTRL_PHY_SEL_MASK 0x1
#define ISPCCP2_CTRL_PHY_SEL_SHIFT 1
#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2)
+#define ISPCCP2_CTRL_IO_OUT_SEL_MASK 0x1
+#define ISPCCP2_CTRL_IO_OUT_SEL_SHIFT 2
#define ISPCCP2_CTRL_MODE (1 << 4)
#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9)
#define ISPCCP2_CTRL_INV (1 << 10)
@@ -94,6 +96,8 @@
#define ISPCCP2_CTRL_INV_SHIFT 10
#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11)
#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12)
+#define ISPCCP2_CTRL_VP_CLK_POL_MASK 0x1
+#define ISPCCP2_CTRL_VP_CLK_POL_SHIFT 12
#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15
#define ISPCCP2_CTRL_VPCLK_DIV_MASK 0x1ffff /* [31:15] */
#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */
diff --git a/drivers/media/platform/omap3isp/omap3isp.h b/drivers/media/platform/omap3isp/omap3isp.h
index 443e8f7673e2..9fb4d5bce004 100644
--- a/drivers/media/platform/omap3isp/omap3isp.h
+++ b/drivers/media/platform/omap3isp/omap3isp.h
@@ -46,6 +46,7 @@ enum isp_interface_type {
* 0 - Positive, 1 - Negative
* @data_pol: Data polarity
* 0 - Normal, 1 - One's complement
+ * @bt656: Data contain BT.656 embedded synchronization
*/
struct isp_parallel_cfg {
unsigned int data_lane_shift:3;
@@ -54,6 +55,7 @@ struct isp_parallel_cfg {
unsigned int vs_pol:1;
unsigned int fld_pol:1;
unsigned int data_pol:1;
+ unsigned int bt656:1;
};
enum {
@@ -108,16 +110,20 @@ struct isp_ccp2_cfg {
unsigned int ccp2_mode:1;
unsigned int phy_layer:1;
unsigned int vpclk_div:2;
+ unsigned int vp_clk_pol:1;
struct isp_csiphy_lanes_cfg lanecfg;
};
/**
* struct isp_csi2_cfg - CSI2 interface configuration
* @crc: Enable the cyclic redundancy check
+ * @lanecfg: CSI-2 lane configuration
+ * @num_data_lanes: The number of data lanes in use
*/
struct isp_csi2_cfg {
unsigned crc:1;
struct isp_csiphy_lanes_cfg lanecfg;
+ u8 num_data_lanes;
};
struct isp_bus_cfg {