hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/drivers/media/i2c/adv748x/adv748x-csi2.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Driver for Analog Devices ADV748X CSI-2 Transmitter
34 *
45 * Copyright (C) 2017 Renesas Electronics Corp.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the
8
- * Free Software Foundation; either version 2 of the License, or (at your
9
- * option) any later version.
106 */
117
128 #include <linux/module.h>
....@@ -17,11 +13,6 @@
1713 #include <media/v4l2-ioctl.h>
1814
1915 #include "adv748x.h"
20
-
21
-static bool is_txa(struct adv748x_csi2 *tx)
22
-{
23
- return tx == &tx->state->txa;
24
-}
2516
2617 static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
2718 unsigned int vc)
....@@ -36,6 +27,7 @@
3627 * @v4l2_dev: Video registration device
3728 * @src: Source subdevice to establish link
3829 * @src_pad: Pad number of source to link to this @tx
30
+ * @enable: Link enabled flag
3931 *
4032 * Ensure that the subdevice is registered against the v4l2_device, and link the
4133 * source pad to the sink pad of the CSI2 bus entity.
....@@ -43,16 +35,10 @@
4335 static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
4436 struct v4l2_device *v4l2_dev,
4537 struct v4l2_subdev *src,
46
- unsigned int src_pad)
38
+ unsigned int src_pad,
39
+ bool enable)
4740 {
48
- int enabled = MEDIA_LNK_FL_ENABLED;
4941 int ret;
50
-
51
- /*
52
- * Dynamic linking of the AFE is not supported.
53
- * Register the links as immutable.
54
- */
55
- enabled |= MEDIA_LNK_FL_IMMUTABLE;
5642
5743 if (!src->v4l2_dev) {
5844 ret = v4l2_device_register_subdev(v4l2_dev, src);
....@@ -60,9 +46,16 @@
6046 return ret;
6147 }
6248
63
- return media_create_pad_link(&src->entity, src_pad,
64
- &tx->sd.entity, ADV748X_CSI2_SINK,
65
- enabled);
49
+ ret = media_create_pad_link(&src->entity, src_pad,
50
+ &tx->sd.entity, ADV748X_CSI2_SINK,
51
+ enable ? MEDIA_LNK_FL_ENABLED : 0);
52
+ if (ret)
53
+ return ret;
54
+
55
+ if (enable)
56
+ tx->src = src;
57
+
58
+ return 0;
6659 }
6760
6861 /* -----------------------------------------------------------------------------
....@@ -77,25 +70,43 @@
7770 {
7871 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
7972 struct adv748x_state *state = tx->state;
73
+ int ret;
8074
8175 adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
8276 sd->name);
8377
8478 /*
85
- * The adv748x hardware allows the AFE to route through the TXA, however
86
- * this is not currently supported in this driver.
79
+ * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output
80
+ * HDMI.
8781 *
88
- * Link HDMI->TXA, and AFE->TXB directly.
82
+ * The HDMI->TXA link is enabled by default, as is the AFE->TXB one.
8983 */
90
- if (is_txa(tx)) {
91
- return adv748x_csi2_register_link(tx, sd->v4l2_dev,
92
- &state->hdmi.sd,
93
- ADV748X_HDMI_SOURCE);
94
- } else {
95
- return adv748x_csi2_register_link(tx, sd->v4l2_dev,
96
- &state->afe.sd,
97
- ADV748X_AFE_SOURCE);
84
+ if (is_afe_enabled(state)) {
85
+ ret = adv748x_csi2_register_link(tx, sd->v4l2_dev,
86
+ &state->afe.sd,
87
+ ADV748X_AFE_SOURCE,
88
+ is_txb(tx));
89
+ if (ret)
90
+ return ret;
91
+
92
+ /* TXB can output AFE signals only. */
93
+ if (is_txb(tx))
94
+ state->afe.tx = tx;
9895 }
96
+
97
+ /* Register link to HDMI for TXA only. */
98
+ if (is_txb(tx) || !is_hdmi_enabled(state))
99
+ return 0;
100
+
101
+ ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd,
102
+ ADV748X_HDMI_SOURCE, true);
103
+ if (ret)
104
+ return ret;
105
+
106
+ /* The default HDMI output is TXA. */
107
+ state->hdmi.tx = tx;
108
+
109
+ return 0;
99110 }
100111
101112 static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
....@@ -203,9 +214,40 @@
203214 return ret;
204215 }
205216
217
+static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
218
+ struct v4l2_mbus_config *config)
219
+{
220
+ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
221
+
222
+ if (pad != ADV748X_CSI2_SOURCE)
223
+ return -EINVAL;
224
+
225
+ config->type = V4L2_MBUS_CSI2_DPHY;
226
+ switch (tx->active_lanes) {
227
+ case 1:
228
+ config->flags = V4L2_MBUS_CSI2_1_LANE;
229
+ break;
230
+
231
+ case 2:
232
+ config->flags = V4L2_MBUS_CSI2_2_LANE;
233
+ break;
234
+
235
+ case 3:
236
+ config->flags = V4L2_MBUS_CSI2_3_LANE;
237
+ break;
238
+
239
+ case 4:
240
+ config->flags = V4L2_MBUS_CSI2_4_LANE;
241
+ break;
242
+ }
243
+
244
+ return 0;
245
+}
246
+
206247 static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
207248 .get_fmt = adv748x_csi2_get_format,
208249 .set_fmt = adv748x_csi2_set_format,
250
+ .get_mbus_config = adv748x_csi2_get_mbus_config,
209251 };
210252
211253 /* -----------------------------------------------------------------------------