media: i2c: adv748x: store number of CSI-2 lanes described in device tree
authorNiklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Thu, 29 Nov 2018 02:01:46 +0000 (21:01 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Wed, 16 Jan 2019 17:11:04 +0000 (12:11 -0500)
The adv748x CSI-2 transmitters TXA and TXB can use different number of
lanes to transmit data. In order to be able to configure the device
correctly this information need to be parsed from device tree and stored
in each TX private data structure.

TXA supports 1, 2 and 4 lanes while TXB supports 1 lane.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/i2c/adv748x/adv748x-core.c
drivers/media/i2c/adv748x/adv748x.h

index 2384f50dacb0ccffd6ac38dd20c00b3783c7f613..9d80d7f3062b16bc126fd16c2efc2b1354efdb58 100644 (file)
@@ -23,6 +23,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-dv-timings.h>
+#include <media/v4l2-fwnode.h>
 #include <media/v4l2-ioctl.h>
 
 #include "adv748x.h"
@@ -521,12 +522,56 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
        sd->entity.ops = &adv748x_media_ops;
 }
 
+static int adv748x_parse_csi2_lanes(struct adv748x_state *state,
+                                   unsigned int port,
+                                   struct device_node *ep)
+{
+       struct v4l2_fwnode_endpoint vep;
+       unsigned int num_lanes;
+       int ret;
+
+       if (port != ADV748X_PORT_TXA && port != ADV748X_PORT_TXB)
+               return 0;
+
+       vep.bus_type = V4L2_MBUS_CSI2_DPHY;
+       ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &vep);
+       if (ret)
+               return ret;
+
+       num_lanes = vep.bus.mipi_csi2.num_data_lanes;
+
+       if (vep.base.port == ADV748X_PORT_TXA) {
+               if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4) {
+                       adv_err(state, "TXA: Invalid number (%u) of lanes\n",
+                               num_lanes);
+                       return -EINVAL;
+               }
+
+               state->txa.num_lanes = num_lanes;
+               adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes);
+       }
+
+       if (vep.base.port == ADV748X_PORT_TXB) {
+               if (num_lanes != 1) {
+                       adv_err(state, "TXB: Invalid number (%u) of lanes\n",
+                               num_lanes);
+                       return -EINVAL;
+               }
+
+               state->txb.num_lanes = num_lanes;
+               adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes);
+       }
+
+       return 0;
+}
+
 static int adv748x_parse_dt(struct adv748x_state *state)
 {
        struct device_node *ep_np = NULL;
        struct of_endpoint ep;
        bool out_found = false;
        bool in_found = false;
+       int ret;
 
        for_each_endpoint_of_node(state->dev->of_node, ep_np) {
                of_graph_parse_endpoint(ep_np, &ep);
@@ -557,6 +602,11 @@ static int adv748x_parse_dt(struct adv748x_state *state)
                        in_found = true;
                else
                        out_found = true;
+
+               /* Store number of CSI-2 lanes used for TXA and TXB. */
+               ret = adv748x_parse_csi2_lanes(state, ep.port, ep_np);
+               if (ret)
+                       return ret;
        }
 
        return in_found && out_found ? 0 : -ENODEV;
index 39c2fdc3b41667d8ff23f082ed7d81c7bdc4cfe0..b482c7fe6957eb85985016fa0c453062f22ae84f 100644 (file)
@@ -79,6 +79,7 @@ struct adv748x_csi2 {
        struct v4l2_mbus_framefmt format;
        unsigned int page;
        unsigned int port;
+       unsigned int num_lanes;
 
        struct media_pad pads[ADV748X_CSI2_NR_PADS];
        struct v4l2_ctrl_handler ctrl_hdl;