Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Driver for Analog Devices ADV748X CSI-2 Transmitter
0004  *
0005  * Copyright (C) 2017 Renesas Electronics Corp.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/mutex.h>
0010 
0011 #include <media/v4l2-ctrls.h>
0012 #include <media/v4l2-device.h>
0013 #include <media/v4l2-ioctl.h>
0014 
0015 #include "adv748x.h"
0016 
0017 int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
0018 {
0019     return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
0020 }
0021 
0022 /**
0023  * adv748x_csi2_register_link : Register and link internal entities
0024  *
0025  * @tx: CSI2 private entity
0026  * @v4l2_dev: Video registration device
0027  * @src: Source subdevice to establish link
0028  * @src_pad: Pad number of source to link to this @tx
0029  * @enable: Link enabled flag
0030  *
0031  * Ensure that the subdevice is registered against the v4l2_device, and link the
0032  * source pad to the sink pad of the CSI2 bus entity.
0033  */
0034 static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
0035                       struct v4l2_device *v4l2_dev,
0036                       struct v4l2_subdev *src,
0037                       unsigned int src_pad,
0038                       bool enable)
0039 {
0040     int ret;
0041 
0042     if (!src->v4l2_dev) {
0043         ret = v4l2_device_register_subdev(v4l2_dev, src);
0044         if (ret)
0045             return ret;
0046     }
0047 
0048     ret = media_create_pad_link(&src->entity, src_pad,
0049                     &tx->sd.entity, ADV748X_CSI2_SINK,
0050                     enable ? MEDIA_LNK_FL_ENABLED : 0);
0051     if (ret)
0052         return ret;
0053 
0054     if (enable)
0055         tx->src = src;
0056 
0057     return 0;
0058 }
0059 
0060 /* -----------------------------------------------------------------------------
0061  * v4l2_subdev_internal_ops
0062  *
0063  * We use the internal registered operation to be able to ensure that our
0064  * incremental subdevices (not connected in the forward path) can be registered
0065  * against the resulting video path and media device.
0066  */
0067 
0068 static int adv748x_csi2_registered(struct v4l2_subdev *sd)
0069 {
0070     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0071     struct adv748x_state *state = tx->state;
0072     int ret;
0073 
0074     adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
0075             sd->name);
0076 
0077     /*
0078      * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output
0079      * HDMI.
0080      *
0081      * The HDMI->TXA link is enabled by default, as is the AFE->TXB one.
0082      */
0083     if (is_afe_enabled(state)) {
0084         ret = adv748x_csi2_register_link(tx, sd->v4l2_dev,
0085                          &state->afe.sd,
0086                          ADV748X_AFE_SOURCE,
0087                          is_txb(tx));
0088         if (ret)
0089             return ret;
0090 
0091         /* TXB can output AFE signals only. */
0092         if (is_txb(tx))
0093             state->afe.tx = tx;
0094     }
0095 
0096     /* Register link to HDMI for TXA only. */
0097     if (is_txb(tx) || !is_hdmi_enabled(state))
0098         return 0;
0099 
0100     ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd,
0101                      ADV748X_HDMI_SOURCE, true);
0102     if (ret)
0103         return ret;
0104 
0105     /* The default HDMI output is TXA. */
0106     state->hdmi.tx = tx;
0107 
0108     return 0;
0109 }
0110 
0111 static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
0112     .registered = adv748x_csi2_registered,
0113 };
0114 
0115 /* -----------------------------------------------------------------------------
0116  * v4l2_subdev_video_ops
0117  */
0118 
0119 static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable)
0120 {
0121     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0122     struct v4l2_subdev *src;
0123 
0124     src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]);
0125     if (!src)
0126         return -EPIPE;
0127 
0128     return v4l2_subdev_call(src, video, s_stream, enable);
0129 }
0130 
0131 static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
0132     .s_stream = adv748x_csi2_s_stream,
0133 };
0134 
0135 /* -----------------------------------------------------------------------------
0136  * v4l2_subdev_pad_ops
0137  *
0138  * The CSI2 bus pads are ignorant to the data sizes or formats.
0139  * But we must support setting the pad formats for format propagation.
0140  */
0141 
0142 static struct v4l2_mbus_framefmt *
0143 adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
0144                 struct v4l2_subdev_state *sd_state,
0145                 unsigned int pad, u32 which)
0146 {
0147     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0148 
0149     if (which == V4L2_SUBDEV_FORMAT_TRY)
0150         return v4l2_subdev_get_try_format(sd, sd_state, pad);
0151 
0152     return &tx->format;
0153 }
0154 
0155 static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
0156                    struct v4l2_subdev_state *sd_state,
0157                    struct v4l2_subdev_format *sdformat)
0158 {
0159     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0160     struct adv748x_state *state = tx->state;
0161     struct v4l2_mbus_framefmt *mbusformat;
0162 
0163     mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
0164                          sdformat->which);
0165     if (!mbusformat)
0166         return -EINVAL;
0167 
0168     mutex_lock(&state->mutex);
0169 
0170     sdformat->format = *mbusformat;
0171 
0172     mutex_unlock(&state->mutex);
0173 
0174     return 0;
0175 }
0176 
0177 static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
0178                    struct v4l2_subdev_state *sd_state,
0179                    struct v4l2_subdev_format *sdformat)
0180 {
0181     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0182     struct adv748x_state *state = tx->state;
0183     struct v4l2_mbus_framefmt *mbusformat;
0184     int ret = 0;
0185 
0186     mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
0187                          sdformat->which);
0188     if (!mbusformat)
0189         return -EINVAL;
0190 
0191     mutex_lock(&state->mutex);
0192 
0193     if (sdformat->pad == ADV748X_CSI2_SOURCE) {
0194         const struct v4l2_mbus_framefmt *sink_fmt;
0195 
0196         sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
0197                                ADV748X_CSI2_SINK,
0198                                sdformat->which);
0199 
0200         if (!sink_fmt) {
0201             ret = -EINVAL;
0202             goto unlock;
0203         }
0204 
0205         sdformat->format = *sink_fmt;
0206     }
0207 
0208     *mbusformat = sdformat->format;
0209 
0210 unlock:
0211     mutex_unlock(&state->mutex);
0212 
0213     return ret;
0214 }
0215 
0216 static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
0217                     struct v4l2_mbus_config *config)
0218 {
0219     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0220 
0221     if (pad != ADV748X_CSI2_SOURCE)
0222         return -EINVAL;
0223 
0224     config->type = V4L2_MBUS_CSI2_DPHY;
0225     config->bus.mipi_csi2.num_data_lanes = tx->active_lanes;
0226 
0227     return 0;
0228 }
0229 
0230 static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
0231     .get_fmt = adv748x_csi2_get_format,
0232     .set_fmt = adv748x_csi2_set_format,
0233     .get_mbus_config = adv748x_csi2_get_mbus_config,
0234 };
0235 
0236 /* -----------------------------------------------------------------------------
0237  * v4l2_subdev_ops
0238  */
0239 
0240 static const struct v4l2_subdev_ops adv748x_csi2_ops = {
0241     .video = &adv748x_csi2_video_ops,
0242     .pad = &adv748x_csi2_pad_ops,
0243 };
0244 
0245 /* -----------------------------------------------------------------------------
0246  * Subdev module and controls
0247  */
0248 
0249 int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
0250 {
0251     struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
0252 
0253     if (!tx->pixel_rate)
0254         return -EINVAL;
0255 
0256     return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
0257 }
0258 
0259 static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
0260 {
0261     switch (ctrl->id) {
0262     case V4L2_CID_PIXEL_RATE:
0263         return 0;
0264     default:
0265         return -EINVAL;
0266     }
0267 }
0268 
0269 static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
0270     .s_ctrl = adv748x_csi2_s_ctrl,
0271 };
0272 
0273 static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
0274 {
0275 
0276     v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
0277 
0278     tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
0279                        &adv748x_csi2_ctrl_ops,
0280                        V4L2_CID_PIXEL_RATE, 1, INT_MAX,
0281                        1, 1);
0282 
0283     tx->sd.ctrl_handler = &tx->ctrl_hdl;
0284     if (tx->ctrl_hdl.error) {
0285         v4l2_ctrl_handler_free(&tx->ctrl_hdl);
0286         return tx->ctrl_hdl.error;
0287     }
0288 
0289     return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
0290 }
0291 
0292 int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
0293 {
0294     int ret;
0295 
0296     if (!is_tx_enabled(tx))
0297         return 0;
0298 
0299     adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
0300                 MEDIA_ENT_F_VID_IF_BRIDGE,
0301                 is_txa(tx) ? "txa" : "txb");
0302 
0303     /* Ensure that matching is based upon the endpoint fwnodes */
0304     tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
0305 
0306     /* Register internal ops for incremental subdev registration */
0307     tx->sd.internal_ops = &adv748x_csi2_internal_ops;
0308 
0309     tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
0310     tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
0311 
0312     ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
0313                      tx->pads);
0314     if (ret)
0315         return ret;
0316 
0317     ret = adv748x_csi2_init_controls(tx);
0318     if (ret)
0319         goto err_free_media;
0320 
0321     ret = v4l2_async_register_subdev(&tx->sd);
0322     if (ret)
0323         goto err_free_ctrl;
0324 
0325     return 0;
0326 
0327 err_free_ctrl:
0328     v4l2_ctrl_handler_free(&tx->ctrl_hdl);
0329 err_free_media:
0330     media_entity_cleanup(&tx->sd.entity);
0331 
0332     return ret;
0333 }
0334 
0335 void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
0336 {
0337     if (!is_tx_enabled(tx))
0338         return;
0339 
0340     v4l2_async_unregister_subdev(&tx->sd);
0341     media_entity_cleanup(&tx->sd.entity);
0342     v4l2_ctrl_handler_free(&tx->ctrl_hdl);
0343 }