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
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 * adv748x_csi2_register_link : Register and link internal entities
24 *
25 * @tx: CSI2 private entity
26 * @v4l2_dev: Video registration device
27 * @src: Source subdevice to establish link
28 * @src_pad: Pad number of source to link to this @tx
29 * @enable: Link enabled flag
30 *
31 * Ensure that the subdevice is registered against the v4l2_device, and link the
32 * source pad to the sink pad of the CSI2 bus entity.
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 * v4l2_subdev_internal_ops
62 *
63 * We use the internal registered operation to be able to ensure that our
64 * incremental subdevices (not connected in the forward path) can be registered
65 * against the resulting video path and media device.
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	 * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output
79	 * HDMI.
80	 *
81	 * The HDMI->TXA link is enabled by default, as is the AFE->TXB one.
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		/* TXB can output AFE signals only. */
92		if (is_txb(tx))
93			state->afe.tx = tx;
94	}
95
96	/* Register link to HDMI for TXA only. */
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	/* The default HDMI output is TXA. */
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 * v4l2_subdev_video_ops
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 * v4l2_subdev_pad_ops
137 *
138 * The CSI2 bus pads are ignorant to the data sizes or formats.
139 * But we must support setting the pad formats for format propagation.
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_state_get_format(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	config->bus.mipi_csi2.num_data_lanes = tx->active_lanes;
226
227	return 0;
228}
229
230static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
231	.get_fmt = adv748x_csi2_get_format,
232	.set_fmt = adv748x_csi2_set_format,
233	.get_mbus_config = adv748x_csi2_get_mbus_config,
234};
235
236/* -----------------------------------------------------------------------------
237 * v4l2_subdev_ops
238 */
239
240static const struct v4l2_subdev_ops adv748x_csi2_ops = {
241	.video = &adv748x_csi2_video_ops,
242	.pad = &adv748x_csi2_pad_ops,
243};
244
245/* -----------------------------------------------------------------------------
246 * Subdev module and controls
247 */
248
249int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
250{
251	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
252
253	if (!tx->pixel_rate)
254		return -EINVAL;
255
256	return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
257}
258
259static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
260{
261	switch (ctrl->id) {
262	case V4L2_CID_PIXEL_RATE:
263		return 0;
264	default:
265		return -EINVAL;
266	}
267}
268
269static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
270	.s_ctrl = adv748x_csi2_s_ctrl,
271};
272
273static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
274{
275
276	v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
277
278	tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
279					   &adv748x_csi2_ctrl_ops,
280					   V4L2_CID_PIXEL_RATE, 1, INT_MAX,
281					   1, 1);
282
283	tx->sd.ctrl_handler = &tx->ctrl_hdl;
284	if (tx->ctrl_hdl.error) {
285		v4l2_ctrl_handler_free(&tx->ctrl_hdl);
286		return tx->ctrl_hdl.error;
287	}
288
289	return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
290}
291
292int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
293{
294	int ret;
295
296	if (!is_tx_enabled(tx))
297		return 0;
298
299	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
300			    MEDIA_ENT_F_VID_IF_BRIDGE,
301			    is_txa(tx) ? "txa" : "txb");
302
303	/* Register internal ops for incremental subdev registration */
304	tx->sd.internal_ops = &adv748x_csi2_internal_ops;
305
306	tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
307	tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
308
309	ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
310				     tx->pads);
311	if (ret)
312		return ret;
313
314	ret = v4l2_async_subdev_endpoint_add(&tx->sd,
315					     of_fwnode_handle(state->endpoints[tx->port]));
316	if (ret)
317		goto err_free_media;
318
319	ret = adv748x_csi2_init_controls(tx);
320	if (ret)
321		goto err_cleanup_subdev;
322
323	ret = v4l2_async_register_subdev(&tx->sd);
324	if (ret)
325		goto err_free_ctrl;
326
327	return 0;
328
329err_free_ctrl:
330	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
331err_cleanup_subdev:
332	v4l2_subdev_cleanup(&tx->sd);
333err_free_media:
334	media_entity_cleanup(&tx->sd.entity);
335
336	return ret;
337}
338
339void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
340{
341	if (!is_tx_enabled(tx))
342		return;
343
344	v4l2_async_unregister_subdev(&tx->sd);
345	media_entity_cleanup(&tx->sd.entity);
346	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
347	v4l2_subdev_cleanup(&tx->sd);
348}
349