media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code
Introduce MIPI CSI-2 support to the bridge with a new port, source and hardware configuration helper. Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
dc85e4cdbe
commit
a617f33d8e
|
@ -20,6 +20,7 @@
|
|||
|
||||
enum sun6i_csi_port {
|
||||
SUN6I_CSI_PORT_PARALLEL = 0,
|
||||
SUN6I_CSI_PORT_MIPI_CSI2 = 1,
|
||||
};
|
||||
|
||||
struct sun6i_csi_buffer {
|
||||
|
|
|
@ -226,7 +226,7 @@ static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev)
|
|||
}
|
||||
|
||||
static void
|
||||
sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev)
|
||||
sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev)
|
||||
{
|
||||
struct device *dev = csi_dev->dev;
|
||||
struct regmap *regmap = csi_dev->regmap;
|
||||
|
@ -316,6 +316,25 @@ sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev)
|
|||
regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
|
||||
}
|
||||
|
||||
static void
|
||||
sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev)
|
||||
{
|
||||
struct regmap *regmap = csi_dev->regmap;
|
||||
u32 value = SUN6I_CSI_IF_CFG_IF_MIPI;
|
||||
u32 field;
|
||||
|
||||
sun6i_csi_bridge_format(csi_dev, NULL, &field);
|
||||
|
||||
if (field == V4L2_FIELD_INTERLACED ||
|
||||
field == V4L2_FIELD_INTERLACED_TB ||
|
||||
field == V4L2_FIELD_INTERLACED_BT)
|
||||
value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED;
|
||||
else
|
||||
value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE;
|
||||
|
||||
regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value);
|
||||
}
|
||||
|
||||
static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev)
|
||||
{
|
||||
struct regmap *regmap = csi_dev->regmap;
|
||||
|
@ -367,9 +386,16 @@ static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev)
|
|||
regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value);
|
||||
}
|
||||
|
||||
static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev)
|
||||
static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev,
|
||||
struct sun6i_csi_bridge_source *source)
|
||||
{
|
||||
sun6i_csi_bridge_configure_interface(csi_dev);
|
||||
struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
|
||||
|
||||
if (source == &bridge->source_parallel)
|
||||
sun6i_csi_bridge_configure_parallel(csi_dev);
|
||||
else
|
||||
sun6i_csi_bridge_configure_mipi_csi2(csi_dev);
|
||||
|
||||
sun6i_csi_bridge_configure_format(csi_dev);
|
||||
}
|
||||
|
||||
|
@ -381,6 +407,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)
|
|||
struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
|
||||
struct media_pad *local_pad = &bridge->pads[SUN6I_CSI_BRIDGE_PAD_SINK];
|
||||
struct device *dev = csi_dev->dev;
|
||||
struct sun6i_csi_bridge_source *source;
|
||||
struct v4l2_subdev *source_subdev;
|
||||
struct media_pad *remote_pad;
|
||||
/* Initialize to 0 to use both in disable label (ret != 0) and off. */
|
||||
|
@ -397,6 +424,11 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)
|
|||
|
||||
source_subdev = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
if (source_subdev == bridge->source_parallel.subdev)
|
||||
source = &bridge->source_parallel;
|
||||
else
|
||||
source = &bridge->source_mipi_csi2;
|
||||
|
||||
if (!on) {
|
||||
v4l2_subdev_call(source_subdev, video, s_stream, 0);
|
||||
goto disable;
|
||||
|
@ -414,7 +446,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on)
|
|||
|
||||
/* Configure */
|
||||
|
||||
sun6i_csi_bridge_configure(csi_dev);
|
||||
sun6i_csi_bridge_configure(csi_dev, source);
|
||||
sun6i_csi_capture_configure(csi_dev);
|
||||
|
||||
/* State Update */
|
||||
|
@ -606,6 +638,7 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
|
|||
struct sun6i_csi_bridge_async_subdev *bridge_async_subdev =
|
||||
container_of(async_subdev, struct sun6i_csi_bridge_async_subdev,
|
||||
async_subdev);
|
||||
struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
|
||||
struct sun6i_csi_bridge_source *source = bridge_async_subdev->source;
|
||||
bool enabled;
|
||||
|
||||
|
@ -613,6 +646,9 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier,
|
|||
case SUN6I_CSI_PORT_PARALLEL:
|
||||
enabled = true;
|
||||
break;
|
||||
case SUN6I_CSI_PORT_MIPI_CSI2:
|
||||
enabled = !bridge->source_parallel.expected;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -759,6 +795,8 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
|
|||
sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel,
|
||||
SUN6I_CSI_PORT_PARALLEL,
|
||||
parallel_mbus_types);
|
||||
sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2,
|
||||
SUN6I_CSI_PORT_MIPI_CSI2, NULL);
|
||||
|
||||
ret = v4l2_async_nf_register(v4l2_dev, notifier);
|
||||
if (ret) {
|
||||
|
|
|
@ -46,6 +46,7 @@ struct sun6i_csi_bridge {
|
|||
struct mutex lock; /* Mbus format lock. */
|
||||
|
||||
struct sun6i_csi_bridge_source source_parallel;
|
||||
struct sun6i_csi_bridge_source source_mipi_csi2;
|
||||
};
|
||||
|
||||
/* Helpers */
|
||||
|
|
Loading…
Reference in New Issue