mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
media: i2c: max9286: Support manual framesync operation
The MAX9286 can generate a framesync signal to synchronize the cameras, using an internal timer. Support this mode of operation and configure it through the .s_frameinterval() operation. If the frame interval is not 0, framesync is switched to manual mode with the specified interval, otherwise automatic mode is used. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo+renesas@jmondi.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
817660f44d
commit
cffc9fb1ed
1 changed files with 75 additions and 9 deletions
|
@ -174,9 +174,11 @@ struct max9286_priv {
|
|||
u32 gpio_poc[2];
|
||||
|
||||
struct v4l2_ctrl_handler ctrls;
|
||||
struct v4l2_ctrl *pixelrate;
|
||||
struct v4l2_ctrl *pixelrate_ctrl;
|
||||
unsigned int pixelrate;
|
||||
|
||||
struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
|
||||
struct v4l2_fract interval;
|
||||
|
||||
/* Protects controls and fmt structures */
|
||||
struct mutex mutex;
|
||||
|
@ -477,6 +479,40 @@ static int max9286_check_config_link(struct max9286_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void max9286_set_fsync_period(struct max9286_priv *priv)
|
||||
{
|
||||
u32 fsync;
|
||||
|
||||
if (!priv->interval.numerator || !priv->interval.denominator) {
|
||||
/*
|
||||
* Special case, a null interval enables automatic FRAMESYNC
|
||||
* mode. FRAMESYNC is taken from the slowest link.
|
||||
*/
|
||||
max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ |
|
||||
MAX9286_FSYNCMETH_AUTO);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Manual FRAMESYNC
|
||||
*
|
||||
* The FRAMESYNC generator is configured with a period expressed as a
|
||||
* number of PCLK periods.
|
||||
*/
|
||||
fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
|
||||
priv->interval.denominator);
|
||||
|
||||
dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
|
||||
priv->pixelrate);
|
||||
|
||||
max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT |
|
||||
MAX9286_FSYNCMETH_MANUAL);
|
||||
|
||||
max9286_write(priv, 0x06, (fsync >> 0) & 0xff);
|
||||
max9286_write(priv, 0x07, (fsync >> 8) & 0xff);
|
||||
max9286_write(priv, 0x08, (fsync >> 16) & 0xff);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* V4L2 Subdev
|
||||
*/
|
||||
|
@ -515,11 +551,13 @@ static int max9286_set_pixelrate(struct max9286_priv *priv)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->pixelrate = pixelrate;
|
||||
|
||||
/*
|
||||
* The CSI-2 transmitter pixel rate is the single source rate multiplied
|
||||
* by the number of available sources.
|
||||
*/
|
||||
return v4l2_ctrl_s_ctrl_int64(priv->pixelrate,
|
||||
return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl,
|
||||
pixelrate * priv->nsources);
|
||||
}
|
||||
|
||||
|
@ -659,6 +697,8 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
int ret;
|
||||
|
||||
if (enable) {
|
||||
max9286_set_fsync_period(priv);
|
||||
|
||||
/*
|
||||
* The frame sync between cameras is transmitted across the
|
||||
* reverse channel as GPIO. We must open all channels while
|
||||
|
@ -718,6 +758,32 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int max9286_g_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *interval)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
|
||||
if (interval->pad != MAX9286_SRC_PAD)
|
||||
return -EINVAL;
|
||||
|
||||
interval->interval = priv->interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9286_s_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *interval)
|
||||
{
|
||||
struct max9286_priv *priv = sd_to_max9286(sd);
|
||||
|
||||
if (interval->pad != MAX9286_SRC_PAD)
|
||||
return -EINVAL;
|
||||
|
||||
priv->interval = interval->interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
|
@ -809,6 +875,8 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
|
|||
|
||||
static const struct v4l2_subdev_video_ops max9286_video_ops = {
|
||||
.s_stream = max9286_s_stream,
|
||||
.g_frame_interval = max9286_g_frame_interval,
|
||||
.s_frame_interval = max9286_s_frame_interval,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
|
||||
|
@ -893,10 +961,10 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
|
|||
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
v4l2_ctrl_handler_init(&priv->ctrls, 1);
|
||||
priv->pixelrate = v4l2_ctrl_new_std(&priv->ctrls,
|
||||
&max9286_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE,
|
||||
1, INT_MAX, 1, 50000000);
|
||||
priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls,
|
||||
&max9286_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE,
|
||||
1, INT_MAX, 1, 50000000);
|
||||
|
||||
priv->sd.ctrl_handler = &priv->ctrls;
|
||||
ret = priv->ctrls.error;
|
||||
|
@ -1006,9 +1074,7 @@ static int max9286_setup(struct max9286_priv *priv)
|
|||
MAX9286_CSILANECNT(priv->csi2_data_lanes) |
|
||||
MAX9286_DATATYPE_YUV422_8BIT);
|
||||
|
||||
/* Automatic: FRAMESYNC taken from the slowest Link. */
|
||||
max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ |
|
||||
MAX9286_FSYNCMETH_AUTO);
|
||||
max9286_set_fsync_period(priv);
|
||||
|
||||
/* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */
|
||||
max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS |
|
||||
|
|
Loading…
Reference in a new issue