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