blob: 469be87a3761feb5b775e4cf26aeac2600987f83 [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001/*
2 * Driver for Analog Devices ADV748X CSI-2 Transmitter
3 *
4 * 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.
10 */
11
12#include <linux/module.h>
13#include <linux/mutex.h>
14
15#include <media/v4l2-ctrls.h>
16#include <media/v4l2-device.h>
17#include <media/v4l2-ioctl.h>
18
19#include "adv748x.h"
20
21static bool is_txa(struct adv748x_csi2 *tx)
22{
23 return tx == &tx->state->txa;
24}
25
26static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
27 unsigned int vc)
28{
29 return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
30}
31
32/**
33 * adv748x_csi2_register_link : Register and link internal entities
34 *
35 * @tx: CSI2 private entity
36 * @v4l2_dev: Video registration device
37 * @src: Source subdevice to establish link
38 * @src_pad: Pad number of source to link to this @tx
39 *
40 * Ensure that the subdevice is registered against the v4l2_device, and link the
41 * source pad to the sink pad of the CSI2 bus entity.
42 */
43static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
44 struct v4l2_device *v4l2_dev,
45 struct v4l2_subdev *src,
46 unsigned int src_pad)
47{
48 int enabled = MEDIA_LNK_FL_ENABLED;
49 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;
56
57 if (!src->v4l2_dev) {
58 ret = v4l2_device_register_subdev(v4l2_dev, src);
59 if (ret)
60 return ret;
61 }
62
63 return media_create_pad_link(&src->entity, src_pad,
64 &tx->sd.entity, ADV748X_CSI2_SINK,
65 enabled);
66}
67
68/* -----------------------------------------------------------------------------
69 * v4l2_subdev_internal_ops
70 *
71 * We use the internal registered operation to be able to ensure that our
72 * incremental subdevices (not connected in the forward path) can be registered
73 * against the resulting video path and media device.
74 */
75
76static int adv748x_csi2_registered(struct v4l2_subdev *sd)
77{
78 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
79 struct adv748x_state *state = tx->state;
80
81 adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
82 sd->name);
83
84 /*
85 * The adv748x hardware allows the AFE to route through the TXA, however
86 * this is not currently supported in this driver.
87 *
88 * Link HDMI->TXA, and AFE->TXB directly.
89 */
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);
98 }
99}
100
101static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
102 .registered = adv748x_csi2_registered,
103};
104
105/* -----------------------------------------------------------------------------
106 * v4l2_subdev_video_ops
107 */
108
109static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable)
110{
111 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
112 struct v4l2_subdev *src;
113
114 src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]);
115 if (!src)
116 return -EPIPE;
117
118 return v4l2_subdev_call(src, video, s_stream, enable);
119}
120
121static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
122 .s_stream = adv748x_csi2_s_stream,
123};
124
125/* -----------------------------------------------------------------------------
126 * v4l2_subdev_pad_ops
127 *
128 * The CSI2 bus pads are ignorant to the data sizes or formats.
129 * But we must support setting the pad formats for format propagation.
130 */
131
132static struct v4l2_mbus_framefmt *
133adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
134 struct v4l2_subdev_pad_config *cfg,
135 unsigned int pad, u32 which)
136{
137 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
138
139 if (which == V4L2_SUBDEV_FORMAT_TRY)
140 return v4l2_subdev_get_try_format(sd, cfg, pad);
141
142 return &tx->format;
143}
144
145static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
146 struct v4l2_subdev_pad_config *cfg,
147 struct v4l2_subdev_format *sdformat)
148{
149 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
150 struct adv748x_state *state = tx->state;
151 struct v4l2_mbus_framefmt *mbusformat;
152
153 mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
154 sdformat->which);
155 if (!mbusformat)
156 return -EINVAL;
157
158 mutex_lock(&state->mutex);
159
160 sdformat->format = *mbusformat;
161
162 mutex_unlock(&state->mutex);
163
164 return 0;
165}
166
167static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
168 struct v4l2_subdev_pad_config *cfg,
169 struct v4l2_subdev_format *sdformat)
170{
171 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
172 struct adv748x_state *state = tx->state;
173 struct v4l2_mbus_framefmt *mbusformat;
174 int ret = 0;
175
176 mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
177 sdformat->which);
178 if (!mbusformat)
179 return -EINVAL;
180
181 mutex_lock(&state->mutex);
182
183 if (sdformat->pad == ADV748X_CSI2_SOURCE) {
184 const struct v4l2_mbus_framefmt *sink_fmt;
185
186 sink_fmt = adv748x_csi2_get_pad_format(sd, cfg,
187 ADV748X_CSI2_SINK,
188 sdformat->which);
189
190 if (!sink_fmt) {
191 ret = -EINVAL;
192 goto unlock;
193 }
194
195 sdformat->format = *sink_fmt;
196 }
197
198 *mbusformat = sdformat->format;
199
200unlock:
201 mutex_unlock(&state->mutex);
202
203 return ret;
204}
205
206static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
207 .get_fmt = adv748x_csi2_get_format,
208 .set_fmt = adv748x_csi2_set_format,
209};
210
211/* -----------------------------------------------------------------------------
212 * v4l2_subdev_ops
213 */
214
215static const struct v4l2_subdev_ops adv748x_csi2_ops = {
216 .video = &adv748x_csi2_video_ops,
217 .pad = &adv748x_csi2_pad_ops,
218};
219
220/* -----------------------------------------------------------------------------
221 * Subdev module and controls
222 */
223
224int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
225{
226 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
227
228 if (!tx->pixel_rate)
229 return -EINVAL;
230
231 return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
232}
233
234static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
235{
236 switch (ctrl->id) {
237 case V4L2_CID_PIXEL_RATE:
238 return 0;
239 default:
240 return -EINVAL;
241 }
242}
243
244static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
245 .s_ctrl = adv748x_csi2_s_ctrl,
246};
247
248static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
249{
250
251 v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
252
253 tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
254 &adv748x_csi2_ctrl_ops,
255 V4L2_CID_PIXEL_RATE, 1, INT_MAX,
256 1, 1);
257
258 tx->sd.ctrl_handler = &tx->ctrl_hdl;
259 if (tx->ctrl_hdl.error) {
260 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
261 return tx->ctrl_hdl.error;
262 }
263
264 return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
265}
266
267int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
268{
269 struct device_node *ep;
270 int ret;
271
272 /* We can not use container_of to get back to the state with two TXs */
273 tx->state = state;
274 tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB;
275
276 ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB];
277 if (!ep) {
278 adv_err(state, "No endpoint found for %s\n",
279 is_txa(tx) ? "txa" : "txb");
280 return -ENODEV;
281 }
282
283 /* Initialise the virtual channel */
284 adv748x_csi2_set_virtual_channel(tx, 0);
285
286 adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
287 MEDIA_ENT_F_VID_IF_BRIDGE,
288 is_txa(tx) ? "txa" : "txb");
289
290 /* Ensure that matching is based upon the endpoint fwnodes */
291 tx->sd.fwnode = of_fwnode_handle(ep);
292
293 /* Register internal ops for incremental subdev registration */
294 tx->sd.internal_ops = &adv748x_csi2_internal_ops;
295
296 tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
297 tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
298
299 ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
300 tx->pads);
301 if (ret)
302 return ret;
303
304 ret = adv748x_csi2_init_controls(tx);
305 if (ret)
306 goto err_free_media;
307
308 ret = v4l2_async_register_subdev(&tx->sd);
309 if (ret)
310 goto err_free_ctrl;
311
312 return 0;
313
314err_free_ctrl:
315 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
316err_free_media:
317 media_entity_cleanup(&tx->sd.entity);
318
319 return ret;
320}
321
322void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
323{
324 v4l2_async_unregister_subdev(&tx->sd);
325 media_entity_cleanup(&tx->sd.entity);
326 v4l2_ctrl_handler_free(&tx->ctrl_hdl);
327}