1
2
3
4
5
6
7
8#include <linux/module.h>
9#include <linux/mutex.h>
10
11#include <media/v4l2-ctrls.h>
12#include <media/v4l2-device.h>
13#include <media/v4l2-ioctl.h>
14
15#include "adv748x.h"
16
17int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
18{
19 return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
20}
21
22
23
24
25
26
27
28
29
30
31
32
33
34static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
35 struct v4l2_device *v4l2_dev,
36 struct v4l2_subdev *src,
37 unsigned int src_pad,
38 bool enable)
39{
40 int ret;
41
42 if (!src->v4l2_dev) {
43 ret = v4l2_device_register_subdev(v4l2_dev, src);
44 if (ret)
45 return ret;
46 }
47
48 ret = media_create_pad_link(&src->entity, src_pad,
49 &tx->sd.entity, ADV748X_CSI2_SINK,
50 enable ? MEDIA_LNK_FL_ENABLED : 0);
51 if (ret)
52 return ret;
53
54 if (enable)
55 tx->src = src;
56
57 return 0;
58}
59
60
61
62
63
64
65
66
67
68static int adv748x_csi2_registered(struct v4l2_subdev *sd)
69{
70 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
71 struct adv748x_state *state = tx->state;
72 int ret;
73
74 adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
75 sd->name);
76
77
78
79
80
81
82
83 if (is_afe_enabled(state)) {
84 ret = adv748x_csi2_register_link(tx, sd->v4l2_dev,
85 &state->afe.sd,
86 ADV748X_AFE_SOURCE,
87 is_txb(tx));
88 if (ret)
89 return ret;
90
91
92 if (is_txb(tx))
93 state->afe.tx = tx;
94 }
95
96
97 if (is_txb(tx) || !is_hdmi_enabled(state))
98 return 0;
99
100 ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd,
101 ADV748X_HDMI_SOURCE, true);
102 if (ret)
103 return ret;
104
105
106 state->hdmi.tx = tx;
107
108 return 0;
109}
110
111static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
112 .registered = adv748x_csi2_registered,
113};
114
115
116
117
118
119static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable)
120{
121 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
122 struct v4l2_subdev *src;
123
124 src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]);
125 if (!src)
126 return -EPIPE;
127
128 return v4l2_subdev_call(src, video, s_stream, enable);
129}
130
131static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
132 .s_stream = adv748x_csi2_s_stream,
133};
134
135
136
137
138
139
140
141
142static struct v4l2_mbus_framefmt *
143adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
144 struct v4l2_subdev_state *sd_state,
145 unsigned int pad, u32 which)
146{
147 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
148
149 if (which == V4L2_SUBDEV_FORMAT_TRY)
150 return v4l2_subdev_get_try_format(sd, sd_state, pad);
151
152 return &tx->format;
153}
154
155static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
156 struct v4l2_subdev_state *sd_state,
157 struct v4l2_subdev_format *sdformat)
158{
159 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
160 struct adv748x_state *state = tx->state;
161 struct v4l2_mbus_framefmt *mbusformat;
162
163 mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
164 sdformat->which);
165 if (!mbusformat)
166 return -EINVAL;
167
168 mutex_lock(&state->mutex);
169
170 sdformat->format = *mbusformat;
171
172 mutex_unlock(&state->mutex);
173
174 return 0;
175}
176
177static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
178 struct v4l2_subdev_state *sd_state,
179 struct v4l2_subdev_format *sdformat)
180{
181 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
182 struct adv748x_state *state = tx->state;
183 struct v4l2_mbus_framefmt *mbusformat;
184 int ret = 0;
185
186 mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
187 sdformat->which);
188 if (!mbusformat)
189 return -EINVAL;
190
191 mutex_lock(&state->mutex);
192
193 if (sdformat->pad == ADV748X_CSI2_SOURCE) {
194 const struct v4l2_mbus_framefmt *sink_fmt;
195
196 sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
197 ADV748X_CSI2_SINK,
198 sdformat->which);
199
200 if (!sink_fmt) {
201 ret = -EINVAL;
202 goto unlock;
203 }
204
205 sdformat->format = *sink_fmt;
206 }
207
208 *mbusformat = sdformat->format;
209
210unlock:
211 mutex_unlock(&state->mutex);
212
213 return ret;
214}
215
216static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
217 struct v4l2_mbus_config *config)
218{
219 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
220
221 if (pad != ADV748X_CSI2_SOURCE)
222 return -EINVAL;
223
224 config->type = V4L2_MBUS_CSI2_DPHY;
225 switch (tx->active_lanes) {
226 case 1:
227 config->flags = V4L2_MBUS_CSI2_1_LANE;
228 break;
229
230 case 2:
231 config->flags = V4L2_MBUS_CSI2_2_LANE;
232 break;
233
234 case 3:
235 config->flags = V4L2_MBUS_CSI2_3_LANE;
236 break;
237
238 case 4:
239 config->flags = V4L2_MBUS_CSI2_4_LANE;
240 break;
241 }
242
243 return 0;
244}
245
246static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
247 .get_fmt = adv748x_csi2_get_format,
248 .set_fmt = adv748x_csi2_set_format,
249 .get_mbus_config = adv748x_csi2_get_mbus_config,
250};
251
252
253
254
255
256static const struct v4l2_subdev_ops adv748x_csi2_ops = {
257 .video = &adv748x_csi2_video_ops,
258 .pad = &adv748x_csi2_pad_ops,
259};
260
261
262
263
264
265int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
266{
267 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
268
269 if (!tx->pixel_rate)
270 return -EINVAL;
271
272 return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
273}
274
275static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
276{
277 switch (ctrl->id) {
278 case V4L2_CID_PIXEL_RATE:
279 return 0;
280 default:
281 return -EINVAL;
282 }
283}
284
285static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
286 .s_ctrl = adv748x_csi2_s_ctrl,
287};
288
289static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
290{
291
292 v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
293
294 tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
295 &adv748x_csi2_ctrl_ops,
296 V4L2_CID_PIXEL_RATE, 1, INT_MAX,
297 1, 1);
298
299 tx->sd.ctrl_handler = &tx->ctrl_hdl;
300 if (tx->ctrl_hdl.error) {
301 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
302 return tx->ctrl_hdl.error;
303 }
304
305 return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
306}
307
308int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
309{
310 int ret;
311
312 if (!is_tx_enabled(tx))
313 return 0;
314
315 adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
316 MEDIA_ENT_F_VID_IF_BRIDGE,
317 is_txa(tx) ? "txa" : "txb");
318
319
320 tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
321
322
323 tx->sd.internal_ops = &adv748x_csi2_internal_ops;
324
325 tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
326 tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
327
328 ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
329 tx->pads);
330 if (ret)
331 return ret;
332
333 ret = adv748x_csi2_init_controls(tx);
334 if (ret)
335 goto err_free_media;
336
337 ret = v4l2_async_register_subdev(&tx->sd);
338 if (ret)
339 goto err_free_ctrl;
340
341 return 0;
342
343err_free_ctrl:
344 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
345err_free_media:
346 media_entity_cleanup(&tx->sd.entity);
347
348 return ret;
349}
350
351void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
352{
353 if (!is_tx_enabled(tx))
354 return;
355
356 v4l2_async_unregister_subdev(&tx->sd);
357 media_entity_cleanup(&tx->sd.entity);
358 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
359}
360