Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020 NVIDIA CORPORATION.  All rights reserved.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/clk/tegra.h>
0008 #include <linux/device.h>
0009 #include <linux/host1x.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_graph.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_runtime.h>
0016 
0017 #include <media/v4l2-fwnode.h>
0018 
0019 #include "csi.h"
0020 #include "video.h"
0021 
0022 #define MHZ         1000000
0023 
0024 static inline struct tegra_csi *
0025 host1x_client_to_csi(struct host1x_client *client)
0026 {
0027     return container_of(client, struct tegra_csi, client);
0028 }
0029 
0030 static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev)
0031 {
0032     return container_of(subdev, struct tegra_csi_channel, subdev);
0033 }
0034 
0035 /*
0036  * CSI is a separate subdevice which has 6 source pads to generate
0037  * test pattern. CSI subdevice pad ops are used only for TPG and
0038  * allows below TPG formats.
0039  */
0040 static const struct v4l2_mbus_framefmt tegra_csi_tpg_fmts[] = {
0041     {
0042         TEGRA_DEF_WIDTH,
0043         TEGRA_DEF_HEIGHT,
0044         MEDIA_BUS_FMT_SRGGB10_1X10,
0045         V4L2_FIELD_NONE,
0046         V4L2_COLORSPACE_SRGB
0047     },
0048     {
0049         TEGRA_DEF_WIDTH,
0050         TEGRA_DEF_HEIGHT,
0051         MEDIA_BUS_FMT_RGB888_1X32_PADHI,
0052         V4L2_FIELD_NONE,
0053         V4L2_COLORSPACE_SRGB
0054     },
0055 };
0056 
0057 static const struct v4l2_frmsize_discrete tegra_csi_tpg_sizes[] = {
0058     { 1280, 720 },
0059     { 1920, 1080 },
0060     { 3840, 2160 },
0061 };
0062 
0063 /*
0064  * V4L2 Subdevice Pad Operations
0065  */
0066 static int csi_enum_bus_code(struct v4l2_subdev *subdev,
0067                  struct v4l2_subdev_state *sd_state,
0068                  struct v4l2_subdev_mbus_code_enum *code)
0069 {
0070     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0071         return -ENOIOCTLCMD;
0072 
0073     if (code->index >= ARRAY_SIZE(tegra_csi_tpg_fmts))
0074         return -EINVAL;
0075 
0076     code->code = tegra_csi_tpg_fmts[code->index].code;
0077 
0078     return 0;
0079 }
0080 
0081 static int csi_get_format(struct v4l2_subdev *subdev,
0082               struct v4l2_subdev_state *sd_state,
0083               struct v4l2_subdev_format *fmt)
0084 {
0085     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0086 
0087     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0088         return -ENOIOCTLCMD;
0089 
0090     fmt->format = csi_chan->format;
0091 
0092     return 0;
0093 }
0094 
0095 static int csi_get_frmrate_table_index(struct tegra_csi *csi, u32 code,
0096                        u32 width, u32 height)
0097 {
0098     const struct tpg_framerate *frmrate;
0099     unsigned int i;
0100 
0101     frmrate = csi->soc->tpg_frmrate_table;
0102     for (i = 0; i < csi->soc->tpg_frmrate_table_size; i++) {
0103         if (frmrate[i].code == code &&
0104             frmrate[i].frmsize.width == width &&
0105             frmrate[i].frmsize.height == height) {
0106             return i;
0107         }
0108     }
0109 
0110     return -EINVAL;
0111 }
0112 
0113 static void csi_chan_update_blank_intervals(struct tegra_csi_channel *csi_chan,
0114                         u32 code, u32 width, u32 height)
0115 {
0116     struct tegra_csi *csi = csi_chan->csi;
0117     const struct tpg_framerate *frmrate = csi->soc->tpg_frmrate_table;
0118     int index;
0119 
0120     index = csi_get_frmrate_table_index(csi_chan->csi, code,
0121                         width, height);
0122     if (index >= 0) {
0123         csi_chan->h_blank = frmrate[index].h_blank;
0124         csi_chan->v_blank = frmrate[index].v_blank;
0125         csi_chan->framerate = frmrate[index].framerate;
0126     }
0127 }
0128 
0129 static int csi_enum_framesizes(struct v4l2_subdev *subdev,
0130                    struct v4l2_subdev_state *sd_state,
0131                    struct v4l2_subdev_frame_size_enum *fse)
0132 {
0133     unsigned int i;
0134 
0135     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0136         return -ENOIOCTLCMD;
0137 
0138     if (fse->index >= ARRAY_SIZE(tegra_csi_tpg_sizes))
0139         return -EINVAL;
0140 
0141     for (i = 0; i < ARRAY_SIZE(tegra_csi_tpg_fmts); i++)
0142         if (fse->code == tegra_csi_tpg_fmts[i].code)
0143             break;
0144 
0145     if (i == ARRAY_SIZE(tegra_csi_tpg_fmts))
0146         return -EINVAL;
0147 
0148     fse->min_width = tegra_csi_tpg_sizes[fse->index].width;
0149     fse->max_width = tegra_csi_tpg_sizes[fse->index].width;
0150     fse->min_height = tegra_csi_tpg_sizes[fse->index].height;
0151     fse->max_height = tegra_csi_tpg_sizes[fse->index].height;
0152 
0153     return 0;
0154 }
0155 
0156 static int csi_enum_frameintervals(struct v4l2_subdev *subdev,
0157                    struct v4l2_subdev_state *sd_state,
0158                    struct v4l2_subdev_frame_interval_enum *fie)
0159 {
0160     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0161     struct tegra_csi *csi = csi_chan->csi;
0162     const struct tpg_framerate *frmrate = csi->soc->tpg_frmrate_table;
0163     int index;
0164 
0165     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0166         return -ENOIOCTLCMD;
0167 
0168     /* one framerate per format and resolution */
0169     if (fie->index > 0)
0170         return -EINVAL;
0171 
0172     index = csi_get_frmrate_table_index(csi_chan->csi, fie->code,
0173                         fie->width, fie->height);
0174     if (index < 0)
0175         return -EINVAL;
0176 
0177     fie->interval.numerator = 1;
0178     fie->interval.denominator = frmrate[index].framerate;
0179 
0180     return 0;
0181 }
0182 
0183 static int csi_set_format(struct v4l2_subdev *subdev,
0184               struct v4l2_subdev_state *sd_state,
0185               struct v4l2_subdev_format *fmt)
0186 {
0187     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0188     struct v4l2_mbus_framefmt *format = &fmt->format;
0189     const struct v4l2_frmsize_discrete *sizes;
0190     unsigned int i;
0191 
0192     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0193         return -ENOIOCTLCMD;
0194 
0195     sizes = v4l2_find_nearest_size(tegra_csi_tpg_sizes,
0196                        ARRAY_SIZE(tegra_csi_tpg_sizes),
0197                        width, height,
0198                        format->width, format->width);
0199     format->width = sizes->width;
0200     format->height = sizes->height;
0201 
0202     for (i = 0; i < ARRAY_SIZE(tegra_csi_tpg_fmts); i++)
0203         if (format->code == tegra_csi_tpg_fmts[i].code)
0204             break;
0205 
0206     if (i == ARRAY_SIZE(tegra_csi_tpg_fmts))
0207         i = 0;
0208 
0209     format->code = tegra_csi_tpg_fmts[i].code;
0210     format->field = V4L2_FIELD_NONE;
0211 
0212     if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
0213         return 0;
0214 
0215     /* update blanking intervals from frame rate table and format */
0216     csi_chan_update_blank_intervals(csi_chan, format->code,
0217                     format->width, format->height);
0218     csi_chan->format = *format;
0219 
0220     return 0;
0221 }
0222 
0223 /*
0224  * V4L2 Subdevice Video Operations
0225  */
0226 static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev,
0227                       struct v4l2_subdev_frame_interval *vfi)
0228 {
0229     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0230 
0231     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0232         return -ENOIOCTLCMD;
0233 
0234     vfi->interval.numerator = 1;
0235     vfi->interval.denominator = csi_chan->framerate;
0236 
0237     return 0;
0238 }
0239 
0240 static unsigned int csi_get_pixel_rate(struct tegra_csi_channel *csi_chan)
0241 {
0242     struct tegra_vi_channel *chan;
0243     struct v4l2_subdev *src_subdev;
0244     struct v4l2_ctrl *ctrl;
0245 
0246     chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
0247     src_subdev = tegra_channel_get_remote_source_subdev(chan);
0248     ctrl = v4l2_ctrl_find(src_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
0249     if (ctrl)
0250         return v4l2_ctrl_g_ctrl_int64(ctrl);
0251 
0252     return 0;
0253 }
0254 
0255 void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
0256                 u8 csi_port_num,
0257                 u8 *clk_settle_time,
0258                 u8 *ths_settle_time)
0259 {
0260     struct tegra_csi *csi = csi_chan->csi;
0261     unsigned int cil_clk_mhz;
0262     unsigned int pix_clk_mhz;
0263     int clk_idx = (csi_port_num >> 1) + 1;
0264 
0265     cil_clk_mhz = clk_get_rate(csi->clks[clk_idx].clk) / MHZ;
0266     pix_clk_mhz = csi_get_pixel_rate(csi_chan) / MHZ;
0267 
0268     /*
0269      * CLK Settle time is the interval during which HS receiver should
0270      * ignore any clock lane HS transitions, starting from the beginning
0271      * of T-CLK-PREPARE.
0272      * Per DPHY specification, T-CLK-SETTLE should be between 95ns ~ 300ns
0273      *
0274      * 95ns < (clk-settle-programmed + 7) * lp clk period < 300ns
0275      * midpoint = 197.5 ns
0276      */
0277     *clk_settle_time = ((95 + 300) * cil_clk_mhz - 14000) / 2000;
0278 
0279     /*
0280      * THS Settle time is the interval during which HS receiver should
0281      * ignore any data lane HS transitions, starting from the beginning
0282      * of THS-PREPARE.
0283      *
0284      * Per DPHY specification, T-HS-SETTLE should be between 85ns + 6UI
0285      * and 145ns+10UI.
0286      * 85ns + 6UI < (Ths-settle-prog + 5) * lp_clk_period < 145ns + 10UI
0287      * midpoint = 115ns + 8UI
0288      */
0289     if (pix_clk_mhz)
0290         *ths_settle_time = (115 * cil_clk_mhz + 8000 * cil_clk_mhz
0291                    / (2 * pix_clk_mhz) - 5000) / 1000;
0292 }
0293 
0294 static int tegra_csi_enable_stream(struct v4l2_subdev *subdev)
0295 {
0296     struct tegra_vi_channel *chan = v4l2_get_subdev_hostdata(subdev);
0297     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0298     struct tegra_csi *csi = csi_chan->csi;
0299     int ret, err;
0300 
0301     ret = pm_runtime_resume_and_get(csi->dev);
0302     if (ret < 0) {
0303         dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
0304         return ret;
0305     }
0306 
0307     if (csi_chan->mipi) {
0308         ret = tegra_mipi_enable(csi_chan->mipi);
0309         if (ret < 0) {
0310             dev_err(csi->dev,
0311                 "failed to enable MIPI pads: %d\n", ret);
0312             goto rpm_put;
0313         }
0314 
0315         /*
0316          * CSI MIPI pads PULLUP, PULLDN and TERM impedances need to
0317          * be calibrated after power on.
0318          * So, trigger the calibration start here and results will
0319          * be latched and applied to the pads when link is in LP11
0320          * state during start of sensor streaming.
0321          */
0322         ret = tegra_mipi_start_calibration(csi_chan->mipi);
0323         if (ret < 0) {
0324             dev_err(csi->dev,
0325                 "failed to start MIPI calibration: %d\n", ret);
0326             goto disable_mipi;
0327         }
0328     }
0329 
0330     csi_chan->pg_mode = chan->pg_mode;
0331     ret = csi->ops->csi_start_streaming(csi_chan);
0332     if (ret < 0)
0333         goto finish_calibration;
0334 
0335     return 0;
0336 
0337 finish_calibration:
0338     if (csi_chan->mipi)
0339         tegra_mipi_finish_calibration(csi_chan->mipi);
0340 disable_mipi:
0341     if (csi_chan->mipi) {
0342         err = tegra_mipi_disable(csi_chan->mipi);
0343         if (err < 0)
0344             dev_err(csi->dev,
0345                 "failed to disable MIPI pads: %d\n", err);
0346     }
0347 
0348 rpm_put:
0349     pm_runtime_put(csi->dev);
0350     return ret;
0351 }
0352 
0353 static int tegra_csi_disable_stream(struct v4l2_subdev *subdev)
0354 {
0355     struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
0356     struct tegra_csi *csi = csi_chan->csi;
0357     int err;
0358 
0359     csi->ops->csi_stop_streaming(csi_chan);
0360 
0361     if (csi_chan->mipi) {
0362         err = tegra_mipi_disable(csi_chan->mipi);
0363         if (err < 0)
0364             dev_err(csi->dev,
0365                 "failed to disable MIPI pads: %d\n", err);
0366     }
0367 
0368     pm_runtime_put(csi->dev);
0369 
0370     return 0;
0371 }
0372 
0373 static int tegra_csi_s_stream(struct v4l2_subdev *subdev, int enable)
0374 {
0375     int ret;
0376 
0377     if (enable)
0378         ret = tegra_csi_enable_stream(subdev);
0379     else
0380         ret = tegra_csi_disable_stream(subdev);
0381 
0382     return ret;
0383 }
0384 
0385 /*
0386  * V4L2 Subdevice Operations
0387  */
0388 static const struct v4l2_subdev_video_ops tegra_csi_video_ops = {
0389     .s_stream = tegra_csi_s_stream,
0390     .g_frame_interval = tegra_csi_g_frame_interval,
0391     .s_frame_interval = tegra_csi_g_frame_interval,
0392 };
0393 
0394 static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
0395     .enum_mbus_code     = csi_enum_bus_code,
0396     .enum_frame_size    = csi_enum_framesizes,
0397     .enum_frame_interval    = csi_enum_frameintervals,
0398     .get_fmt        = csi_get_format,
0399     .set_fmt        = csi_set_format,
0400 };
0401 
0402 static const struct v4l2_subdev_ops tegra_csi_ops = {
0403     .video  = &tegra_csi_video_ops,
0404     .pad    = &tegra_csi_pad_ops,
0405 };
0406 
0407 static int tegra_csi_channel_alloc(struct tegra_csi *csi,
0408                    struct device_node *node,
0409                    unsigned int port_num, unsigned int lanes,
0410                    unsigned int num_pads)
0411 {
0412     struct tegra_csi_channel *chan;
0413     int ret = 0, i;
0414 
0415     chan = kzalloc(sizeof(*chan), GFP_KERNEL);
0416     if (!chan)
0417         return -ENOMEM;
0418 
0419     list_add_tail(&chan->list, &csi->csi_chans);
0420     chan->csi = csi;
0421     /*
0422      * Each CSI brick has maximum of 4 lanes.
0423      * For lanes more than 4, use multiple of immediate CSI bricks as gang.
0424      */
0425     if (lanes <= CSI_LANES_PER_BRICK) {
0426         chan->numlanes = lanes;
0427         chan->numgangports = 1;
0428     } else {
0429         chan->numlanes = CSI_LANES_PER_BRICK;
0430         chan->numgangports = lanes / CSI_LANES_PER_BRICK;
0431     }
0432 
0433     for (i = 0; i < chan->numgangports; i++)
0434         chan->csi_port_nums[i] = port_num + i * CSI_PORTS_PER_BRICK;
0435 
0436     chan->of_node = node;
0437     chan->numpads = num_pads;
0438     if (num_pads & 0x2) {
0439         chan->pads[0].flags = MEDIA_PAD_FL_SINK;
0440         chan->pads[1].flags = MEDIA_PAD_FL_SOURCE;
0441     } else {
0442         chan->pads[0].flags = MEDIA_PAD_FL_SOURCE;
0443     }
0444 
0445     if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0446         return 0;
0447 
0448     chan->mipi = tegra_mipi_request(csi->dev, node);
0449     if (IS_ERR(chan->mipi)) {
0450         ret = PTR_ERR(chan->mipi);
0451         dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
0452     }
0453 
0454     return ret;
0455 }
0456 
0457 static int tegra_csi_tpg_channels_alloc(struct tegra_csi *csi)
0458 {
0459     struct device_node *node = csi->dev->of_node;
0460     unsigned int port_num;
0461     unsigned int tpg_channels = csi->soc->csi_max_channels;
0462     int ret;
0463 
0464     /* allocate CSI channel for each CSI x2 ports */
0465     for (port_num = 0; port_num < tpg_channels; port_num++) {
0466         ret = tegra_csi_channel_alloc(csi, node, port_num, 2, 1);
0467         if (ret < 0)
0468             return ret;
0469     }
0470 
0471     return 0;
0472 }
0473 
0474 static int tegra_csi_channels_alloc(struct tegra_csi *csi)
0475 {
0476     struct device_node *node = csi->dev->of_node;
0477     struct v4l2_fwnode_endpoint v4l2_ep = {
0478         .bus_type = V4L2_MBUS_CSI2_DPHY
0479     };
0480     struct fwnode_handle *fwh;
0481     struct device_node *channel;
0482     struct device_node *ep;
0483     unsigned int lanes, portno, num_pads;
0484     int ret;
0485 
0486     for_each_child_of_node(node, channel) {
0487         if (!of_node_name_eq(channel, "channel"))
0488             continue;
0489 
0490         ret = of_property_read_u32(channel, "reg", &portno);
0491         if (ret < 0)
0492             continue;
0493 
0494         if (portno >= csi->soc->csi_max_channels) {
0495             dev_err(csi->dev, "invalid port num %d for %pOF\n",
0496                 portno, channel);
0497             ret = -EINVAL;
0498             goto err_node_put;
0499         }
0500 
0501         ep = of_graph_get_endpoint_by_regs(channel, 0, 0);
0502         if (!ep)
0503             continue;
0504 
0505         fwh = of_fwnode_handle(ep);
0506         ret = v4l2_fwnode_endpoint_parse(fwh, &v4l2_ep);
0507         of_node_put(ep);
0508         if (ret) {
0509             dev_err(csi->dev,
0510                 "failed to parse v4l2 endpoint for %pOF: %d\n",
0511                 channel, ret);
0512             goto err_node_put;
0513         }
0514 
0515         lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
0516         /*
0517          * Each CSI brick has maximum 4 data lanes.
0518          * For lanes more than 4, validate lanes to be multiple of 4
0519          * so multiple of consecutive CSI bricks can be ganged up for
0520          * streaming.
0521          */
0522         if (!lanes || ((lanes & (lanes - 1)) != 0) ||
0523             (lanes > CSI_LANES_PER_BRICK && ((portno & 1) != 0))) {
0524             dev_err(csi->dev, "invalid data-lanes %d for %pOF\n",
0525                 lanes, channel);
0526             ret = -EINVAL;
0527             goto err_node_put;
0528         }
0529 
0530         num_pads = of_graph_get_endpoint_count(channel);
0531         if (num_pads == TEGRA_CSI_PADS_NUM) {
0532             ret = tegra_csi_channel_alloc(csi, channel, portno,
0533                               lanes, num_pads);
0534             if (ret < 0)
0535                 goto err_node_put;
0536         }
0537     }
0538 
0539     return 0;
0540 
0541 err_node_put:
0542     of_node_put(channel);
0543     return ret;
0544 }
0545 
0546 static int tegra_csi_channel_init(struct tegra_csi_channel *chan)
0547 {
0548     struct tegra_csi *csi = chan->csi;
0549     struct v4l2_subdev *subdev;
0550     int ret;
0551 
0552     /* initialize the default format */
0553     chan->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
0554     chan->format.field = V4L2_FIELD_NONE;
0555     chan->format.colorspace = V4L2_COLORSPACE_SRGB;
0556     chan->format.width = TEGRA_DEF_WIDTH;
0557     chan->format.height = TEGRA_DEF_HEIGHT;
0558     csi_chan_update_blank_intervals(chan, chan->format.code,
0559                     chan->format.width,
0560                     chan->format.height);
0561     /* initialize V4L2 subdevice and media entity */
0562     subdev = &chan->subdev;
0563     v4l2_subdev_init(subdev, &tegra_csi_ops);
0564     subdev->dev = csi->dev;
0565     if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0566         snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s-%d", "tpg",
0567              chan->csi_port_nums[0]);
0568     else
0569         snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s",
0570              kbasename(chan->of_node->full_name));
0571 
0572     v4l2_set_subdevdata(subdev, chan);
0573     subdev->fwnode = of_fwnode_handle(chan->of_node);
0574     subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
0575 
0576     /* initialize media entity pads */
0577     ret = media_entity_pads_init(&subdev->entity, chan->numpads,
0578                      chan->pads);
0579     if (ret < 0) {
0580         dev_err(csi->dev,
0581             "failed to initialize media entity: %d\n", ret);
0582         subdev->dev = NULL;
0583         return ret;
0584     }
0585 
0586     if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
0587         ret = v4l2_async_register_subdev(subdev);
0588         if (ret < 0) {
0589             dev_err(csi->dev,
0590                 "failed to register subdev: %d\n", ret);
0591             return ret;
0592         }
0593     }
0594 
0595     return 0;
0596 }
0597 
0598 void tegra_csi_error_recover(struct v4l2_subdev *sd)
0599 {
0600     struct tegra_csi_channel *csi_chan = to_csi_chan(sd);
0601     struct tegra_csi *csi = csi_chan->csi;
0602 
0603     /* stop streaming during error recovery */
0604     csi->ops->csi_stop_streaming(csi_chan);
0605     csi->ops->csi_err_recover(csi_chan);
0606     csi->ops->csi_start_streaming(csi_chan);
0607 }
0608 
0609 static int tegra_csi_channels_init(struct tegra_csi *csi)
0610 {
0611     struct tegra_csi_channel *chan;
0612     int ret;
0613 
0614     list_for_each_entry(chan, &csi->csi_chans, list) {
0615         ret = tegra_csi_channel_init(chan);
0616         if (ret) {
0617             dev_err(csi->dev,
0618                 "failed to initialize channel-%d: %d\n",
0619                 chan->csi_port_nums[0], ret);
0620             return ret;
0621         }
0622     }
0623 
0624     return 0;
0625 }
0626 
0627 static void tegra_csi_channels_cleanup(struct tegra_csi *csi)
0628 {
0629     struct v4l2_subdev *subdev;
0630     struct tegra_csi_channel *chan, *tmp;
0631 
0632     list_for_each_entry_safe(chan, tmp, &csi->csi_chans, list) {
0633         if (chan->mipi)
0634             tegra_mipi_free(chan->mipi);
0635 
0636         subdev = &chan->subdev;
0637         if (subdev->dev) {
0638             if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0639                 v4l2_async_unregister_subdev(subdev);
0640             media_entity_cleanup(&subdev->entity);
0641         }
0642 
0643         list_del(&chan->list);
0644         kfree(chan);
0645     }
0646 }
0647 
0648 static int __maybe_unused csi_runtime_suspend(struct device *dev)
0649 {
0650     struct tegra_csi *csi = dev_get_drvdata(dev);
0651 
0652     clk_bulk_disable_unprepare(csi->soc->num_clks, csi->clks);
0653 
0654     return 0;
0655 }
0656 
0657 static int __maybe_unused csi_runtime_resume(struct device *dev)
0658 {
0659     struct tegra_csi *csi = dev_get_drvdata(dev);
0660     int ret;
0661 
0662     ret = clk_bulk_prepare_enable(csi->soc->num_clks, csi->clks);
0663     if (ret < 0) {
0664         dev_err(csi->dev, "failed to enable clocks: %d\n", ret);
0665         return ret;
0666     }
0667 
0668     return 0;
0669 }
0670 
0671 static int tegra_csi_init(struct host1x_client *client)
0672 {
0673     struct tegra_csi *csi = host1x_client_to_csi(client);
0674     struct tegra_video_device *vid = dev_get_drvdata(client->host);
0675     int ret;
0676 
0677     INIT_LIST_HEAD(&csi->csi_chans);
0678 
0679     if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0680         ret = tegra_csi_tpg_channels_alloc(csi);
0681     else
0682         ret = tegra_csi_channels_alloc(csi);
0683     if (ret < 0) {
0684         dev_err(csi->dev,
0685             "failed to allocate channels: %d\n", ret);
0686         goto cleanup;
0687     }
0688 
0689     ret = tegra_csi_channels_init(csi);
0690     if (ret < 0)
0691         goto cleanup;
0692 
0693     vid->csi = csi;
0694 
0695     return 0;
0696 
0697 cleanup:
0698     tegra_csi_channels_cleanup(csi);
0699     return ret;
0700 }
0701 
0702 static int tegra_csi_exit(struct host1x_client *client)
0703 {
0704     struct tegra_csi *csi = host1x_client_to_csi(client);
0705 
0706     tegra_csi_channels_cleanup(csi);
0707 
0708     return 0;
0709 }
0710 
0711 static const struct host1x_client_ops csi_client_ops = {
0712     .init = tegra_csi_init,
0713     .exit = tegra_csi_exit,
0714 };
0715 
0716 static int tegra_csi_probe(struct platform_device *pdev)
0717 {
0718     struct tegra_csi *csi;
0719     unsigned int i;
0720     int ret;
0721 
0722     csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
0723     if (!csi)
0724         return -ENOMEM;
0725 
0726     csi->iomem = devm_platform_ioremap_resource(pdev, 0);
0727     if (IS_ERR(csi->iomem))
0728         return PTR_ERR(csi->iomem);
0729 
0730     csi->soc = of_device_get_match_data(&pdev->dev);
0731 
0732     csi->clks = devm_kcalloc(&pdev->dev, csi->soc->num_clks,
0733                  sizeof(*csi->clks), GFP_KERNEL);
0734     if (!csi->clks)
0735         return -ENOMEM;
0736 
0737     for (i = 0; i < csi->soc->num_clks; i++)
0738         csi->clks[i].id = csi->soc->clk_names[i];
0739 
0740     ret = devm_clk_bulk_get(&pdev->dev, csi->soc->num_clks, csi->clks);
0741     if (ret) {
0742         dev_err(&pdev->dev, "failed to get the clocks: %d\n", ret);
0743         return ret;
0744     }
0745 
0746     if (!pdev->dev.pm_domain) {
0747         ret = -ENOENT;
0748         dev_warn(&pdev->dev, "PM domain is not attached: %d\n", ret);
0749         return ret;
0750     }
0751 
0752     csi->dev = &pdev->dev;
0753     csi->ops = csi->soc->ops;
0754     platform_set_drvdata(pdev, csi);
0755     pm_runtime_enable(&pdev->dev);
0756 
0757     /* initialize host1x interface */
0758     INIT_LIST_HEAD(&csi->client.list);
0759     csi->client.ops = &csi_client_ops;
0760     csi->client.dev = &pdev->dev;
0761 
0762     ret = host1x_client_register(&csi->client);
0763     if (ret < 0) {
0764         dev_err(&pdev->dev,
0765             "failed to register host1x client: %d\n", ret);
0766         goto rpm_disable;
0767     }
0768 
0769     return 0;
0770 
0771 rpm_disable:
0772     pm_runtime_disable(&pdev->dev);
0773     return ret;
0774 }
0775 
0776 static int tegra_csi_remove(struct platform_device *pdev)
0777 {
0778     struct tegra_csi *csi = platform_get_drvdata(pdev);
0779     int err;
0780 
0781     err = host1x_client_unregister(&csi->client);
0782     if (err < 0) {
0783         dev_err(&pdev->dev,
0784             "failed to unregister host1x client: %d\n", err);
0785         return err;
0786     }
0787 
0788     pm_runtime_disable(&pdev->dev);
0789 
0790     return 0;
0791 }
0792 
0793 static const struct of_device_id tegra_csi_of_id_table[] = {
0794 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
0795     { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
0796 #endif
0797     { }
0798 };
0799 MODULE_DEVICE_TABLE(of, tegra_csi_of_id_table);
0800 
0801 static const struct dev_pm_ops tegra_csi_pm_ops = {
0802     SET_RUNTIME_PM_OPS(csi_runtime_suspend, csi_runtime_resume, NULL)
0803 };
0804 
0805 struct platform_driver tegra_csi_driver = {
0806     .driver = {
0807         .name       = "tegra-csi",
0808         .of_match_table = tegra_csi_of_id_table,
0809         .pm     = &tegra_csi_pm_ops,
0810     },
0811     .probe          = tegra_csi_probe,
0812     .remove         = tegra_csi_remove,
0813 };