1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor 4 * 5 * Copyright (C) STMicroelectronics SA 2023 6 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com> 7 * Alain Volmat <alain.volmat@foss.st.com> 8 * for STMicroelectronics. 9 */ 10 11 #include <linux/v4l2-mediabus.h> 12 #include <media/mipi-csi2.h> 13 #include <media/v4l2-event.h> 14 #include <media/v4l2-subdev.h> 15 16 #include "dcmipp-common.h" 17 18 #define DCMIPP_PRCR 0x104 19 #define DCMIPP_PRCR_FORMAT_SHIFT 16 20 #define DCMIPP_PRCR_FORMAT_YUV422 0x1e 21 #define DCMIPP_PRCR_FORMAT_RGB565 0x22 22 #define DCMIPP_PRCR_FORMAT_RAW8 0x2a 23 #define DCMIPP_PRCR_FORMAT_RAW10 0x2b 24 #define DCMIPP_PRCR_FORMAT_RAW12 0x2c 25 #define DCMIPP_PRCR_FORMAT_RAW14 0x2d 26 #define DCMIPP_PRCR_FORMAT_G8 0x4a 27 #define DCMIPP_PRCR_FORMAT_BYTE_STREAM 0x5a 28 #define DCMIPP_PRCR_ESS BIT(4) 29 #define DCMIPP_PRCR_PCKPOL BIT(5) 30 #define DCMIPP_PRCR_HSPOL BIT(6) 31 #define DCMIPP_PRCR_VSPOL BIT(7) 32 #define DCMIPP_PRCR_ENABLE BIT(14) 33 #define DCMIPP_PRCR_SWAPCYCLES BIT(25) 34 35 #define DCMIPP_PRESCR 0x108 36 #define DCMIPP_PRESUR 0x10c 37 38 #define DCMIPP_CMCR 0x204 39 #define DCMIPP_CMCR_INSEL BIT(0) 40 41 #define DCMIPP_P0FSCR 0x404 42 #define DCMIPP_P0FSCR_DTMODE_MASK GENMASK(17, 16) 43 #define DCMIPP_P0FSCR_DTMODE_SHIFT 16 44 #define DCMIPP_P0FSCR_DTMODE_DTIDA 0x00 45 #define DCMIPP_P0FSCR_DTMODE_ALLDT 0x03 46 #define DCMIPP_P0FSCR_DTIDA_MASK GENMASK(5, 0) 47 #define DCMIPP_P0FSCR_DTIDA_SHIFT 0 48 49 #define IS_SINK(pad) (!(pad)) 50 #define IS_SRC(pad) ((pad)) 51 52 struct dcmipp_inp_pix_map { 53 unsigned int code_sink; 54 unsigned int code_src; 55 /* Parallel related information */ 56 u8 prcr_format; 57 u8 prcr_swapcycles; 58 /* CSI related information */ 59 unsigned int dt; 60 }; 61 62 #define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap, data_type) \ 63 { \ 64 .code_sink = MEDIA_BUS_FMT_##sink, \ 65 .code_src = MEDIA_BUS_FMT_##src, \ 66 .prcr_format = DCMIPP_PRCR_FORMAT_##prcr, \ 67 .prcr_swapcycles = swap, \ 68 .dt = data_type, \ 69 } 70 static const struct dcmipp_inp_pix_map dcmipp_inp_pix_map_list[] = { 71 /* RGB565 */ 72 PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1, MIPI_CSI2_DT_RGB565), 73 PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0, MIPI_CSI2_DT_RGB565), 74 PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_1X16, RGB565_1X16, RGB565, 0, MIPI_CSI2_DT_RGB565), 75 /* YUV422 */ 76 PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 77 PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_1X16, YUYV8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 78 PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 79 PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 80 PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_1X16, UYVY8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 81 PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 82 PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 83 PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_1X16, YVYU8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 84 PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 85 PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_1X16, VYUY8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 86 /* GREY */ 87 PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0, MIPI_CSI2_DT_RAW8), 88 /* Raw Bayer */ 89 PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 90 PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 91 PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 92 PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 93 PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR10_1X10, SBGGR10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 94 PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG10_1X10, SGBRG10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 95 PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG10_1X10, SGRBG10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 96 PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB10_1X10, SRGGB10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 97 PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR12_1X12, SBGGR12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 98 PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG12_1X12, SGBRG12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 99 PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG12_1X12, SGRBG12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 100 PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB12_1X12, SRGGB12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 101 PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR14_1X14, SBGGR14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 102 PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG14_1X14, SGBRG14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 103 PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG14_1X14, SGRBG14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 104 PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB14_1X14, SRGGB14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 105 /* JPEG */ 106 PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0, 0), 107 }; 108 109 /* 110 * Search through the pix_map table, skipping two consecutive entry with the 111 * same code 112 */ 113 static inline const struct dcmipp_inp_pix_map *dcmipp_inp_pix_map_by_index 114 (unsigned int index, 115 unsigned int pad) 116 { 117 unsigned int i = 0; 118 u32 prev_code = 0, cur_code; 119 120 while (i < ARRAY_SIZE(dcmipp_inp_pix_map_list)) { 121 if (IS_SRC(pad)) 122 cur_code = dcmipp_inp_pix_map_list[i].code_src; 123 else 124 cur_code = dcmipp_inp_pix_map_list[i].code_sink; 125 126 if (cur_code == prev_code) { 127 i++; 128 continue; 129 } 130 prev_code = cur_code; 131 132 if (index == 0) 133 break; 134 i++; 135 index--; 136 } 137 138 if (i >= ARRAY_SIZE(dcmipp_inp_pix_map_list)) 139 return NULL; 140 141 return &dcmipp_inp_pix_map_list[i]; 142 } 143 144 static inline const struct dcmipp_inp_pix_map *dcmipp_inp_pix_map_by_code 145 (u32 code_sink, u32 code_src) 146 { 147 unsigned int i; 148 149 for (i = 0; i < ARRAY_SIZE(dcmipp_inp_pix_map_list); i++) { 150 if ((dcmipp_inp_pix_map_list[i].code_sink == code_sink && 151 dcmipp_inp_pix_map_list[i].code_src == code_src) || 152 (dcmipp_inp_pix_map_list[i].code_sink == code_src && 153 dcmipp_inp_pix_map_list[i].code_src == code_sink) || 154 (dcmipp_inp_pix_map_list[i].code_sink == code_sink && 155 code_src == 0) || 156 (code_sink == 0 && 157 dcmipp_inp_pix_map_list[i].code_src == code_src)) 158 return &dcmipp_inp_pix_map_list[i]; 159 } 160 return NULL; 161 } 162 163 struct dcmipp_inp_device { 164 struct dcmipp_ent_device ved; 165 struct v4l2_subdev sd; 166 struct device *dev; 167 void __iomem *regs; 168 }; 169 170 static const struct v4l2_mbus_framefmt fmt_default = { 171 .width = DCMIPP_FMT_WIDTH_DEFAULT, 172 .height = DCMIPP_FMT_HEIGHT_DEFAULT, 173 .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 174 .field = V4L2_FIELD_NONE, 175 .colorspace = DCMIPP_COLORSPACE_DEFAULT, 176 .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, 177 .quantization = DCMIPP_QUANTIZATION_DEFAULT, 178 .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, 179 }; 180 181 static int dcmipp_inp_init_state(struct v4l2_subdev *sd, 182 struct v4l2_subdev_state *sd_state) 183 { 184 unsigned int i; 185 186 for (i = 0; i < sd->entity.num_pads; i++) { 187 struct v4l2_mbus_framefmt *mf; 188 189 mf = v4l2_subdev_state_get_format(sd_state, i); 190 *mf = fmt_default; 191 } 192 193 return 0; 194 } 195 196 static int dcmipp_inp_enum_mbus_code(struct v4l2_subdev *sd, 197 struct v4l2_subdev_state *sd_state, 198 struct v4l2_subdev_mbus_code_enum *code) 199 { 200 const struct dcmipp_inp_pix_map *vpix = 201 dcmipp_inp_pix_map_by_index(code->index, code->pad); 202 203 if (!vpix) 204 return -EINVAL; 205 206 code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink; 207 208 return 0; 209 } 210 211 static int dcmipp_inp_enum_frame_size(struct v4l2_subdev *sd, 212 struct v4l2_subdev_state *sd_state, 213 struct v4l2_subdev_frame_size_enum *fse) 214 { 215 const struct dcmipp_inp_pix_map *vpix; 216 217 if (fse->index) 218 return -EINVAL; 219 220 /* Only accept code in the pix map table */ 221 vpix = dcmipp_inp_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0, 222 IS_SRC(fse->pad) ? fse->code : 0); 223 if (!vpix) 224 return -EINVAL; 225 226 fse->min_width = DCMIPP_FRAME_MIN_WIDTH; 227 fse->max_width = DCMIPP_FRAME_MAX_WIDTH; 228 fse->min_height = DCMIPP_FRAME_MIN_HEIGHT; 229 fse->max_height = DCMIPP_FRAME_MAX_HEIGHT; 230 231 return 0; 232 } 233 234 static void dcmipp_inp_adjust_fmt(struct dcmipp_inp_device *inp, 235 struct v4l2_mbus_framefmt *fmt, __u32 pad) 236 { 237 const struct dcmipp_inp_pix_map *vpix; 238 239 /* Only accept code in the pix map table */ 240 vpix = dcmipp_inp_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0, 241 IS_SRC(pad) ? fmt->code : 0); 242 if (!vpix) 243 fmt->code = fmt_default.code; 244 245 /* Exclude JPEG if BT656 bus is selected */ 246 if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 && 247 inp->ved.bus_type == V4L2_MBUS_BT656) 248 fmt->code = fmt_default.code; 249 250 fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH, 251 DCMIPP_FRAME_MAX_WIDTH) & ~1; 252 fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT, 253 DCMIPP_FRAME_MAX_HEIGHT) & ~1; 254 255 if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) 256 fmt->field = fmt_default.field; 257 258 dcmipp_colorimetry_clamp(fmt); 259 } 260 261 static int dcmipp_inp_set_fmt(struct v4l2_subdev *sd, 262 struct v4l2_subdev_state *sd_state, 263 struct v4l2_subdev_format *fmt) 264 { 265 struct dcmipp_inp_device *inp = v4l2_get_subdevdata(sd); 266 struct v4l2_mbus_framefmt *mf; 267 268 if (v4l2_subdev_is_streaming(sd)) 269 return -EBUSY; 270 271 mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); 272 273 /* Set the new format */ 274 dcmipp_inp_adjust_fmt(inp, &fmt->format, fmt->pad); 275 276 dev_dbg(inp->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n", 277 inp->sd.name, 278 /* old */ 279 mf->width, mf->height, mf->code, 280 mf->colorspace, mf->quantization, 281 mf->xfer_func, mf->ycbcr_enc, 282 /* new */ 283 fmt->format.width, fmt->format.height, fmt->format.code, 284 fmt->format.colorspace, fmt->format.quantization, 285 fmt->format.xfer_func, fmt->format.ycbcr_enc); 286 287 *mf = fmt->format; 288 289 /* When setting the sink format, report that format on the src pad */ 290 if (IS_SINK(fmt->pad)) { 291 mf = v4l2_subdev_state_get_format(sd_state, 1); 292 *mf = fmt->format; 293 dcmipp_inp_adjust_fmt(inp, mf, 1); 294 } 295 296 return 0; 297 } 298 299 static int dcmipp_inp_configure_parallel(struct dcmipp_inp_device *inp, 300 struct v4l2_subdev_state *state) 301 { 302 u32 val = 0; 303 const struct dcmipp_inp_pix_map *vpix; 304 struct v4l2_mbus_framefmt *sink_fmt; 305 struct v4l2_mbus_framefmt *src_fmt; 306 307 /* Set vertical synchronization polarity */ 308 if (inp->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 309 val |= DCMIPP_PRCR_VSPOL; 310 311 /* Set horizontal synchronization polarity */ 312 if (inp->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 313 val |= DCMIPP_PRCR_HSPOL; 314 315 /* Set pixel clock polarity */ 316 if (inp->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 317 val |= DCMIPP_PRCR_PCKPOL; 318 319 /* 320 * BT656 embedded synchronisation bus mode. 321 * 322 * Default SAV/EAV mode is supported here with default codes 323 * SAV=0xff000080 & EAV=0xff00009d. 324 * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d. 325 */ 326 if (inp->ved.bus_type == V4L2_MBUS_BT656) { 327 val |= DCMIPP_PRCR_ESS; 328 329 /* Unmask all codes */ 330 reg_write(inp, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ 331 332 /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ 333 reg_write(inp, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ 334 } 335 336 /* Set format */ 337 sink_fmt = v4l2_subdev_state_get_format(state, 0); 338 src_fmt = v4l2_subdev_state_get_format(state, 1); 339 340 vpix = dcmipp_inp_pix_map_by_code(sink_fmt->code, src_fmt->code); 341 if (!vpix) { 342 dev_err(inp->dev, "Invalid sink/src format configuration\n"); 343 return -EINVAL; 344 } 345 346 val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT; 347 348 /* swap cycles */ 349 if (vpix->prcr_swapcycles) 350 val |= DCMIPP_PRCR_SWAPCYCLES; 351 352 reg_write(inp, DCMIPP_PRCR, val); 353 354 /* Select the DCMIPP parallel interface */ 355 reg_write(inp, DCMIPP_CMCR, 0); 356 357 /* Enable parallel interface */ 358 reg_set(inp, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 359 360 return 0; 361 } 362 363 static int dcmipp_inp_configure_csi(struct dcmipp_inp_device *inp, 364 struct v4l2_subdev_state *state) 365 { 366 const struct dcmipp_inp_pix_map *vpix; 367 struct v4l2_mbus_framefmt *sink_fmt; 368 struct v4l2_mbus_framefmt *src_fmt; 369 370 /* Get format information */ 371 sink_fmt = v4l2_subdev_state_get_format(state, 0); 372 src_fmt = v4l2_subdev_state_get_format(state, 1); 373 374 vpix = dcmipp_inp_pix_map_by_code(sink_fmt->code, src_fmt->code); 375 if (!vpix) { 376 dev_err(inp->dev, "Invalid sink/src format configuration\n"); 377 return -EINVAL; 378 } 379 380 /* Apply configuration on each input pipe */ 381 reg_clear(inp, DCMIPP_P0FSCR, 382 DCMIPP_P0FSCR_DTMODE_MASK | DCMIPP_P0FSCR_DTIDA_MASK); 383 384 /* In case of JPEG we don't know the DT so we allow all data */ 385 /* 386 * TODO - check instead dt == 0 for the time being to allow other 387 * unknown data-type 388 */ 389 if (!vpix->dt) 390 reg_set(inp, DCMIPP_P0FSCR, 391 DCMIPP_P0FSCR_DTMODE_ALLDT << DCMIPP_P0FSCR_DTMODE_SHIFT); 392 else 393 reg_set(inp, DCMIPP_P0FSCR, 394 vpix->dt << DCMIPP_P0FSCR_DTIDA_SHIFT | 395 DCMIPP_P0FSCR_DTMODE_DTIDA); 396 397 /* Select the DCMIPP CSI interface */ 398 reg_write(inp, DCMIPP_CMCR, DCMIPP_CMCR_INSEL); 399 400 return 0; 401 } 402 403 static int dcmipp_inp_enable_streams(struct v4l2_subdev *sd, 404 struct v4l2_subdev_state *state, 405 u32 pad, u64 streams_mask) 406 { 407 struct dcmipp_inp_device *inp = 408 container_of(sd, struct dcmipp_inp_device, sd); 409 struct v4l2_subdev *s_subdev; 410 struct media_pad *s_pad; 411 int ret = 0; 412 413 /* Get source subdev */ 414 s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]); 415 if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity)) 416 return -EINVAL; 417 s_subdev = media_entity_to_v4l2_subdev(s_pad->entity); 418 419 if (inp->ved.bus_type == V4L2_MBUS_PARALLEL || 420 inp->ved.bus_type == V4L2_MBUS_BT656) 421 ret = dcmipp_inp_configure_parallel(inp, state); 422 else if (inp->ved.bus_type == V4L2_MBUS_CSI2_DPHY) 423 ret = dcmipp_inp_configure_csi(inp, state); 424 if (ret) 425 return ret; 426 427 ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0)); 428 if (ret < 0) { 429 dev_err(inp->dev, 430 "failed to start source subdev streaming (%d)\n", ret); 431 return ret; 432 } 433 434 return 0; 435 } 436 437 static int dcmipp_inp_disable_streams(struct v4l2_subdev *sd, 438 struct v4l2_subdev_state *state, 439 u32 pad, u64 streams_mask) 440 { 441 struct dcmipp_inp_device *inp = 442 container_of(sd, struct dcmipp_inp_device, sd); 443 struct v4l2_subdev *s_subdev; 444 struct media_pad *s_pad; 445 int ret; 446 447 /* Get source subdev */ 448 s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]); 449 if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity)) 450 return -EINVAL; 451 s_subdev = media_entity_to_v4l2_subdev(s_pad->entity); 452 453 ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0)); 454 if (ret < 0) { 455 dev_err(inp->dev, 456 "failed to stop source subdev streaming (%d)\n", ret); 457 return ret; 458 } 459 460 if (inp->ved.bus_type == V4L2_MBUS_PARALLEL || 461 inp->ved.bus_type == V4L2_MBUS_BT656) { 462 /* Disable parallel interface */ 463 reg_clear(inp, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 464 } 465 466 return 0; 467 } 468 469 static const struct v4l2_subdev_pad_ops dcmipp_inp_pad_ops = { 470 .enum_mbus_code = dcmipp_inp_enum_mbus_code, 471 .enum_frame_size = dcmipp_inp_enum_frame_size, 472 .get_fmt = v4l2_subdev_get_fmt, 473 .set_fmt = dcmipp_inp_set_fmt, 474 .enable_streams = dcmipp_inp_enable_streams, 475 .disable_streams = dcmipp_inp_disable_streams, 476 }; 477 478 static const struct v4l2_subdev_video_ops dcmipp_inp_video_ops = { 479 .s_stream = v4l2_subdev_s_stream_helper, 480 }; 481 482 static const struct v4l2_subdev_ops dcmipp_inp_ops = { 483 .pad = &dcmipp_inp_pad_ops, 484 .video = &dcmipp_inp_video_ops, 485 }; 486 487 static void dcmipp_inp_release(struct v4l2_subdev *sd) 488 { 489 struct dcmipp_inp_device *inp = 490 container_of(sd, struct dcmipp_inp_device, sd); 491 492 kfree(inp); 493 } 494 495 static const struct v4l2_subdev_internal_ops dcmipp_inp_int_ops = { 496 .init_state = dcmipp_inp_init_state, 497 .release = dcmipp_inp_release, 498 }; 499 500 void dcmipp_inp_ent_release(struct dcmipp_ent_device *ved) 501 { 502 struct dcmipp_inp_device *inp = 503 container_of(ved, struct dcmipp_inp_device, ved); 504 505 dcmipp_ent_sd_unregister(ved, &inp->sd); 506 } 507 508 struct dcmipp_ent_device *dcmipp_inp_ent_init(struct device *dev, 509 const char *entity_name, 510 struct v4l2_device *v4l2_dev, 511 void __iomem *regs) 512 { 513 struct dcmipp_inp_device *inp; 514 const unsigned long pads_flag[] = { 515 MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, 516 }; 517 int ret; 518 519 /* Allocate the inp struct */ 520 inp = kzalloc(sizeof(*inp), GFP_KERNEL); 521 if (!inp) 522 return ERR_PTR(-ENOMEM); 523 524 inp->regs = regs; 525 526 /* Initialize ved and sd */ 527 ret = dcmipp_ent_sd_register(&inp->ved, &inp->sd, v4l2_dev, 528 entity_name, MEDIA_ENT_F_VID_IF_BRIDGE, 529 ARRAY_SIZE(pads_flag), pads_flag, 530 &dcmipp_inp_int_ops, &dcmipp_inp_ops, 531 NULL, NULL); 532 if (ret) { 533 kfree(inp); 534 return ERR_PTR(ret); 535 } 536 537 inp->dev = dev; 538 539 return &inp->ved; 540 } 541