summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/adv748x
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/adv748x')
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c4
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c145
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c16
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h3
4 files changed, 106 insertions, 62 deletions
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 50d9fbadbe38..5edb3295dc58 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe,
{
memset(fmt, 0, sizeof(*fmt));
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->field = V4L2_FIELD_ALTERNATE;
@@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0;
}
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 5b265b722394..ebe7da8ebed7 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/mutex.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -14,6 +13,15 @@
#include "adv748x.h"
+static const unsigned int adv748x_csi2_txa_fmts[] = {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static const unsigned int adv748x_csi2_txb_fmts[] = {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+};
+
int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
{
return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
@@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
/* -----------------------------------------------------------------------------
* v4l2_subdev_internal_ops
- *
+ */
+
+static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ };
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK);
+ *fmt = adv748x_csi2_default_fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE);
+ *fmt = adv748x_csi2_default_fmt;
+
+ return 0;
+}
+
+/*
* We use the internal registered operation to be able to ensure that our
* incremental subdevices (not connected in the forward path) can be registered
* against the resulting video path and media device.
@@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
+ .init_state = adv748x_csi2_init_state,
.registered = adv748x_csi2_registered,
};
@@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
* But we must support setting the pad formats for format propagation.
*/
-static struct v4l2_mbus_framefmt *
-adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
+static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+ const unsigned int *codes = is_txa(tx) ?
+ adv748x_csi2_txa_fmts :
+ adv748x_csi2_txb_fmts;
+ size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
+ : ARRAY_SIZE(adv748x_csi2_txb_fmts);
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_state_get_format(sd_state, pad);
+ /*
+ * The format available on the source pad is the one applied on the sink
+ * pad.
+ */
+ if (code->pad == ADV748X_CSI2_SOURCE) {
+ struct v4l2_mbus_framefmt *fmt;
- return &tx->format;
-}
+ if (code->index)
+ return -EINVAL;
-static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
- struct v4l2_mbus_framefmt *mbusformat;
+ fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK);
+ code->code = fmt->code;
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
+ return 0;
+ }
+
+ if (code->index >= num_fmts)
return -EINVAL;
- mutex_lock(&state->mutex);
+ code->code = codes[code->index];
- sdformat->format = *mbusformat;
+ return 0;
+}
- mutex_unlock(&state->mutex);
+static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code)
+{
+ const unsigned int *codes = is_txa(tx) ?
+ adv748x_csi2_txa_fmts :
+ adv748x_csi2_txb_fmts;
+ size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
+ : ARRAY_SIZE(adv748x_csi2_txb_fmts);
+
+ for (unsigned int i = 0; i < num_fmts; i++) {
+ if (codes[i] == code)
+ return true;
+ }
- return 0;
+ return false;
}
static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
@@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
struct v4l2_mbus_framefmt *mbusformat;
- int ret = 0;
-
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
- return -EINVAL;
-
- mutex_lock(&state->mutex);
- if (sdformat->pad == ADV748X_CSI2_SOURCE) {
- const struct v4l2_mbus_framefmt *sink_fmt;
+ if (sdformat->pad == ADV748X_CSI2_SOURCE)
+ return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
- sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
- ADV748X_CSI2_SINK,
- sdformat->which);
-
- if (!sink_fmt) {
- ret = -EINVAL;
- goto unlock;
- }
-
- sdformat->format = *sink_fmt;
- }
+ /*
+ * Make sure the format is supported, if not default it to
+ * UYVY8 as it's supported by both TXes.
+ */
+ if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code))
+ sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
+ mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*mbusformat = sdformat->format;
-unlock:
- mutex_unlock(&state->mutex);
+ /* Propagate format to the source pad. */
+ mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE);
+ *mbusformat = sdformat->format;
- return ret;
+ return 0;
}
static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
@@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
}
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
- .get_fmt = adv748x_csi2_get_format,
+ .enum_mbus_code = adv748x_csi2_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
};
@@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
if (ret)
goto err_cleanup_subdev;
+ tx->sd.state_lock = &state->mutex;
+ ret = v4l2_subdev_init_finalize(&tx->sd);
+ if (ret)
+ goto err_free_ctrl;
+
ret = v4l2_async_register_subdev(&tx->sd);
if (ret)
goto err_free_ctrl;
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index ec151dc69c23..a4db9bae5f79 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -214,7 +214,7 @@ static int adv748x_hdmi_set_video_timings(struct adv748x_state *state,
* v4l2_subdev_video_ops
*/
-static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd,
+static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_dv_timings *timings)
{
struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -254,7 +254,7 @@ error:
return ret;
}
-static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd,
+static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_dv_timings *timings)
{
struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -269,7 +269,7 @@ static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd,
return 0;
}
-static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd,
+static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_dv_timings *timings)
{
struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -392,9 +392,6 @@ static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = {
- .s_dv_timings = adv748x_hdmi_s_dv_timings,
- .g_dv_timings = adv748x_hdmi_g_dv_timings,
- .query_dv_timings = adv748x_hdmi_query_dv_timings,
.g_input_status = adv748x_hdmi_g_input_status,
.s_stream = adv748x_hdmi_s_stream,
.g_pixelaspect = adv748x_hdmi_g_pixelaspect,
@@ -413,7 +410,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
if (!tx)
return -ENOLINK;
- adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings);
+ adv748x_hdmi_query_dv_timings(&hdmi->sd, 0, &timings);
return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock);
}
@@ -610,6 +607,9 @@ static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi = {
.get_fmt = adv748x_hdmi_get_format,
.get_edid = adv748x_hdmi_get_edid,
.set_edid = adv748x_hdmi_set_edid,
+ .s_dv_timings = adv748x_hdmi_s_dv_timings,
+ .g_dv_timings = adv748x_hdmi_g_dv_timings,
+ .query_dv_timings = adv748x_hdmi_query_dv_timings,
.dv_timings_cap = adv748x_hdmi_dv_timings_cap,
.enum_dv_timings = adv748x_hdmi_enum_dv_timings,
};
@@ -734,7 +734,7 @@ int adv748x_hdmi_init(struct adv748x_hdmi *hdmi)
struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30;
int ret;
- adv748x_hdmi_s_dv_timings(&hdmi->sd, &cea1280x720);
+ adv748x_hdmi_s_dv_timings(&hdmi->sd, 0, &cea1280x720);
/* Initialise a default 16:9 aspect ratio */
hdmi->aspect_ratio.numerator = 16;
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index d2b5e722e997..2c1db5968af8 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -75,7 +75,6 @@ enum adv748x_csi2_pads {
struct adv748x_csi2 {
struct adv748x_state *state;
- struct v4l2_mbus_framefmt format;
unsigned int page;
unsigned int port;
unsigned int num_lanes;
@@ -321,7 +320,7 @@ struct adv748x_state {
/* Free run pattern select */
#define ADV748X_SDP_FRP 0x14
-#define ADV748X_SDP_FRP_MASK GENMASK(3, 1)
+#define ADV748X_SDP_FRP_MASK GENMASK(2, 0)
/* Saturation */
#define ADV748X_SDP_SD_SAT_U 0xe3 /* user_map_rw_reg_e3 */