linux/drivers/media/platform/qcom/camss/camss-video.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * camss-video.c
   4 *
   5 * Qualcomm MSM Camera Subsystem - V4L2 device node
   6 *
   7 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
   8 * Copyright (C) 2015-2018 Linaro Ltd.
   9 */
  10#include <linux/slab.h>
  11#include <media/media-entity.h>
  12#include <media/v4l2-dev.h>
  13#include <media/v4l2-device.h>
  14#include <media/v4l2-ioctl.h>
  15#include <media/v4l2-mc.h>
  16#include <media/videobuf2-dma-sg.h>
  17
  18#include "camss-video.h"
  19#include "camss.h"
  20
  21#define CAMSS_FRAME_MIN_WIDTH           1
  22#define CAMSS_FRAME_MAX_WIDTH           8191
  23#define CAMSS_FRAME_MIN_HEIGHT          1
  24#define CAMSS_FRAME_MAX_HEIGHT_RDI      8191
  25#define CAMSS_FRAME_MAX_HEIGHT_PIX      4096
  26
  27struct fract {
  28        u8 numerator;
  29        u8 denominator;
  30};
  31
  32/*
  33 * struct camss_format_info - ISP media bus format information
  34 * @code: V4L2 media bus format code
  35 * @pixelformat: V4L2 pixel format FCC identifier
  36 * @planes: Number of planes
  37 * @hsub: Horizontal subsampling (for each plane)
  38 * @vsub: Vertical subsampling (for each plane)
  39 * @bpp: Bits per pixel when stored in memory (for each plane)
  40 */
  41struct camss_format_info {
  42        u32 code;
  43        u32 pixelformat;
  44        u8 planes;
  45        struct fract hsub[3];
  46        struct fract vsub[3];
  47        unsigned int bpp[3];
  48};
  49
  50static const struct camss_format_info formats_rdi_8x16[] = {
  51        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
  52          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  53        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
  54          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  55        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
  56          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  57        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
  58          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  59        { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
  60          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
  61        { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
  62          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
  63        { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
  64          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
  65        { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
  66          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
  67        { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
  68          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  69        { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
  70          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  71        { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
  72          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  73        { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
  74          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  75        { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
  76          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
  77        { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
  78          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
  79        { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
  80          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
  81        { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
  82          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
  83        { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
  84          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  85};
  86
  87static const struct camss_format_info formats_rdi_8x96[] = {
  88        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
  89          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  90        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
  91          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  92        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
  93          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  94        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
  95          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
  96        { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
  97          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
  98        { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
  99          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 100        { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
 101          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 102        { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
 103          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 104        { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
 105          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 106        { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
 107          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 108        { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
 109          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 110        { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
 111          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 112        { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
 113          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 114        { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
 115          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 116        { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
 117          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 118        { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
 119          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 120        { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
 121          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 122        { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
 123          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 124        { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
 125          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 126        { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
 127          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 128        { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
 129          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 130        { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
 131          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 132        { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
 133          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 134};
 135
 136static const struct camss_format_info formats_rdi_845[] = {
 137        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
 138          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 139        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
 140          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 141        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
 142          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 143        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
 144          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 145        { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
 146          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 147        { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
 148          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 149        { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
 150          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 151        { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
 152          { { 1, 1 } }, { { 1, 1 } }, { 8 } },
 153        { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
 154          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 155        { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
 156          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 157        { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
 158          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 159        { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
 160          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 161        { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
 162          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 163        { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
 164          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 165        { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
 166          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 167        { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
 168          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 169        { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
 170          { { 1, 1 } }, { { 1, 1 } }, { 12 } },
 171        { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
 172          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 173        { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
 174          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 175        { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
 176          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 177        { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
 178          { { 1, 1 } }, { { 1, 1 } }, { 14 } },
 179        { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
 180          { { 1, 1 } }, { { 1, 1 } }, { 10 } },
 181        { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
 182          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 183};
 184
 185static const struct camss_format_info formats_pix_8x16[] = {
 186        { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 187          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 188        { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 189          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 190        { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 191          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 192        { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 193          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 194        { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 195          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 196        { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 197          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 198        { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 199          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 200        { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 201          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 202        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
 203          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 204        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
 205          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 206        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
 207          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 208        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
 209          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 210        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
 211          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 212        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
 213          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 214        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
 215          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 216        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
 217          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 218};
 219
 220static const struct camss_format_info formats_pix_8x96[] = {
 221        { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 222          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 223        { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 224          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 225        { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 226          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 227        { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 228          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 229        { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 230          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 231        { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 232          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 233        { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 234          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 235        { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
 236          { { 1, 1 } }, { { 2, 3 } }, { 8 } },
 237        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
 238          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 239        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
 240          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 241        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
 242          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 243        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
 244          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 245        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
 246          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 247        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
 248          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 249        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
 250          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 251        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
 252          { { 1, 1 } }, { { 1, 2 } }, { 8 } },
 253        { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
 254          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 255        { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
 256          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 257        { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
 258          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 259        { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
 260          { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 261};
 262
 263/* -----------------------------------------------------------------------------
 264 * Helper functions
 265 */
 266
 267static int video_find_format(u32 code, u32 pixelformat,
 268                             const struct camss_format_info *formats,
 269                             unsigned int nformats)
 270{
 271        int i;
 272
 273        for (i = 0; i < nformats; i++) {
 274                if (formats[i].code == code &&
 275                    formats[i].pixelformat == pixelformat)
 276                        return i;
 277        }
 278
 279        for (i = 0; i < nformats; i++)
 280                if (formats[i].code == code)
 281                        return i;
 282
 283        WARN_ON(1);
 284
 285        return -EINVAL;
 286}
 287
 288/*
 289 * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane
 290 * @mbus: v4l2_mbus_framefmt format (input)
 291 * @pix: v4l2_pix_format_mplane format (output)
 292 * @f: a pointer to formats array element to be used for the conversion
 293 * @alignment: bytesperline alignment value
 294 *
 295 * Fill the output pix structure with information from the input mbus format.
 296 *
 297 * Return 0 on success or a negative error code otherwise
 298 */
 299static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus,
 300                                struct v4l2_pix_format_mplane *pix,
 301                                const struct camss_format_info *f,
 302                                unsigned int alignment)
 303{
 304        unsigned int i;
 305        u32 bytesperline;
 306
 307        memset(pix, 0, sizeof(*pix));
 308        v4l2_fill_pix_format_mplane(pix, mbus);
 309        pix->pixelformat = f->pixelformat;
 310        pix->num_planes = f->planes;
 311        for (i = 0; i < pix->num_planes; i++) {
 312                bytesperline = pix->width / f->hsub[i].numerator *
 313                        f->hsub[i].denominator * f->bpp[i] / 8;
 314                bytesperline = ALIGN(bytesperline, alignment);
 315                pix->plane_fmt[i].bytesperline = bytesperline;
 316                pix->plane_fmt[i].sizeimage = pix->height /
 317                                f->vsub[i].numerator * f->vsub[i].denominator *
 318                                bytesperline;
 319        }
 320
 321        return 0;
 322}
 323
 324static struct v4l2_subdev *video_remote_subdev(struct camss_video *video,
 325                                               u32 *pad)
 326{
 327        struct media_pad *remote;
 328
 329        remote = media_entity_remote_pad(&video->pad);
 330
 331        if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
 332                return NULL;
 333
 334        if (pad)
 335                *pad = remote->index;
 336
 337        return media_entity_to_v4l2_subdev(remote->entity);
 338}
 339
 340static int video_get_subdev_format(struct camss_video *video,
 341                                   struct v4l2_format *format)
 342{
 343        struct v4l2_subdev_format fmt;
 344        struct v4l2_subdev *subdev;
 345        u32 pad;
 346        int ret;
 347
 348        subdev = video_remote_subdev(video, &pad);
 349        if (subdev == NULL)
 350                return -EPIPE;
 351
 352        fmt.pad = pad;
 353        fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 354
 355        ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
 356        if (ret)
 357                return ret;
 358
 359        ret = video_find_format(fmt.format.code,
 360                                format->fmt.pix_mp.pixelformat,
 361                                video->formats, video->nformats);
 362        if (ret < 0)
 363                return ret;
 364
 365        format->type = video->type;
 366
 367        return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp,
 368                                    &video->formats[ret], video->bpl_alignment);
 369}
 370
 371/* -----------------------------------------------------------------------------
 372 * Video queue operations
 373 */
 374
 375static int video_queue_setup(struct vb2_queue *q,
 376        unsigned int *num_buffers, unsigned int *num_planes,
 377        unsigned int sizes[], struct device *alloc_devs[])
 378{
 379        struct camss_video *video = vb2_get_drv_priv(q);
 380        const struct v4l2_pix_format_mplane *format =
 381                                                &video->active_fmt.fmt.pix_mp;
 382        unsigned int i;
 383
 384        if (*num_planes) {
 385                if (*num_planes != format->num_planes)
 386                        return -EINVAL;
 387
 388                for (i = 0; i < *num_planes; i++)
 389                        if (sizes[i] < format->plane_fmt[i].sizeimage)
 390                                return -EINVAL;
 391
 392                return 0;
 393        }
 394
 395        *num_planes = format->num_planes;
 396
 397        for (i = 0; i < *num_planes; i++)
 398                sizes[i] = format->plane_fmt[i].sizeimage;
 399
 400        return 0;
 401}
 402
 403static int video_buf_init(struct vb2_buffer *vb)
 404{
 405        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 406        struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
 407        struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
 408                                                   vb);
 409        const struct v4l2_pix_format_mplane *format =
 410                                                &video->active_fmt.fmt.pix_mp;
 411        struct sg_table *sgt;
 412        unsigned int i;
 413
 414        for (i = 0; i < format->num_planes; i++) {
 415                sgt = vb2_dma_sg_plane_desc(vb, i);
 416                if (!sgt)
 417                        return -EFAULT;
 418
 419                buffer->addr[i] = sg_dma_address(sgt->sgl);
 420        }
 421
 422        if (format->pixelformat == V4L2_PIX_FMT_NV12 ||
 423                        format->pixelformat == V4L2_PIX_FMT_NV21 ||
 424                        format->pixelformat == V4L2_PIX_FMT_NV16 ||
 425                        format->pixelformat == V4L2_PIX_FMT_NV61)
 426                buffer->addr[1] = buffer->addr[0] +
 427                                format->plane_fmt[0].bytesperline *
 428                                format->height;
 429
 430        return 0;
 431}
 432
 433static int video_buf_prepare(struct vb2_buffer *vb)
 434{
 435        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 436        struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
 437        const struct v4l2_pix_format_mplane *format =
 438                                                &video->active_fmt.fmt.pix_mp;
 439        unsigned int i;
 440
 441        for (i = 0; i < format->num_planes; i++) {
 442                if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i))
 443                        return -EINVAL;
 444
 445                vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage);
 446        }
 447
 448        vbuf->field = V4L2_FIELD_NONE;
 449
 450        return 0;
 451}
 452
 453static void video_buf_queue(struct vb2_buffer *vb)
 454{
 455        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 456        struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
 457        struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
 458                                                   vb);
 459
 460        video->ops->queue_buffer(video, buffer);
 461}
 462
 463static int video_check_format(struct camss_video *video)
 464{
 465        struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp;
 466        struct v4l2_format format;
 467        struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp;
 468        int ret;
 469
 470        sd_pix->pixelformat = pix->pixelformat;
 471        ret = video_get_subdev_format(video, &format);
 472        if (ret < 0)
 473                return ret;
 474
 475        if (pix->pixelformat != sd_pix->pixelformat ||
 476            pix->height != sd_pix->height ||
 477            pix->width != sd_pix->width ||
 478            pix->num_planes != sd_pix->num_planes ||
 479            pix->field != format.fmt.pix_mp.field)
 480                return -EPIPE;
 481
 482        return 0;
 483}
 484
 485static int video_start_streaming(struct vb2_queue *q, unsigned int count)
 486{
 487        struct camss_video *video = vb2_get_drv_priv(q);
 488        struct video_device *vdev = &video->vdev;
 489        struct media_entity *entity;
 490        struct media_pad *pad;
 491        struct v4l2_subdev *subdev;
 492        int ret;
 493
 494        ret = media_pipeline_start(&vdev->entity, &video->pipe);
 495        if (ret < 0)
 496                return ret;
 497
 498        ret = video_check_format(video);
 499        if (ret < 0)
 500                goto error;
 501
 502        entity = &vdev->entity;
 503        while (1) {
 504                pad = &entity->pads[0];
 505                if (!(pad->flags & MEDIA_PAD_FL_SINK))
 506                        break;
 507
 508                pad = media_entity_remote_pad(pad);
 509                if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
 510                        break;
 511
 512                entity = pad->entity;
 513                subdev = media_entity_to_v4l2_subdev(entity);
 514
 515                ret = v4l2_subdev_call(subdev, video, s_stream, 1);
 516                if (ret < 0 && ret != -ENOIOCTLCMD)
 517                        goto error;
 518        }
 519
 520        return 0;
 521
 522error:
 523        media_pipeline_stop(&vdev->entity);
 524
 525        video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
 526
 527        return ret;
 528}
 529
 530static void video_stop_streaming(struct vb2_queue *q)
 531{
 532        struct camss_video *video = vb2_get_drv_priv(q);
 533        struct video_device *vdev = &video->vdev;
 534        struct media_entity *entity;
 535        struct media_pad *pad;
 536        struct v4l2_subdev *subdev;
 537
 538        entity = &vdev->entity;
 539        while (1) {
 540                pad = &entity->pads[0];
 541                if (!(pad->flags & MEDIA_PAD_FL_SINK))
 542                        break;
 543
 544                pad = media_entity_remote_pad(pad);
 545                if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
 546                        break;
 547
 548                entity = pad->entity;
 549                subdev = media_entity_to_v4l2_subdev(entity);
 550
 551                v4l2_subdev_call(subdev, video, s_stream, 0);
 552        }
 553
 554        media_pipeline_stop(&vdev->entity);
 555
 556        video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
 557}
 558
 559static const struct vb2_ops msm_video_vb2_q_ops = {
 560        .queue_setup     = video_queue_setup,
 561        .wait_prepare    = vb2_ops_wait_prepare,
 562        .wait_finish     = vb2_ops_wait_finish,
 563        .buf_init        = video_buf_init,
 564        .buf_prepare     = video_buf_prepare,
 565        .buf_queue       = video_buf_queue,
 566        .start_streaming = video_start_streaming,
 567        .stop_streaming  = video_stop_streaming,
 568};
 569
 570/* -----------------------------------------------------------------------------
 571 * V4L2 ioctls
 572 */
 573
 574static int video_querycap(struct file *file, void *fh,
 575                          struct v4l2_capability *cap)
 576{
 577        struct camss_video *video = video_drvdata(file);
 578
 579        strscpy(cap->driver, "qcom-camss", sizeof(cap->driver));
 580        strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
 581        snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
 582                 dev_name(video->camss->dev));
 583
 584        return 0;
 585}
 586
 587static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
 588{
 589        struct camss_video *video = video_drvdata(file);
 590        int i, j, k;
 591        u32 mcode = f->mbus_code;
 592
 593        if (f->type != video->type)
 594                return -EINVAL;
 595
 596        if (f->index >= video->nformats)
 597                return -EINVAL;
 598
 599        /*
 600         * Find index "i" of "k"th unique pixelformat in formats array.
 601         *
 602         * If f->mbus_code passed to video_enum_fmt() is not zero, a device
 603         * with V4L2_CAP_IO_MC capability restricts enumeration to only the
 604         * pixel formats that can be produced from that media bus code.
 605         * This is implemented by skipping video->formats[] entries with
 606         * code != f->mbus_code (if f->mbus_code is not zero).
 607         * If the f->mbus_code passed to video_enum_fmt() is not supported,
 608         * -EINVAL is returned.
 609         * If f->mbus_code is zero, all the pixel formats are enumerated.
 610         */
 611        k = -1;
 612        for (i = 0; i < video->nformats; i++) {
 613                if (mcode != 0 && video->formats[i].code != mcode)
 614                        continue;
 615
 616                for (j = 0; j < i; j++) {
 617                        if (mcode != 0 && video->formats[j].code != mcode)
 618                                continue;
 619                        if (video->formats[i].pixelformat ==
 620                                        video->formats[j].pixelformat)
 621                                break;
 622                }
 623
 624                if (j == i)
 625                        k++;
 626
 627                if (k == f->index)
 628                        break;
 629        }
 630
 631        if (k == -1 || k < f->index)
 632                /*
 633                 * All the unique pixel formats matching the arguments
 634                 * have been enumerated (k >= 0 and f->index > 0), or
 635                 * no pixel formats match the non-zero f->mbus_code (k == -1).
 636                 */
 637                return -EINVAL;
 638
 639        f->pixelformat = video->formats[i].pixelformat;
 640
 641        return 0;
 642}
 643
 644static int video_enum_framesizes(struct file *file, void *fh,
 645                                 struct v4l2_frmsizeenum *fsize)
 646{
 647        struct camss_video *video = video_drvdata(file);
 648        int i;
 649
 650        if (fsize->index)
 651                return -EINVAL;
 652
 653        /* Only accept pixel format present in the formats[] table */
 654        for (i = 0; i < video->nformats; i++) {
 655                if (video->formats[i].pixelformat == fsize->pixel_format)
 656                        break;
 657        }
 658
 659        if (i == video->nformats)
 660                return -EINVAL;
 661
 662        fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
 663        fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH;
 664        fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH;
 665        fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT;
 666        fsize->stepwise.max_height = (video->line_based) ?
 667                CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI;
 668        fsize->stepwise.step_width = 1;
 669        fsize->stepwise.step_height = 1;
 670
 671        return 0;
 672}
 673
 674static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
 675{
 676        struct camss_video *video = video_drvdata(file);
 677
 678        *f = video->active_fmt;
 679
 680        return 0;
 681}
 682
 683static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
 684{
 685        struct v4l2_pix_format_mplane *pix_mp;
 686        const struct camss_format_info *fi;
 687        struct v4l2_plane_pix_format *p;
 688        u32 bytesperline[3] = { 0 };
 689        u32 sizeimage[3] = { 0 };
 690        u32 width, height;
 691        u32 bpl, lines;
 692        int i, j;
 693
 694        pix_mp = &f->fmt.pix_mp;
 695
 696        if (video->line_based)
 697                for (i = 0; i < pix_mp->num_planes && i < 3; i++) {
 698                        p = &pix_mp->plane_fmt[i];
 699                        bytesperline[i] = clamp_t(u32, p->bytesperline,
 700                                                  1, 65528);
 701                        sizeimage[i] = clamp_t(u32, p->sizeimage,
 702                                               bytesperline[i],
 703                                               bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX);
 704                }
 705
 706        for (j = 0; j < video->nformats; j++)
 707                if (pix_mp->pixelformat == video->formats[j].pixelformat)
 708                        break;
 709
 710        if (j == video->nformats)
 711                j = 0; /* default format */
 712
 713        fi = &video->formats[j];
 714        width = pix_mp->width;
 715        height = pix_mp->height;
 716
 717        memset(pix_mp, 0, sizeof(*pix_mp));
 718
 719        pix_mp->pixelformat = fi->pixelformat;
 720        pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH);
 721        pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI);
 722        pix_mp->num_planes = fi->planes;
 723        for (i = 0; i < pix_mp->num_planes; i++) {
 724                bpl = pix_mp->width / fi->hsub[i].numerator *
 725                        fi->hsub[i].denominator * fi->bpp[i] / 8;
 726                bpl = ALIGN(bpl, video->bpl_alignment);
 727                pix_mp->plane_fmt[i].bytesperline = bpl;
 728                pix_mp->plane_fmt[i].sizeimage = pix_mp->height /
 729                        fi->vsub[i].numerator * fi->vsub[i].denominator * bpl;
 730        }
 731
 732        pix_mp->field = V4L2_FIELD_NONE;
 733        pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
 734        pix_mp->flags = 0;
 735        pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace);
 736        pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
 737                                        pix_mp->colorspace, pix_mp->ycbcr_enc);
 738        pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace);
 739
 740        if (video->line_based)
 741                for (i = 0; i < pix_mp->num_planes; i++) {
 742                        p = &pix_mp->plane_fmt[i];
 743                        p->bytesperline = clamp_t(u32, p->bytesperline,
 744                                                  1, 65528);
 745                        p->sizeimage = clamp_t(u32, p->sizeimage,
 746                                               p->bytesperline,
 747                                               p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX);
 748                        lines = p->sizeimage / p->bytesperline;
 749
 750                        if (p->bytesperline < bytesperline[i])
 751                                p->bytesperline = ALIGN(bytesperline[i], 8);
 752
 753                        if (p->sizeimage < p->bytesperline * lines)
 754                                p->sizeimage = p->bytesperline * lines;
 755
 756                        if (p->sizeimage < sizeimage[i])
 757                                p->sizeimage = sizeimage[i];
 758                }
 759
 760        return 0;
 761}
 762
 763static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
 764{
 765        struct camss_video *video = video_drvdata(file);
 766
 767        return __video_try_fmt(video, f);
 768}
 769
 770static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
 771{
 772        struct camss_video *video = video_drvdata(file);
 773        int ret;
 774
 775        if (vb2_is_busy(&video->vb2_q))
 776                return -EBUSY;
 777
 778        ret = __video_try_fmt(video, f);
 779        if (ret < 0)
 780                return ret;
 781
 782        video->active_fmt = *f;
 783
 784        return 0;
 785}
 786
 787static int video_enum_input(struct file *file, void *fh,
 788                            struct v4l2_input *input)
 789{
 790        if (input->index > 0)
 791                return -EINVAL;
 792
 793        strscpy(input->name, "camera", sizeof(input->name));
 794        input->type = V4L2_INPUT_TYPE_CAMERA;
 795
 796        return 0;
 797}
 798
 799static int video_g_input(struct file *file, void *fh, unsigned int *input)
 800{
 801        *input = 0;
 802
 803        return 0;
 804}
 805
 806static int video_s_input(struct file *file, void *fh, unsigned int input)
 807{
 808        return input == 0 ? 0 : -EINVAL;
 809}
 810
 811static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
 812        .vidioc_querycap                = video_querycap,
 813        .vidioc_enum_fmt_vid_cap        = video_enum_fmt,
 814        .vidioc_enum_framesizes         = video_enum_framesizes,
 815        .vidioc_g_fmt_vid_cap_mplane    = video_g_fmt,
 816        .vidioc_s_fmt_vid_cap_mplane    = video_s_fmt,
 817        .vidioc_try_fmt_vid_cap_mplane  = video_try_fmt,
 818        .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
 819        .vidioc_querybuf                = vb2_ioctl_querybuf,
 820        .vidioc_qbuf                    = vb2_ioctl_qbuf,
 821        .vidioc_expbuf                  = vb2_ioctl_expbuf,
 822        .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
 823        .vidioc_create_bufs             = vb2_ioctl_create_bufs,
 824        .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
 825        .vidioc_streamon                = vb2_ioctl_streamon,
 826        .vidioc_streamoff               = vb2_ioctl_streamoff,
 827        .vidioc_enum_input              = video_enum_input,
 828        .vidioc_g_input                 = video_g_input,
 829        .vidioc_s_input                 = video_s_input,
 830};
 831
 832/* -----------------------------------------------------------------------------
 833 * V4L2 file operations
 834 */
 835
 836static int video_open(struct file *file)
 837{
 838        struct video_device *vdev = video_devdata(file);
 839        struct camss_video *video = video_drvdata(file);
 840        struct v4l2_fh *vfh;
 841        int ret;
 842
 843        mutex_lock(&video->lock);
 844
 845        vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
 846        if (vfh == NULL) {
 847                ret = -ENOMEM;
 848                goto error_alloc;
 849        }
 850
 851        v4l2_fh_init(vfh, vdev);
 852        v4l2_fh_add(vfh);
 853
 854        file->private_data = vfh;
 855
 856        ret = v4l2_pipeline_pm_get(&vdev->entity);
 857        if (ret < 0) {
 858                dev_err(video->camss->dev, "Failed to power up pipeline: %d\n",
 859                        ret);
 860                goto error_pm_use;
 861        }
 862
 863        mutex_unlock(&video->lock);
 864
 865        return 0;
 866
 867error_pm_use:
 868        v4l2_fh_release(file);
 869
 870error_alloc:
 871        mutex_unlock(&video->lock);
 872
 873        return ret;
 874}
 875
 876static int video_release(struct file *file)
 877{
 878        struct video_device *vdev = video_devdata(file);
 879
 880        vb2_fop_release(file);
 881
 882        v4l2_pipeline_pm_put(&vdev->entity);
 883
 884        file->private_data = NULL;
 885
 886        return 0;
 887}
 888
 889static const struct v4l2_file_operations msm_vid_fops = {
 890        .owner          = THIS_MODULE,
 891        .unlocked_ioctl = video_ioctl2,
 892        .open           = video_open,
 893        .release        = video_release,
 894        .poll           = vb2_fop_poll,
 895        .mmap           = vb2_fop_mmap,
 896        .read           = vb2_fop_read,
 897};
 898
 899/* -----------------------------------------------------------------------------
 900 * CAMSS video core
 901 */
 902
 903static void msm_video_release(struct video_device *vdev)
 904{
 905        struct camss_video *video = video_get_drvdata(vdev);
 906
 907        media_entity_cleanup(&vdev->entity);
 908
 909        mutex_destroy(&video->q_lock);
 910        mutex_destroy(&video->lock);
 911
 912        if (atomic_dec_and_test(&video->camss->ref_count))
 913                camss_delete(video->camss);
 914}
 915
 916/*
 917 * msm_video_init_format - Helper function to initialize format
 918 * @video: struct camss_video
 919 *
 920 * Initialize pad format with default value.
 921 *
 922 * Return 0 on success or a negative error code otherwise
 923 */
 924static int msm_video_init_format(struct camss_video *video)
 925{
 926        int ret;
 927        struct v4l2_format format = {
 928                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
 929                .fmt.pix_mp = {
 930                        .width = 1920,
 931                        .height = 1080,
 932                        .pixelformat = video->formats[0].pixelformat,
 933                },
 934        };
 935
 936        ret = __video_try_fmt(video, &format);
 937        if (ret < 0)
 938                return ret;
 939
 940        video->active_fmt = format;
 941
 942        return 0;
 943}
 944
 945/*
 946 * msm_video_register - Register a video device node
 947 * @video: struct camss_video
 948 * @v4l2_dev: V4L2 device
 949 * @name: name to be used for the video device node
 950 *
 951 * Initialize and register a video device node to a V4L2 device. Also
 952 * initialize the vb2 queue.
 953 *
 954 * Return 0 on success or a negative error code otherwise
 955 */
 956
 957int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 958                       const char *name, int is_pix)
 959{
 960        struct media_pad *pad = &video->pad;
 961        struct video_device *vdev;
 962        struct vb2_queue *q;
 963        int ret;
 964
 965        vdev = &video->vdev;
 966
 967        mutex_init(&video->q_lock);
 968
 969        q = &video->vb2_q;
 970        q->drv_priv = video;
 971        q->mem_ops = &vb2_dma_sg_memops;
 972        q->ops = &msm_video_vb2_q_ops;
 973        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 974        q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
 975        q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 976        q->buf_struct_size = sizeof(struct camss_buffer);
 977        q->dev = video->camss->dev;
 978        q->lock = &video->q_lock;
 979        ret = vb2_queue_init(q);
 980        if (ret < 0) {
 981                dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret);
 982                goto error_vb2_init;
 983        }
 984
 985        pad->flags = MEDIA_PAD_FL_SINK;
 986        ret = media_entity_pads_init(&vdev->entity, 1, pad);
 987        if (ret < 0) {
 988                dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n",
 989                        ret);
 990                goto error_vb2_init;
 991        }
 992
 993        mutex_init(&video->lock);
 994
 995        if (video->camss->version == CAMSS_8x16) {
 996                if (is_pix) {
 997                        video->formats = formats_pix_8x16;
 998                        video->nformats = ARRAY_SIZE(formats_pix_8x16);
 999                } else {
1000                        video->formats = formats_rdi_8x16;
1001                        video->nformats = ARRAY_SIZE(formats_rdi_8x16);
1002                }
1003        } else if (video->camss->version == CAMSS_8x96 ||
1004                   video->camss->version == CAMSS_660) {
1005                if (is_pix) {
1006                        video->formats = formats_pix_8x96;
1007                        video->nformats = ARRAY_SIZE(formats_pix_8x96);
1008                } else {
1009                        video->formats = formats_rdi_8x96;
1010                        video->nformats = ARRAY_SIZE(formats_rdi_8x96);
1011                }
1012        }  else if (video->camss->version == CAMSS_845) {
1013                video->formats = formats_rdi_845;
1014                video->nformats = ARRAY_SIZE(formats_rdi_845);
1015        } else {
1016                ret = -EINVAL;
1017                goto error_video_register;
1018        }
1019
1020        ret = msm_video_init_format(video);
1021        if (ret < 0) {
1022                dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret);
1023                goto error_video_register;
1024        }
1025
1026        vdev->fops = &msm_vid_fops;
1027        vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING
1028                          | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC;
1029        vdev->ioctl_ops = &msm_vid_ioctl_ops;
1030        vdev->release = msm_video_release;
1031        vdev->v4l2_dev = v4l2_dev;
1032        vdev->vfl_dir = VFL_DIR_RX;
1033        vdev->queue = &video->vb2_q;
1034        vdev->lock = &video->lock;
1035        strscpy(vdev->name, name, sizeof(vdev->name));
1036
1037        ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1038        if (ret < 0) {
1039                dev_err(v4l2_dev->dev, "Failed to register video device: %d\n",
1040                        ret);
1041                goto error_video_register;
1042        }
1043
1044        video_set_drvdata(vdev, video);
1045        atomic_inc(&video->camss->ref_count);
1046
1047        return 0;
1048
1049error_video_register:
1050        media_entity_cleanup(&vdev->entity);
1051        mutex_destroy(&video->lock);
1052error_vb2_init:
1053        mutex_destroy(&video->q_lock);
1054
1055        return ret;
1056}
1057
1058void msm_video_unregister(struct camss_video *video)
1059{
1060        atomic_inc(&video->camss->ref_count);
1061        vb2_video_unregister_device(&video->vdev);
1062        atomic_dec(&video->camss->ref_count);
1063}
1064