• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for Analog Devices ADV748X CSI-2 Transmitter
4  *
5  * Copyright (C) 2017 Renesas Electronics Corp.
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 
adv748x_csi2_set_virtual_channel(struct adv748x_csi2 * tx,unsigned int vc)17 static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
18 					    unsigned int vc)
19 {
20 	return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
21 }
22 
23 /**
24  * adv748x_csi2_register_link : Register and link internal entities
25  *
26  * @tx: CSI2 private entity
27  * @v4l2_dev: Video registration device
28  * @src: Source subdevice to establish link
29  * @src_pad: Pad number of source to link to this @tx
30  * @enable: Link enabled flag
31  *
32  * Ensure that the subdevice is registered against the v4l2_device, and link the
33  * source pad to the sink pad of the CSI2 bus entity.
34  */
adv748x_csi2_register_link(struct adv748x_csi2 * tx,struct v4l2_device * v4l2_dev,struct v4l2_subdev * src,unsigned int src_pad,bool enable)35 static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
36 				      struct v4l2_device *v4l2_dev,
37 				      struct v4l2_subdev *src,
38 				      unsigned int src_pad,
39 				      bool enable)
40 {
41 	int ret;
42 
43 	if (!src->v4l2_dev) {
44 		ret = v4l2_device_register_subdev(v4l2_dev, src);
45 		if (ret)
46 			return ret;
47 	}
48 
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;
59 }
60 
61 /* -----------------------------------------------------------------------------
62  * v4l2_subdev_internal_ops
63  *
64  * We use the internal registered operation to be able to ensure that our
65  * incremental subdevices (not connected in the forward path) can be registered
66  * against the resulting video path and media device.
67  */
68 
adv748x_csi2_registered(struct v4l2_subdev * sd)69 static int adv748x_csi2_registered(struct v4l2_subdev *sd)
70 {
71 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
72 	struct adv748x_state *state = tx->state;
73 	int ret;
74 
75 	adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
76 			sd->name);
77 
78 	/*
79 	 * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output
80 	 * HDMI.
81 	 *
82 	 * The HDMI->TXA link is enabled by default, as is the AFE->TXB one.
83 	 */
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;
95 	}
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;
110 }
111 
112 static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
113 	.registered = adv748x_csi2_registered,
114 };
115 
116 /* -----------------------------------------------------------------------------
117  * v4l2_subdev_video_ops
118  */
119 
adv748x_csi2_s_stream(struct v4l2_subdev * sd,int enable)120 static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable)
121 {
122 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
123 	struct v4l2_subdev *src;
124 
125 	src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]);
126 	if (!src)
127 		return -EPIPE;
128 
129 	return v4l2_subdev_call(src, video, s_stream, enable);
130 }
131 
132 static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
133 	.s_stream = adv748x_csi2_s_stream,
134 };
135 
136 /* -----------------------------------------------------------------------------
137  * v4l2_subdev_pad_ops
138  *
139  * The CSI2 bus pads are ignorant to the data sizes or formats.
140  * But we must support setting the pad formats for format propagation.
141  */
142 
143 static struct v4l2_mbus_framefmt *
adv748x_csi2_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,unsigned int pad,u32 which)144 adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
145 			    struct v4l2_subdev_pad_config *cfg,
146 			    unsigned int pad, u32 which)
147 {
148 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
149 
150 	if (which == V4L2_SUBDEV_FORMAT_TRY)
151 		return v4l2_subdev_get_try_format(sd, cfg, pad);
152 
153 	return &tx->format;
154 }
155 
adv748x_csi2_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * sdformat)156 static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
157 				   struct v4l2_subdev_pad_config *cfg,
158 				   struct v4l2_subdev_format *sdformat)
159 {
160 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
161 	struct adv748x_state *state = tx->state;
162 	struct v4l2_mbus_framefmt *mbusformat;
163 
164 	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
165 						 sdformat->which);
166 	if (!mbusformat)
167 		return -EINVAL;
168 
169 	mutex_lock(&state->mutex);
170 
171 	sdformat->format = *mbusformat;
172 
173 	mutex_unlock(&state->mutex);
174 
175 	return 0;
176 }
177 
adv748x_csi2_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * sdformat)178 static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
179 				   struct v4l2_subdev_pad_config *cfg,
180 				   struct v4l2_subdev_format *sdformat)
181 {
182 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
183 	struct adv748x_state *state = tx->state;
184 	struct v4l2_mbus_framefmt *mbusformat;
185 	int ret = 0;
186 
187 	mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
188 						 sdformat->which);
189 	if (!mbusformat)
190 		return -EINVAL;
191 
192 	mutex_lock(&state->mutex);
193 
194 	if (sdformat->pad == ADV748X_CSI2_SOURCE) {
195 		const struct v4l2_mbus_framefmt *sink_fmt;
196 
197 		sink_fmt = adv748x_csi2_get_pad_format(sd, cfg,
198 						       ADV748X_CSI2_SINK,
199 						       sdformat->which);
200 
201 		if (!sink_fmt) {
202 			ret = -EINVAL;
203 			goto unlock;
204 		}
205 
206 		sdformat->format = *sink_fmt;
207 	}
208 
209 	*mbusformat = sdformat->format;
210 
211 unlock:
212 	mutex_unlock(&state->mutex);
213 
214 	return ret;
215 }
216 
adv748x_csi2_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * config)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 
247 static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
248 	.get_fmt = adv748x_csi2_get_format,
249 	.set_fmt = adv748x_csi2_set_format,
250 	.get_mbus_config = adv748x_csi2_get_mbus_config,
251 };
252 
253 /* -----------------------------------------------------------------------------
254  * v4l2_subdev_ops
255  */
256 
257 static const struct v4l2_subdev_ops adv748x_csi2_ops = {
258 	.video = &adv748x_csi2_video_ops,
259 	.pad = &adv748x_csi2_pad_ops,
260 };
261 
262 /* -----------------------------------------------------------------------------
263  * Subdev module and controls
264  */
265 
adv748x_csi2_set_pixelrate(struct v4l2_subdev * sd,s64 rate)266 int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
267 {
268 	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
269 
270 	if (!tx->pixel_rate)
271 		return -EINVAL;
272 
273 	return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
274 }
275 
adv748x_csi2_s_ctrl(struct v4l2_ctrl * ctrl)276 static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
277 {
278 	switch (ctrl->id) {
279 	case V4L2_CID_PIXEL_RATE:
280 		return 0;
281 	default:
282 		return -EINVAL;
283 	}
284 }
285 
286 static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
287 	.s_ctrl = adv748x_csi2_s_ctrl,
288 };
289 
adv748x_csi2_init_controls(struct adv748x_csi2 * tx)290 static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
291 {
292 
293 	v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
294 
295 	tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
296 					   &adv748x_csi2_ctrl_ops,
297 					   V4L2_CID_PIXEL_RATE, 1, INT_MAX,
298 					   1, 1);
299 
300 	tx->sd.ctrl_handler = &tx->ctrl_hdl;
301 	if (tx->ctrl_hdl.error) {
302 		v4l2_ctrl_handler_free(&tx->ctrl_hdl);
303 		return tx->ctrl_hdl.error;
304 	}
305 
306 	return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
307 }
308 
adv748x_csi2_init(struct adv748x_state * state,struct adv748x_csi2 * tx)309 int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
310 {
311 	int ret;
312 
313 	if (!is_tx_enabled(tx))
314 		return 0;
315 
316 	/* Initialise the virtual channel */
317 	adv748x_csi2_set_virtual_channel(tx, 0);
318 
319 	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
320 			    MEDIA_ENT_F_VID_IF_BRIDGE,
321 			    is_txa(tx) ? "txa" : "txb");
322 
323 	/* Ensure that matching is based upon the endpoint fwnodes */
324 	tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
325 
326 	/* Register internal ops for incremental subdev registration */
327 	tx->sd.internal_ops = &adv748x_csi2_internal_ops;
328 
329 	tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
330 	tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
331 
332 	ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
333 				     tx->pads);
334 	if (ret)
335 		return ret;
336 
337 	ret = adv748x_csi2_init_controls(tx);
338 	if (ret)
339 		goto err_free_media;
340 
341 	ret = v4l2_async_register_subdev(&tx->sd);
342 	if (ret)
343 		goto err_free_ctrl;
344 
345 	return 0;
346 
347 err_free_ctrl:
348 	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
349 err_free_media:
350 	media_entity_cleanup(&tx->sd.entity);
351 
352 	return ret;
353 }
354 
adv748x_csi2_cleanup(struct adv748x_csi2 * tx)355 void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
356 {
357 	if (!is_tx_enabled(tx))
358 		return;
359 
360 	v4l2_async_unregister_subdev(&tx->sd);
361 	media_entity_cleanup(&tx->sd.entity);
362 	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
363 }
364