1 // SPDX-License-Identifier: GPL-2.0
5 * Qualcomm MSM Camera Subsystem - CSIPHY Module
7 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
8 * Copyright (C) 2016-2018 Linaro Ltd.
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/interrupt.h>
14 #include <linux/kernel.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <media/media-entity.h>
19 #include <media/v4l2-device.h>
20 #include <media/v4l2-subdev.h>
22 #include "camss-csiphy.h"
25 #define MSM_CSIPHY_NAME "msm_csiphy"
27 struct csiphy_format
{
32 static const struct csiphy_format csiphy_formats_8x16
[] = {
33 { MEDIA_BUS_FMT_UYVY8_2X8
, 8 },
34 { MEDIA_BUS_FMT_VYUY8_2X8
, 8 },
35 { MEDIA_BUS_FMT_YUYV8_2X8
, 8 },
36 { MEDIA_BUS_FMT_YVYU8_2X8
, 8 },
37 { MEDIA_BUS_FMT_SBGGR8_1X8
, 8 },
38 { MEDIA_BUS_FMT_SGBRG8_1X8
, 8 },
39 { MEDIA_BUS_FMT_SGRBG8_1X8
, 8 },
40 { MEDIA_BUS_FMT_SRGGB8_1X8
, 8 },
41 { MEDIA_BUS_FMT_SBGGR10_1X10
, 10 },
42 { MEDIA_BUS_FMT_SGBRG10_1X10
, 10 },
43 { MEDIA_BUS_FMT_SGRBG10_1X10
, 10 },
44 { MEDIA_BUS_FMT_SRGGB10_1X10
, 10 },
45 { MEDIA_BUS_FMT_SBGGR12_1X12
, 12 },
46 { MEDIA_BUS_FMT_SGBRG12_1X12
, 12 },
47 { MEDIA_BUS_FMT_SGRBG12_1X12
, 12 },
48 { MEDIA_BUS_FMT_SRGGB12_1X12
, 12 },
49 { MEDIA_BUS_FMT_Y10_1X10
, 10 },
52 static const struct csiphy_format csiphy_formats_8x96
[] = {
53 { MEDIA_BUS_FMT_UYVY8_2X8
, 8 },
54 { MEDIA_BUS_FMT_VYUY8_2X8
, 8 },
55 { MEDIA_BUS_FMT_YUYV8_2X8
, 8 },
56 { MEDIA_BUS_FMT_YVYU8_2X8
, 8 },
57 { MEDIA_BUS_FMT_SBGGR8_1X8
, 8 },
58 { MEDIA_BUS_FMT_SGBRG8_1X8
, 8 },
59 { MEDIA_BUS_FMT_SGRBG8_1X8
, 8 },
60 { MEDIA_BUS_FMT_SRGGB8_1X8
, 8 },
61 { MEDIA_BUS_FMT_SBGGR10_1X10
, 10 },
62 { MEDIA_BUS_FMT_SGBRG10_1X10
, 10 },
63 { MEDIA_BUS_FMT_SGRBG10_1X10
, 10 },
64 { MEDIA_BUS_FMT_SRGGB10_1X10
, 10 },
65 { MEDIA_BUS_FMT_SBGGR12_1X12
, 12 },
66 { MEDIA_BUS_FMT_SGBRG12_1X12
, 12 },
67 { MEDIA_BUS_FMT_SGRBG12_1X12
, 12 },
68 { MEDIA_BUS_FMT_SRGGB12_1X12
, 12 },
69 { MEDIA_BUS_FMT_SBGGR14_1X14
, 14 },
70 { MEDIA_BUS_FMT_SGBRG14_1X14
, 14 },
71 { MEDIA_BUS_FMT_SGRBG14_1X14
, 14 },
72 { MEDIA_BUS_FMT_SRGGB14_1X14
, 14 },
73 { MEDIA_BUS_FMT_Y10_1X10
, 10 },
77 * csiphy_get_bpp - map media bus format to bits per pixel
78 * @formats: supported media bus formats array
79 * @nformats: size of @formats array
80 * @code: media bus format code
82 * Return number of bits per pixel
84 static u8
csiphy_get_bpp(const struct csiphy_format
*formats
,
85 unsigned int nformats
, u32 code
)
89 for (i
= 0; i
< nformats
; i
++)
90 if (code
== formats
[i
].code
)
91 return formats
[i
].bpp
;
93 WARN(1, "Unknown format\n");
95 return formats
[0].bpp
;
99 * csiphy_set_clock_rates - Calculate and set clock rates on CSIPHY module
100 * @csiphy: CSIPHY device
102 static int csiphy_set_clock_rates(struct csiphy_device
*csiphy
)
104 struct device
*dev
= csiphy
->camss
->dev
;
109 ret
= camss_get_pixel_clock(&csiphy
->subdev
.entity
, &pixel_clock
);
113 for (i
= 0; i
< csiphy
->nclocks
; i
++) {
114 struct camss_clock
*clock
= &csiphy
->clock
[i
];
116 if (!strcmp(clock
->name
, "csiphy0_timer") ||
117 !strcmp(clock
->name
, "csiphy1_timer") ||
118 !strcmp(clock
->name
, "csiphy2_timer")) {
119 u8 bpp
= csiphy_get_bpp(csiphy
->formats
,
121 csiphy
->fmt
[MSM_CSIPHY_PAD_SINK
].code
);
122 u8 num_lanes
= csiphy
->cfg
.csi2
->lane_cfg
.num_data
;
123 u64 min_rate
= pixel_clock
* bpp
/ (2 * num_lanes
* 4);
126 camss_add_clock_margin(&min_rate
);
128 for (j
= 0; j
< clock
->nfreqs
; j
++)
129 if (min_rate
< clock
->freq
[j
])
132 if (j
== clock
->nfreqs
) {
134 "Pixel clock is too high for CSIPHY\n");
138 /* if sensor pixel clock is not available */
139 /* set highest possible CSIPHY clock rate */
141 j
= clock
->nfreqs
- 1;
143 round_rate
= clk_round_rate(clock
->clk
, clock
->freq
[j
]);
144 if (round_rate
< 0) {
145 dev_err(dev
, "clk round rate failed: %ld\n",
150 csiphy
->timer_clk_rate
= round_rate
;
152 ret
= clk_set_rate(clock
->clk
, csiphy
->timer_clk_rate
);
154 dev_err(dev
, "clk set rate failed: %d\n", ret
);
164 * csiphy_set_power - Power on/off CSIPHY module
165 * @sd: CSIPHY V4L2 subdevice
166 * @on: Requested power state
168 * Return 0 on success or a negative error code otherwise
170 static int csiphy_set_power(struct v4l2_subdev
*sd
, int on
)
172 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
173 struct device
*dev
= csiphy
->camss
->dev
;
178 ret
= pm_runtime_get_sync(dev
);
182 ret
= csiphy_set_clock_rates(csiphy
);
184 pm_runtime_put_sync(dev
);
188 ret
= camss_enable_clocks(csiphy
->nclocks
, csiphy
->clock
, dev
);
190 pm_runtime_put_sync(dev
);
194 enable_irq(csiphy
->irq
);
196 csiphy
->ops
->reset(csiphy
);
198 csiphy
->ops
->hw_version_read(csiphy
, dev
);
200 disable_irq(csiphy
->irq
);
202 camss_disable_clocks(csiphy
->nclocks
, csiphy
->clock
);
204 pm_runtime_put_sync(dev
);
211 * csiphy_get_lane_mask - Calculate CSI2 lane mask configuration parameter
212 * @lane_cfg - CSI2 lane configuration
216 static u8
csiphy_get_lane_mask(struct csiphy_lanes_cfg
*lane_cfg
)
221 lane_mask
= 1 << lane_cfg
->clk
.pos
;
223 for (i
= 0; i
< lane_cfg
->num_data
; i
++)
224 lane_mask
|= 1 << lane_cfg
->data
[i
].pos
;
230 * csiphy_stream_on - Enable streaming on CSIPHY module
231 * @csiphy: CSIPHY device
233 * Helper function to enable streaming on CSIPHY module.
234 * Main configuration of CSIPHY module is also done here.
236 * Return 0 on success or a negative error code otherwise
238 static int csiphy_stream_on(struct csiphy_device
*csiphy
)
240 struct csiphy_config
*cfg
= &csiphy
->cfg
;
242 u8 lane_mask
= csiphy_get_lane_mask(&cfg
->csi2
->lane_cfg
);
243 u8 bpp
= csiphy_get_bpp(csiphy
->formats
, csiphy
->nformats
,
244 csiphy
->fmt
[MSM_CSIPHY_PAD_SINK
].code
);
248 ret
= camss_get_pixel_clock(&csiphy
->subdev
.entity
, &pixel_clock
);
250 dev_err(csiphy
->camss
->dev
,
251 "Cannot get CSI2 transmitter's pixel clock\n");
255 dev_err(csiphy
->camss
->dev
,
256 "Got pixel clock == 0, cannot continue\n");
260 val
= readl_relaxed(csiphy
->base_clk_mux
);
261 if (cfg
->combo_mode
&& (lane_mask
& 0x18) == 0x18) {
263 val
|= cfg
->csid_id
<< 4;
268 writel_relaxed(val
, csiphy
->base_clk_mux
);
271 csiphy
->ops
->lanes_enable(csiphy
, cfg
, pixel_clock
, bpp
, lane_mask
);
277 * csiphy_stream_off - Disable streaming on CSIPHY module
278 * @csiphy: CSIPHY device
280 * Helper function to disable streaming on CSIPHY module
282 static void csiphy_stream_off(struct csiphy_device
*csiphy
)
284 csiphy
->ops
->lanes_disable(csiphy
, &csiphy
->cfg
);
289 * csiphy_set_stream - Enable/disable streaming on CSIPHY module
290 * @sd: CSIPHY V4L2 subdevice
291 * @enable: Requested streaming state
293 * Return 0 on success or a negative error code otherwise
295 static int csiphy_set_stream(struct v4l2_subdev
*sd
, int enable
)
297 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
301 ret
= csiphy_stream_on(csiphy
);
303 csiphy_stream_off(csiphy
);
309 * __csiphy_get_format - Get pointer to format structure
310 * @csiphy: CSIPHY device
311 * @cfg: V4L2 subdev pad configuration
312 * @pad: pad from which format is requested
313 * @which: TRY or ACTIVE format
315 * Return pointer to TRY or ACTIVE format structure
317 static struct v4l2_mbus_framefmt
*
318 __csiphy_get_format(struct csiphy_device
*csiphy
,
319 struct v4l2_subdev_pad_config
*cfg
,
321 enum v4l2_subdev_format_whence which
)
323 if (which
== V4L2_SUBDEV_FORMAT_TRY
)
324 return v4l2_subdev_get_try_format(&csiphy
->subdev
, cfg
, pad
);
326 return &csiphy
->fmt
[pad
];
330 * csiphy_try_format - Handle try format by pad subdev method
331 * @csiphy: CSIPHY device
332 * @cfg: V4L2 subdev pad configuration
333 * @pad: pad on which format is requested
334 * @fmt: pointer to v4l2 format structure
335 * @which: wanted subdev format
337 static void csiphy_try_format(struct csiphy_device
*csiphy
,
338 struct v4l2_subdev_pad_config
*cfg
,
340 struct v4l2_mbus_framefmt
*fmt
,
341 enum v4l2_subdev_format_whence which
)
346 case MSM_CSIPHY_PAD_SINK
:
347 /* Set format on sink pad */
349 for (i
= 0; i
< csiphy
->nformats
; i
++)
350 if (fmt
->code
== csiphy
->formats
[i
].code
)
353 /* If not found, use UYVY as default */
354 if (i
>= csiphy
->nformats
)
355 fmt
->code
= MEDIA_BUS_FMT_UYVY8_2X8
;
357 fmt
->width
= clamp_t(u32
, fmt
->width
, 1, 8191);
358 fmt
->height
= clamp_t(u32
, fmt
->height
, 1, 8191);
360 fmt
->field
= V4L2_FIELD_NONE
;
361 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
365 case MSM_CSIPHY_PAD_SRC
:
366 /* Set and return a format same as sink pad */
368 *fmt
= *__csiphy_get_format(csiphy
, cfg
, MSM_CSID_PAD_SINK
,
376 * csiphy_enum_mbus_code - Handle pixel format enumeration
377 * @sd: CSIPHY V4L2 subdevice
378 * @cfg: V4L2 subdev pad configuration
379 * @code: pointer to v4l2_subdev_mbus_code_enum structure
380 * return -EINVAL or zero on success
382 static int csiphy_enum_mbus_code(struct v4l2_subdev
*sd
,
383 struct v4l2_subdev_pad_config
*cfg
,
384 struct v4l2_subdev_mbus_code_enum
*code
)
386 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
387 struct v4l2_mbus_framefmt
*format
;
389 if (code
->pad
== MSM_CSIPHY_PAD_SINK
) {
390 if (code
->index
>= csiphy
->nformats
)
393 code
->code
= csiphy
->formats
[code
->index
].code
;
398 format
= __csiphy_get_format(csiphy
, cfg
, MSM_CSIPHY_PAD_SINK
,
401 code
->code
= format
->code
;
408 * csiphy_enum_frame_size - Handle frame size enumeration
409 * @sd: CSIPHY V4L2 subdevice
410 * @cfg: V4L2 subdev pad configuration
411 * @fse: pointer to v4l2_subdev_frame_size_enum structure
412 * return -EINVAL or zero on success
414 static int csiphy_enum_frame_size(struct v4l2_subdev
*sd
,
415 struct v4l2_subdev_pad_config
*cfg
,
416 struct v4l2_subdev_frame_size_enum
*fse
)
418 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
419 struct v4l2_mbus_framefmt format
;
424 format
.code
= fse
->code
;
427 csiphy_try_format(csiphy
, cfg
, fse
->pad
, &format
, fse
->which
);
428 fse
->min_width
= format
.width
;
429 fse
->min_height
= format
.height
;
431 if (format
.code
!= fse
->code
)
434 format
.code
= fse
->code
;
437 csiphy_try_format(csiphy
, cfg
, fse
->pad
, &format
, fse
->which
);
438 fse
->max_width
= format
.width
;
439 fse
->max_height
= format
.height
;
445 * csiphy_get_format - Handle get format by pads subdev method
446 * @sd: CSIPHY V4L2 subdevice
447 * @cfg: V4L2 subdev pad configuration
448 * @fmt: pointer to v4l2 subdev format structure
450 * Return -EINVAL or zero on success
452 static int csiphy_get_format(struct v4l2_subdev
*sd
,
453 struct v4l2_subdev_pad_config
*cfg
,
454 struct v4l2_subdev_format
*fmt
)
456 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
457 struct v4l2_mbus_framefmt
*format
;
459 format
= __csiphy_get_format(csiphy
, cfg
, fmt
->pad
, fmt
->which
);
463 fmt
->format
= *format
;
469 * csiphy_set_format - Handle set format by pads subdev method
470 * @sd: CSIPHY V4L2 subdevice
471 * @cfg: V4L2 subdev pad configuration
472 * @fmt: pointer to v4l2 subdev format structure
474 * Return -EINVAL or zero on success
476 static int csiphy_set_format(struct v4l2_subdev
*sd
,
477 struct v4l2_subdev_pad_config
*cfg
,
478 struct v4l2_subdev_format
*fmt
)
480 struct csiphy_device
*csiphy
= v4l2_get_subdevdata(sd
);
481 struct v4l2_mbus_framefmt
*format
;
483 format
= __csiphy_get_format(csiphy
, cfg
, fmt
->pad
, fmt
->which
);
487 csiphy_try_format(csiphy
, cfg
, fmt
->pad
, &fmt
->format
, fmt
->which
);
488 *format
= fmt
->format
;
490 /* Propagate the format from sink to source */
491 if (fmt
->pad
== MSM_CSIPHY_PAD_SINK
) {
492 format
= __csiphy_get_format(csiphy
, cfg
, MSM_CSIPHY_PAD_SRC
,
495 *format
= fmt
->format
;
496 csiphy_try_format(csiphy
, cfg
, MSM_CSIPHY_PAD_SRC
, format
,
504 * csiphy_init_formats - Initialize formats on all pads
505 * @sd: CSIPHY V4L2 subdevice
506 * @fh: V4L2 subdev file handle
508 * Initialize all pad formats with default values.
510 * Return 0 on success or a negative error code otherwise
512 static int csiphy_init_formats(struct v4l2_subdev
*sd
,
513 struct v4l2_subdev_fh
*fh
)
515 struct v4l2_subdev_format format
= {
516 .pad
= MSM_CSIPHY_PAD_SINK
,
517 .which
= fh
? V4L2_SUBDEV_FORMAT_TRY
:
518 V4L2_SUBDEV_FORMAT_ACTIVE
,
520 .code
= MEDIA_BUS_FMT_UYVY8_2X8
,
526 return csiphy_set_format(sd
, fh
? fh
->pad
: NULL
, &format
);
530 * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources
531 * @csiphy: CSIPHY device
532 * @res: CSIPHY module resources table
533 * @id: CSIPHY module id
535 * Return 0 on success or a negative error code otherwise
537 int msm_csiphy_subdev_init(struct camss
*camss
,
538 struct csiphy_device
*csiphy
,
539 const struct resources
*res
, u8 id
)
541 struct device
*dev
= camss
->dev
;
542 struct platform_device
*pdev
= to_platform_device(dev
);
547 csiphy
->camss
= camss
;
549 csiphy
->cfg
.combo_mode
= 0;
551 if (camss
->version
== CAMSS_8x16
) {
552 csiphy
->ops
= &csiphy_ops_2ph_1_0
;
553 csiphy
->formats
= csiphy_formats_8x16
;
554 csiphy
->nformats
= ARRAY_SIZE(csiphy_formats_8x16
);
555 } else if (camss
->version
== CAMSS_8x96
) {
556 csiphy
->ops
= &csiphy_ops_3ph_1_0
;
557 csiphy
->formats
= csiphy_formats_8x96
;
558 csiphy
->nformats
= ARRAY_SIZE(csiphy_formats_8x96
);
565 r
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, res
->reg
[0]);
566 csiphy
->base
= devm_ioremap_resource(dev
, r
);
567 if (IS_ERR(csiphy
->base
)) {
568 dev_err(dev
, "could not map memory\n");
569 return PTR_ERR(csiphy
->base
);
572 r
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, res
->reg
[1]);
573 csiphy
->base_clk_mux
= devm_ioremap_resource(dev
, r
);
574 if (IS_ERR(csiphy
->base_clk_mux
)) {
575 dev_err(dev
, "could not map memory\n");
576 return PTR_ERR(csiphy
->base_clk_mux
);
581 r
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
,
584 dev_err(dev
, "missing IRQ\n");
588 csiphy
->irq
= r
->start
;
589 snprintf(csiphy
->irq_name
, sizeof(csiphy
->irq_name
), "%s_%s%d",
590 dev_name(dev
), MSM_CSIPHY_NAME
, csiphy
->id
);
592 ret
= devm_request_irq(dev
, csiphy
->irq
, csiphy
->ops
->isr
,
593 IRQF_TRIGGER_RISING
, csiphy
->irq_name
, csiphy
);
595 dev_err(dev
, "request_irq failed: %d\n", ret
);
599 disable_irq(csiphy
->irq
);
604 while (res
->clock
[csiphy
->nclocks
])
607 csiphy
->clock
= devm_kcalloc(dev
,
608 csiphy
->nclocks
, sizeof(*csiphy
->clock
),
613 for (i
= 0; i
< csiphy
->nclocks
; i
++) {
614 struct camss_clock
*clock
= &csiphy
->clock
[i
];
616 clock
->clk
= devm_clk_get(dev
, res
->clock
[i
]);
617 if (IS_ERR(clock
->clk
))
618 return PTR_ERR(clock
->clk
);
620 clock
->name
= res
->clock
[i
];
623 while (res
->clock_rate
[i
][clock
->nfreqs
])
626 if (!clock
->nfreqs
) {
631 clock
->freq
= devm_kcalloc(dev
,
633 sizeof(*clock
->freq
),
638 for (j
= 0; j
< clock
->nfreqs
; j
++)
639 clock
->freq
[j
] = res
->clock_rate
[i
][j
];
646 * csiphy_link_setup - Setup CSIPHY connections
647 * @entity: Pointer to media entity structure
648 * @local: Pointer to local pad
649 * @remote: Pointer to remote pad
652 * Rreturn 0 on success
654 static int csiphy_link_setup(struct media_entity
*entity
,
655 const struct media_pad
*local
,
656 const struct media_pad
*remote
, u32 flags
)
658 if ((local
->flags
& MEDIA_PAD_FL_SOURCE
) &&
659 (flags
& MEDIA_LNK_FL_ENABLED
)) {
660 struct v4l2_subdev
*sd
;
661 struct csiphy_device
*csiphy
;
662 struct csid_device
*csid
;
664 if (media_entity_remote_pad(local
))
667 sd
= media_entity_to_v4l2_subdev(entity
);
668 csiphy
= v4l2_get_subdevdata(sd
);
670 sd
= media_entity_to_v4l2_subdev(remote
->entity
);
671 csid
= v4l2_get_subdevdata(sd
);
673 csiphy
->cfg
.csid_id
= csid
->id
;
679 static const struct v4l2_subdev_core_ops csiphy_core_ops
= {
680 .s_power
= csiphy_set_power
,
683 static const struct v4l2_subdev_video_ops csiphy_video_ops
= {
684 .s_stream
= csiphy_set_stream
,
687 static const struct v4l2_subdev_pad_ops csiphy_pad_ops
= {
688 .enum_mbus_code
= csiphy_enum_mbus_code
,
689 .enum_frame_size
= csiphy_enum_frame_size
,
690 .get_fmt
= csiphy_get_format
,
691 .set_fmt
= csiphy_set_format
,
694 static const struct v4l2_subdev_ops csiphy_v4l2_ops
= {
695 .core
= &csiphy_core_ops
,
696 .video
= &csiphy_video_ops
,
697 .pad
= &csiphy_pad_ops
,
700 static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops
= {
701 .open
= csiphy_init_formats
,
704 static const struct media_entity_operations csiphy_media_ops
= {
705 .link_setup
= csiphy_link_setup
,
706 .link_validate
= v4l2_subdev_link_validate
,
710 * msm_csiphy_register_entity - Register subdev node for CSIPHY module
711 * @csiphy: CSIPHY device
712 * @v4l2_dev: V4L2 device
714 * Return 0 on success or a negative error code otherwise
716 int msm_csiphy_register_entity(struct csiphy_device
*csiphy
,
717 struct v4l2_device
*v4l2_dev
)
719 struct v4l2_subdev
*sd
= &csiphy
->subdev
;
720 struct media_pad
*pads
= csiphy
->pads
;
721 struct device
*dev
= csiphy
->camss
->dev
;
724 v4l2_subdev_init(sd
, &csiphy_v4l2_ops
);
725 sd
->internal_ops
= &csiphy_v4l2_internal_ops
;
726 sd
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
727 snprintf(sd
->name
, ARRAY_SIZE(sd
->name
), "%s%d",
728 MSM_CSIPHY_NAME
, csiphy
->id
);
729 v4l2_set_subdevdata(sd
, csiphy
);
731 ret
= csiphy_init_formats(sd
, NULL
);
733 dev_err(dev
, "Failed to init format: %d\n", ret
);
737 pads
[MSM_CSIPHY_PAD_SINK
].flags
= MEDIA_PAD_FL_SINK
;
738 pads
[MSM_CSIPHY_PAD_SRC
].flags
= MEDIA_PAD_FL_SOURCE
;
740 sd
->entity
.function
= MEDIA_ENT_F_IO_V4L
;
741 sd
->entity
.ops
= &csiphy_media_ops
;
742 ret
= media_entity_pads_init(&sd
->entity
, MSM_CSIPHY_PADS_NUM
, pads
);
744 dev_err(dev
, "Failed to init media entity: %d\n", ret
);
748 ret
= v4l2_device_register_subdev(v4l2_dev
, sd
);
750 dev_err(dev
, "Failed to register subdev: %d\n", ret
);
751 media_entity_cleanup(&sd
->entity
);
758 * msm_csiphy_unregister_entity - Unregister CSIPHY module subdev node
759 * @csiphy: CSIPHY device
761 void msm_csiphy_unregister_entity(struct csiphy_device
*csiphy
)
763 v4l2_device_unregister_subdev(&csiphy
->subdev
);
764 media_entity_cleanup(&csiphy
->subdev
.entity
);