xref: /linux/drivers/media/platform/qcom/camss/camss-csid.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1b873663bSTodor Tomov // SPDX-License-Identifier: GPL-2.0
2ec6859b2STodor Tomov /*
3ec6859b2STodor Tomov  * camss-csid.c
4ec6859b2STodor Tomov  *
5ec6859b2STodor Tomov  * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
6ec6859b2STodor Tomov  *
7ec6859b2STodor Tomov  * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
8ec6859b2STodor Tomov  * Copyright (C) 2015-2018 Linaro Ltd.
9ec6859b2STodor Tomov  */
10ec6859b2STodor Tomov #include <linux/clk.h>
11ec6859b2STodor Tomov #include <linux/completion.h>
12ec6859b2STodor Tomov #include <linux/interrupt.h>
133799eca5SArnd Bergmann #include <linux/io.h>
14ec6859b2STodor Tomov #include <linux/kernel.h>
15ec6859b2STodor Tomov #include <linux/of.h>
16ec6859b2STodor Tomov #include <linux/platform_device.h>
1702afa816STodor Tomov #include <linux/pm_runtime.h>
18ec6859b2STodor Tomov #include <linux/regulator/consumer.h>
19ec6859b2STodor Tomov #include <media/media-entity.h>
20ec6859b2STodor Tomov #include <media/v4l2-device.h>
21988b3ae3STodor Tomov #include <media/v4l2-event.h>
22ec6859b2STodor Tomov #include <media/v4l2-subdev.h>
23ec6859b2STodor Tomov 
24ec6859b2STodor Tomov #include "camss-csid.h"
25e19b14b1SRobert Foss #include "camss-csid-gen1.h"
26ec6859b2STodor Tomov #include "camss.h"
27ec6859b2STodor Tomov 
28b4436a18SJonathan Marek /* offset of CSID registers in VFE region for VFE 480 */
29b4436a18SJonathan Marek #define VFE_480_CSID_OFFSET 0x1200
30b4436a18SJonathan Marek #define VFE_480_LITE_CSID_OFFSET 0x200
31b4436a18SJonathan Marek 
32ec6859b2STodor Tomov #define MSM_CSID_NAME "msm_csid"
33ec6859b2STodor Tomov 
3476005817SRobert Foss const char * const csid_testgen_modes[] = {
3576005817SRobert Foss 	"Disabled",
3676005817SRobert Foss 	"Incrementing",
3776005817SRobert Foss 	"Alternating 0x55/0xAA",
3876005817SRobert Foss 	"All Zeros 0x00",
3976005817SRobert Foss 	"All Ones 0xFF",
4076005817SRobert Foss 	"Pseudo-random Data",
4176005817SRobert Foss 	"User Specified",
42eebe6d00SRobert Foss 	"Complex pattern",
43eebe6d00SRobert Foss 	"Color box",
44eebe6d00SRobert Foss 	"Color bars",
4576005817SRobert Foss 	NULL
46ec6859b2STodor Tomov };
47ec6859b2STodor Tomov 
4857cf33ccSRadoslav Tsvetkov static const struct csid_format_info formats_4_1[] = {
4957cf33ccSRadoslav Tsvetkov 	{
5057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_UYVY8_1X16,
5157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
5257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
5357cf33ccSRadoslav Tsvetkov 		8,
5457cf33ccSRadoslav Tsvetkov 		2,
5557cf33ccSRadoslav Tsvetkov 	},
5657cf33ccSRadoslav Tsvetkov 	{
5757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_VYUY8_1X16,
5857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
5957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
6057cf33ccSRadoslav Tsvetkov 		8,
6157cf33ccSRadoslav Tsvetkov 		2,
6257cf33ccSRadoslav Tsvetkov 	},
6357cf33ccSRadoslav Tsvetkov 	{
6457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YUYV8_1X16,
6557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
6657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
6757cf33ccSRadoslav Tsvetkov 		8,
6857cf33ccSRadoslav Tsvetkov 		2,
6957cf33ccSRadoslav Tsvetkov 	},
7057cf33ccSRadoslav Tsvetkov 	{
7157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YVYU8_1X16,
7257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
7357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
7457cf33ccSRadoslav Tsvetkov 		8,
7557cf33ccSRadoslav Tsvetkov 		2,
7657cf33ccSRadoslav Tsvetkov 	},
7757cf33ccSRadoslav Tsvetkov 	{
7857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR8_1X8,
7957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
8057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8157cf33ccSRadoslav Tsvetkov 		8,
8257cf33ccSRadoslav Tsvetkov 		1,
8357cf33ccSRadoslav Tsvetkov 	},
8457cf33ccSRadoslav Tsvetkov 	{
8557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG8_1X8,
8657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
8757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8857cf33ccSRadoslav Tsvetkov 		8,
8957cf33ccSRadoslav Tsvetkov 		1,
9057cf33ccSRadoslav Tsvetkov 	},
9157cf33ccSRadoslav Tsvetkov 	{
9257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG8_1X8,
9357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
9457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
9557cf33ccSRadoslav Tsvetkov 		8,
9657cf33ccSRadoslav Tsvetkov 		1,
9757cf33ccSRadoslav Tsvetkov 	},
9857cf33ccSRadoslav Tsvetkov 	{
9957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB8_1X8,
10057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
10157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
10257cf33ccSRadoslav Tsvetkov 		8,
10357cf33ccSRadoslav Tsvetkov 		1,
10457cf33ccSRadoslav Tsvetkov 	},
10557cf33ccSRadoslav Tsvetkov 	{
10657cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR10_1X10,
10757cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
10857cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10957cf33ccSRadoslav Tsvetkov 		10,
11057cf33ccSRadoslav Tsvetkov 		1,
11157cf33ccSRadoslav Tsvetkov 	},
11257cf33ccSRadoslav Tsvetkov 	{
11357cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG10_1X10,
11457cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
11557cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
11657cf33ccSRadoslav Tsvetkov 		10,
11757cf33ccSRadoslav Tsvetkov 		1,
11857cf33ccSRadoslav Tsvetkov 	},
11957cf33ccSRadoslav Tsvetkov 	{
12057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG10_1X10,
12157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
12257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
12357cf33ccSRadoslav Tsvetkov 		10,
12457cf33ccSRadoslav Tsvetkov 		1,
12557cf33ccSRadoslav Tsvetkov 	},
12657cf33ccSRadoslav Tsvetkov 	{
12757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB10_1X10,
12857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
12957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
13057cf33ccSRadoslav Tsvetkov 		10,
13157cf33ccSRadoslav Tsvetkov 		1,
13257cf33ccSRadoslav Tsvetkov 	},
13357cf33ccSRadoslav Tsvetkov 	{
13457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR12_1X12,
13557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
13657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
13757cf33ccSRadoslav Tsvetkov 		12,
13857cf33ccSRadoslav Tsvetkov 		1,
13957cf33ccSRadoslav Tsvetkov 	},
14057cf33ccSRadoslav Tsvetkov 	{
14157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG12_1X12,
14257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
14357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
14457cf33ccSRadoslav Tsvetkov 		12,
14557cf33ccSRadoslav Tsvetkov 		1,
14657cf33ccSRadoslav Tsvetkov 	},
14757cf33ccSRadoslav Tsvetkov 	{
14857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG12_1X12,
14957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
15057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
15157cf33ccSRadoslav Tsvetkov 		12,
15257cf33ccSRadoslav Tsvetkov 		1,
15357cf33ccSRadoslav Tsvetkov 	},
15457cf33ccSRadoslav Tsvetkov 	{
15557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB12_1X12,
15657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
15757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
15857cf33ccSRadoslav Tsvetkov 		12,
15957cf33ccSRadoslav Tsvetkov 		1,
16057cf33ccSRadoslav Tsvetkov 	},
16157cf33ccSRadoslav Tsvetkov 	{
16257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_Y10_1X10,
16357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
16457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
16557cf33ccSRadoslav Tsvetkov 		10,
16657cf33ccSRadoslav Tsvetkov 		1,
16757cf33ccSRadoslav Tsvetkov 	},
16857cf33ccSRadoslav Tsvetkov };
16957cf33ccSRadoslav Tsvetkov 
17057cf33ccSRadoslav Tsvetkov static const struct csid_format_info formats_4_7[] = {
17157cf33ccSRadoslav Tsvetkov 	{
17257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_UYVY8_1X16,
17357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
17457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
17557cf33ccSRadoslav Tsvetkov 		8,
17657cf33ccSRadoslav Tsvetkov 		2,
17757cf33ccSRadoslav Tsvetkov 	},
17857cf33ccSRadoslav Tsvetkov 	{
17957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_VYUY8_1X16,
18057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
18157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
18257cf33ccSRadoslav Tsvetkov 		8,
18357cf33ccSRadoslav Tsvetkov 		2,
18457cf33ccSRadoslav Tsvetkov 	},
18557cf33ccSRadoslav Tsvetkov 	{
18657cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YUYV8_1X16,
18757cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
18857cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
18957cf33ccSRadoslav Tsvetkov 		8,
19057cf33ccSRadoslav Tsvetkov 		2,
19157cf33ccSRadoslav Tsvetkov 	},
19257cf33ccSRadoslav Tsvetkov 	{
19357cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YVYU8_1X16,
19457cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
19557cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
19657cf33ccSRadoslav Tsvetkov 		8,
19757cf33ccSRadoslav Tsvetkov 		2,
19857cf33ccSRadoslav Tsvetkov 	},
19957cf33ccSRadoslav Tsvetkov 	{
20057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR8_1X8,
20157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
20257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
20357cf33ccSRadoslav Tsvetkov 		8,
20457cf33ccSRadoslav Tsvetkov 		1,
20557cf33ccSRadoslav Tsvetkov 	},
20657cf33ccSRadoslav Tsvetkov 	{
20757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG8_1X8,
20857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
20957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
21057cf33ccSRadoslav Tsvetkov 		8,
21157cf33ccSRadoslav Tsvetkov 		1,
21257cf33ccSRadoslav Tsvetkov 	},
21357cf33ccSRadoslav Tsvetkov 	{
21457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG8_1X8,
21557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
21657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
21757cf33ccSRadoslav Tsvetkov 		8,
21857cf33ccSRadoslav Tsvetkov 		1,
21957cf33ccSRadoslav Tsvetkov 	},
22057cf33ccSRadoslav Tsvetkov 	{
22157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB8_1X8,
22257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
22357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
22457cf33ccSRadoslav Tsvetkov 		8,
22557cf33ccSRadoslav Tsvetkov 		1,
22657cf33ccSRadoslav Tsvetkov 	},
22757cf33ccSRadoslav Tsvetkov 	{
22857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR10_1X10,
22957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
23057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
23157cf33ccSRadoslav Tsvetkov 		10,
23257cf33ccSRadoslav Tsvetkov 		1,
23357cf33ccSRadoslav Tsvetkov 	},
23457cf33ccSRadoslav Tsvetkov 	{
23557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG10_1X10,
23657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
23757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
23857cf33ccSRadoslav Tsvetkov 		10,
23957cf33ccSRadoslav Tsvetkov 		1,
24057cf33ccSRadoslav Tsvetkov 	},
24157cf33ccSRadoslav Tsvetkov 	{
24257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG10_1X10,
24357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
24457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
24557cf33ccSRadoslav Tsvetkov 		10,
24657cf33ccSRadoslav Tsvetkov 		1,
24757cf33ccSRadoslav Tsvetkov 	},
24857cf33ccSRadoslav Tsvetkov 	{
24957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB10_1X10,
25057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
25157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
25257cf33ccSRadoslav Tsvetkov 		10,
25357cf33ccSRadoslav Tsvetkov 		1,
25457cf33ccSRadoslav Tsvetkov 	},
25557cf33ccSRadoslav Tsvetkov 	{
25657cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR12_1X12,
25757cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
25857cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
25957cf33ccSRadoslav Tsvetkov 		12,
26057cf33ccSRadoslav Tsvetkov 		1,
26157cf33ccSRadoslav Tsvetkov 	},
26257cf33ccSRadoslav Tsvetkov 	{
26357cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG12_1X12,
26457cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
26557cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
26657cf33ccSRadoslav Tsvetkov 		12,
26757cf33ccSRadoslav Tsvetkov 		1,
26857cf33ccSRadoslav Tsvetkov 	},
26957cf33ccSRadoslav Tsvetkov 	{
27057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG12_1X12,
27157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
27257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
27357cf33ccSRadoslav Tsvetkov 		12,
27457cf33ccSRadoslav Tsvetkov 		1,
27557cf33ccSRadoslav Tsvetkov 	},
27657cf33ccSRadoslav Tsvetkov 	{
27757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB12_1X12,
27857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
27957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
28057cf33ccSRadoslav Tsvetkov 		12,
28157cf33ccSRadoslav Tsvetkov 		1,
28257cf33ccSRadoslav Tsvetkov 	},
28357cf33ccSRadoslav Tsvetkov 	{
28457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR14_1X14,
28557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
28657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
28757cf33ccSRadoslav Tsvetkov 		14,
28857cf33ccSRadoslav Tsvetkov 		1,
28957cf33ccSRadoslav Tsvetkov 	},
29057cf33ccSRadoslav Tsvetkov 	{
29157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG14_1X14,
29257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
29357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
29457cf33ccSRadoslav Tsvetkov 		14,
29557cf33ccSRadoslav Tsvetkov 		1,
29657cf33ccSRadoslav Tsvetkov 	},
29757cf33ccSRadoslav Tsvetkov 	{
29857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG14_1X14,
29957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
30057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
30157cf33ccSRadoslav Tsvetkov 		14,
30257cf33ccSRadoslav Tsvetkov 		1,
30357cf33ccSRadoslav Tsvetkov 	},
30457cf33ccSRadoslav Tsvetkov 	{
30557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB14_1X14,
30657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
30757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
30857cf33ccSRadoslav Tsvetkov 		14,
30957cf33ccSRadoslav Tsvetkov 		1,
31057cf33ccSRadoslav Tsvetkov 	},
31157cf33ccSRadoslav Tsvetkov 	{
31257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_Y10_1X10,
31357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
31457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
31557cf33ccSRadoslav Tsvetkov 		10,
31657cf33ccSRadoslav Tsvetkov 		1,
31757cf33ccSRadoslav Tsvetkov 	},
31857cf33ccSRadoslav Tsvetkov };
31957cf33ccSRadoslav Tsvetkov 
32057cf33ccSRadoslav Tsvetkov static const struct csid_format_info formats_gen2[] = {
32157cf33ccSRadoslav Tsvetkov 	{
32257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_UYVY8_1X16,
32357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
32457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
32557cf33ccSRadoslav Tsvetkov 		8,
32657cf33ccSRadoslav Tsvetkov 		2,
32757cf33ccSRadoslav Tsvetkov 	},
32857cf33ccSRadoslav Tsvetkov 	{
32957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_VYUY8_1X16,
33057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
33157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
33257cf33ccSRadoslav Tsvetkov 		8,
33357cf33ccSRadoslav Tsvetkov 		2,
33457cf33ccSRadoslav Tsvetkov 	},
33557cf33ccSRadoslav Tsvetkov 	{
33657cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YUYV8_1X16,
33757cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
33857cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
33957cf33ccSRadoslav Tsvetkov 		8,
34057cf33ccSRadoslav Tsvetkov 		2,
34157cf33ccSRadoslav Tsvetkov 	},
34257cf33ccSRadoslav Tsvetkov 	{
34357cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_YVYU8_1X16,
34457cf33ccSRadoslav Tsvetkov 		DATA_TYPE_YUV422_8BIT,
34557cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
34657cf33ccSRadoslav Tsvetkov 		8,
34757cf33ccSRadoslav Tsvetkov 		2,
34857cf33ccSRadoslav Tsvetkov 	},
34957cf33ccSRadoslav Tsvetkov 	{
35057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR8_1X8,
35157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
35257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
35357cf33ccSRadoslav Tsvetkov 		8,
35457cf33ccSRadoslav Tsvetkov 		1,
35557cf33ccSRadoslav Tsvetkov 	},
35657cf33ccSRadoslav Tsvetkov 	{
35757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG8_1X8,
35857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
35957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
36057cf33ccSRadoslav Tsvetkov 		8,
36157cf33ccSRadoslav Tsvetkov 		1,
36257cf33ccSRadoslav Tsvetkov 	},
36357cf33ccSRadoslav Tsvetkov 	{
36457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG8_1X8,
36557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
36657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
36757cf33ccSRadoslav Tsvetkov 		8,
36857cf33ccSRadoslav Tsvetkov 		1,
36957cf33ccSRadoslav Tsvetkov 	},
37057cf33ccSRadoslav Tsvetkov 	{
37157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB8_1X8,
37257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
37357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
37457cf33ccSRadoslav Tsvetkov 		8,
37557cf33ccSRadoslav Tsvetkov 		1,
37657cf33ccSRadoslav Tsvetkov 	},
37757cf33ccSRadoslav Tsvetkov 	{
37857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR10_1X10,
37957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
38057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
38157cf33ccSRadoslav Tsvetkov 		10,
38257cf33ccSRadoslav Tsvetkov 		1,
38357cf33ccSRadoslav Tsvetkov 	},
38457cf33ccSRadoslav Tsvetkov 	{
38557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG10_1X10,
38657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
38757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
38857cf33ccSRadoslav Tsvetkov 		10,
38957cf33ccSRadoslav Tsvetkov 		1,
39057cf33ccSRadoslav Tsvetkov 	},
39157cf33ccSRadoslav Tsvetkov 	{
39257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG10_1X10,
39357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
39457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
39557cf33ccSRadoslav Tsvetkov 		10,
39657cf33ccSRadoslav Tsvetkov 		1,
39757cf33ccSRadoslav Tsvetkov 	},
39857cf33ccSRadoslav Tsvetkov 	{
39957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB10_1X10,
40057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
40157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
40257cf33ccSRadoslav Tsvetkov 		10,
40357cf33ccSRadoslav Tsvetkov 		1,
40457cf33ccSRadoslav Tsvetkov 	},
40557cf33ccSRadoslav Tsvetkov 	{
40657cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_Y8_1X8,
40757cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_8BIT,
40857cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
40957cf33ccSRadoslav Tsvetkov 		8,
41057cf33ccSRadoslav Tsvetkov 		1,
41157cf33ccSRadoslav Tsvetkov 	},
41257cf33ccSRadoslav Tsvetkov 	{
41357cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_Y10_1X10,
41457cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_10BIT,
41557cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
41657cf33ccSRadoslav Tsvetkov 		10,
41757cf33ccSRadoslav Tsvetkov 		1,
41857cf33ccSRadoslav Tsvetkov 	},
41957cf33ccSRadoslav Tsvetkov 	{
42057cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR12_1X12,
42157cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
42257cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
42357cf33ccSRadoslav Tsvetkov 		12,
42457cf33ccSRadoslav Tsvetkov 		1,
42557cf33ccSRadoslav Tsvetkov 	},
42657cf33ccSRadoslav Tsvetkov 	{
42757cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG12_1X12,
42857cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
42957cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
43057cf33ccSRadoslav Tsvetkov 		12,
43157cf33ccSRadoslav Tsvetkov 		1,
43257cf33ccSRadoslav Tsvetkov 	},
43357cf33ccSRadoslav Tsvetkov 	{
43457cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG12_1X12,
43557cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
43657cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
43757cf33ccSRadoslav Tsvetkov 		12,
43857cf33ccSRadoslav Tsvetkov 		1,
43957cf33ccSRadoslav Tsvetkov 	},
44057cf33ccSRadoslav Tsvetkov 	{
44157cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB12_1X12,
44257cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_12BIT,
44357cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
44457cf33ccSRadoslav Tsvetkov 		12,
44557cf33ccSRadoslav Tsvetkov 		1,
44657cf33ccSRadoslav Tsvetkov 	},
44757cf33ccSRadoslav Tsvetkov 	{
44857cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SBGGR14_1X14,
44957cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
45057cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
45157cf33ccSRadoslav Tsvetkov 		14,
45257cf33ccSRadoslav Tsvetkov 		1,
45357cf33ccSRadoslav Tsvetkov 	},
45457cf33ccSRadoslav Tsvetkov 	{
45557cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGBRG14_1X14,
45657cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
45757cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
45857cf33ccSRadoslav Tsvetkov 		14,
45957cf33ccSRadoslav Tsvetkov 		1,
46057cf33ccSRadoslav Tsvetkov 	},
46157cf33ccSRadoslav Tsvetkov 	{
46257cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SGRBG14_1X14,
46357cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
46457cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
46557cf33ccSRadoslav Tsvetkov 		14,
46657cf33ccSRadoslav Tsvetkov 		1,
46757cf33ccSRadoslav Tsvetkov 	},
46857cf33ccSRadoslav Tsvetkov 	{
46957cf33ccSRadoslav Tsvetkov 		MEDIA_BUS_FMT_SRGGB14_1X14,
47057cf33ccSRadoslav Tsvetkov 		DATA_TYPE_RAW_14BIT,
47157cf33ccSRadoslav Tsvetkov 		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
47257cf33ccSRadoslav Tsvetkov 		14,
47357cf33ccSRadoslav Tsvetkov 		1,
47457cf33ccSRadoslav Tsvetkov 	},
47557cf33ccSRadoslav Tsvetkov };
47657cf33ccSRadoslav Tsvetkov 
47757cf33ccSRadoslav Tsvetkov const struct csid_formats csid_formats_4_1 = {
47857cf33ccSRadoslav Tsvetkov 	.nformats = ARRAY_SIZE(formats_4_1),
47957cf33ccSRadoslav Tsvetkov 	.formats = formats_4_1
48057cf33ccSRadoslav Tsvetkov };
48157cf33ccSRadoslav Tsvetkov 
48257cf33ccSRadoslav Tsvetkov const struct csid_formats csid_formats_4_7 = {
48357cf33ccSRadoslav Tsvetkov 	.nformats = ARRAY_SIZE(formats_4_7),
48457cf33ccSRadoslav Tsvetkov 	.formats = formats_4_7
48557cf33ccSRadoslav Tsvetkov };
48657cf33ccSRadoslav Tsvetkov 
48757cf33ccSRadoslav Tsvetkov const struct csid_formats csid_formats_gen2 = {
48857cf33ccSRadoslav Tsvetkov 	.nformats = ARRAY_SIZE(formats_gen2),
48957cf33ccSRadoslav Tsvetkov 	.formats = formats_gen2
49057cf33ccSRadoslav Tsvetkov };
49157cf33ccSRadoslav Tsvetkov 
csid_find_code(u32 * codes,unsigned int ncodes,unsigned int match_format_idx,u32 match_code)49276005817SRobert Foss u32 csid_find_code(u32 *codes, unsigned int ncodes,
49376005817SRobert Foss 		   unsigned int match_format_idx, u32 match_code)
4947e37f47fSTodor Tomov {
4957e37f47fSTodor Tomov 	int i;
4967e37f47fSTodor Tomov 
49776005817SRobert Foss 	if (!match_code && (match_format_idx >= ncodes))
4987e37f47fSTodor Tomov 		return 0;
4997e37f47fSTodor Tomov 
50076005817SRobert Foss 	for (i = 0; i < ncodes; i++)
50176005817SRobert Foss 		if (match_code) {
50276005817SRobert Foss 			if (codes[i] == match_code)
50376005817SRobert Foss 				return match_code;
5047e37f47fSTodor Tomov 		} else {
50576005817SRobert Foss 			if (i == match_format_idx)
50676005817SRobert Foss 				return codes[i];
5077e37f47fSTodor Tomov 		}
5087e37f47fSTodor Tomov 
50976005817SRobert Foss 	return codes[0];
5107e37f47fSTodor Tomov }
5117e37f47fSTodor Tomov 
csid_get_fmt_entry(const struct csid_format_info * formats,unsigned int nformats,u32 code)51257cf33ccSRadoslav Tsvetkov const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats,
51376005817SRobert Foss 						  unsigned int nformats,
514cba3819dSTodor Tomov 						  u32 code)
515ec6859b2STodor Tomov {
516ec6859b2STodor Tomov 	unsigned int i;
517ec6859b2STodor Tomov 
51876005817SRobert Foss 	for (i = 0; i < nformats; i++)
519cba3819dSTodor Tomov 		if (code == formats[i].code)
520cba3819dSTodor Tomov 			return &formats[i];
521ec6859b2STodor Tomov 
522ec6859b2STodor Tomov 	WARN(1, "Unknown format\n");
523ec6859b2STodor Tomov 
524cba3819dSTodor Tomov 	return &formats[0];
525ec6859b2STodor Tomov }
526ec6859b2STodor Tomov 
527ec6859b2STodor Tomov /*
528ec6859b2STodor Tomov  * csid_set_clock_rates - Calculate and set clock rates on CSID module
529ec6859b2STodor Tomov  * @csiphy: CSID device
530ec6859b2STodor Tomov  */
csid_set_clock_rates(struct csid_device * csid)531ec6859b2STodor Tomov static int csid_set_clock_rates(struct csid_device *csid)
532ec6859b2STodor Tomov {
5339c3e59deSTodor Tomov 	struct device *dev = csid->camss->dev;
53457cf33ccSRadoslav Tsvetkov 	const struct csid_format_info *fmt;
53578c2cc28SAndrey Konovalov 	s64 link_freq;
536ec6859b2STodor Tomov 	int i, j;
537ec6859b2STodor Tomov 	int ret;
538ec6859b2STodor Tomov 
53957cf33ccSRadoslav Tsvetkov 	fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats,
54078c2cc28SAndrey Konovalov 				 csid->fmt[MSM_CSIPHY_PAD_SINK].code);
54178c2cc28SAndrey Konovalov 	link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp,
54278c2cc28SAndrey Konovalov 					csid->phy.lane_cnt);
54378c2cc28SAndrey Konovalov 	if (link_freq < 0)
54478c2cc28SAndrey Konovalov 		link_freq = 0;
545ec6859b2STodor Tomov 
546ec6859b2STodor Tomov 	for (i = 0; i < csid->nclocks; i++) {
547ec6859b2STodor Tomov 		struct camss_clock *clock = &csid->clock[i];
548ec6859b2STodor Tomov 
549ec6859b2STodor Tomov 		if (!strcmp(clock->name, "csi0") ||
5509c3e59deSTodor Tomov 		    !strcmp(clock->name, "csi1") ||
5519c3e59deSTodor Tomov 		    !strcmp(clock->name, "csi2") ||
5529c3e59deSTodor Tomov 		    !strcmp(clock->name, "csi3")) {
55378c2cc28SAndrey Konovalov 			u64 min_rate = link_freq / 4;
554ec6859b2STodor Tomov 			long rate;
555ec6859b2STodor Tomov 
556ec6859b2STodor Tomov 			camss_add_clock_margin(&min_rate);
557ec6859b2STodor Tomov 
558ec6859b2STodor Tomov 			for (j = 0; j < clock->nfreqs; j++)
559ec6859b2STodor Tomov 				if (min_rate < clock->freq[j])
560ec6859b2STodor Tomov 					break;
561ec6859b2STodor Tomov 
562ec6859b2STodor Tomov 			if (j == clock->nfreqs) {
563ec6859b2STodor Tomov 				dev_err(dev,
564ec6859b2STodor Tomov 					"Pixel clock is too high for CSID\n");
565ec6859b2STodor Tomov 				return -EINVAL;
566ec6859b2STodor Tomov 			}
567ec6859b2STodor Tomov 
568ec6859b2STodor Tomov 			/* if sensor pixel clock is not available */
569ec6859b2STodor Tomov 			/* set highest possible CSID clock rate */
570ec6859b2STodor Tomov 			if (min_rate == 0)
571ec6859b2STodor Tomov 				j = clock->nfreqs - 1;
572ec6859b2STodor Tomov 
573ec6859b2STodor Tomov 			rate = clk_round_rate(clock->clk, clock->freq[j]);
574ec6859b2STodor Tomov 			if (rate < 0) {
575ec6859b2STodor Tomov 				dev_err(dev, "clk round rate failed: %ld\n",
576ec6859b2STodor Tomov 					rate);
577ec6859b2STodor Tomov 				return -EINVAL;
578ec6859b2STodor Tomov 			}
579ec6859b2STodor Tomov 
580ec6859b2STodor Tomov 			ret = clk_set_rate(clock->clk, rate);
581ec6859b2STodor Tomov 			if (ret < 0) {
582ec6859b2STodor Tomov 				dev_err(dev, "clk set rate failed: %d\n", ret);
583ec6859b2STodor Tomov 				return ret;
584ec6859b2STodor Tomov 			}
585eebe6d00SRobert Foss 		} else if (clock->nfreqs) {
586eebe6d00SRobert Foss 			clk_set_rate(clock->clk, clock->freq[0]);
587ec6859b2STodor Tomov 		}
588ec6859b2STodor Tomov 	}
589ec6859b2STodor Tomov 
590ec6859b2STodor Tomov 	return 0;
591ec6859b2STodor Tomov }
592ec6859b2STodor Tomov 
593ec6859b2STodor Tomov /*
594ec6859b2STodor Tomov  * csid_set_power - Power on/off CSID module
595ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
596ec6859b2STodor Tomov  * @on: Requested power state
597ec6859b2STodor Tomov  *
598ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
599ec6859b2STodor Tomov  */
csid_set_power(struct v4l2_subdev * sd,int on)600ec6859b2STodor Tomov static int csid_set_power(struct v4l2_subdev *sd, int on)
601ec6859b2STodor Tomov {
602ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
603c5af8db8SBryan O'Donoghue 	struct camss *camss = csid->camss;
604c5af8db8SBryan O'Donoghue 	struct device *dev = camss->dev;
6050d814017SBryan O'Donoghue 	int ret = 0;
606ec6859b2STodor Tomov 
607ec6859b2STodor Tomov 	if (on) {
608b2c2715eSBryan O'Donoghue 		/*
609b2c2715eSBryan O'Donoghue 		 * From SDM845 onwards, the VFE needs to be powered on before
610b2c2715eSBryan O'Donoghue 		 * switching on the CSID. Do so unconditionally, as there is no
611b2c2715eSBryan O'Donoghue 		 * drawback in following the same powering order on older SoCs.
612b2c2715eSBryan O'Donoghue 		 */
613*b1e6eef5SMilen Mitkov 		ret = csid->res->parent_dev_ops->get(camss, csid->id);
614c5af8db8SBryan O'Donoghue 		if (ret < 0)
615c5af8db8SBryan O'Donoghue 			return ret;
616c5af8db8SBryan O'Donoghue 
61709dfb36cSMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(dev);
61809dfb36cSMauro Carvalho Chehab 		if (ret < 0)
619ec6859b2STodor Tomov 			return ret;
620ec6859b2STodor Tomov 
6210d814017SBryan O'Donoghue 		ret = regulator_bulk_enable(csid->num_supplies,
6220d814017SBryan O'Donoghue 					    csid->supplies);
62302afa816STodor Tomov 		if (ret < 0) {
62402afa816STodor Tomov 			pm_runtime_put_sync(dev);
62502afa816STodor Tomov 			return ret;
62602afa816STodor Tomov 		}
62702afa816STodor Tomov 
628ec6859b2STodor Tomov 		ret = csid_set_clock_rates(csid);
629ec6859b2STodor Tomov 		if (ret < 0) {
6300d814017SBryan O'Donoghue 			regulator_bulk_disable(csid->num_supplies,
6310d814017SBryan O'Donoghue 					       csid->supplies);
63202afa816STodor Tomov 			pm_runtime_put_sync(dev);
633ec6859b2STodor Tomov 			return ret;
634ec6859b2STodor Tomov 		}
635ec6859b2STodor Tomov 
636ec6859b2STodor Tomov 		ret = camss_enable_clocks(csid->nclocks, csid->clock, dev);
637ec6859b2STodor Tomov 		if (ret < 0) {
6380d814017SBryan O'Donoghue 			regulator_bulk_disable(csid->num_supplies,
6390d814017SBryan O'Donoghue 					       csid->supplies);
64002afa816STodor Tomov 			pm_runtime_put_sync(dev);
641ec6859b2STodor Tomov 			return ret;
642ec6859b2STodor Tomov 		}
643ec6859b2STodor Tomov 
6443c4ed72aSMilen Mitkov 		csid->phy.need_vc_update = true;
6453c4ed72aSMilen Mitkov 
646ec6859b2STodor Tomov 		enable_irq(csid->irq);
647ec6859b2STodor Tomov 
648ae44829aSRadoslav Tsvetkov 		ret = csid->res->hw_ops->reset(csid);
649ec6859b2STodor Tomov 		if (ret < 0) {
650ec6859b2STodor Tomov 			disable_irq(csid->irq);
651ec6859b2STodor Tomov 			camss_disable_clocks(csid->nclocks, csid->clock);
6520d814017SBryan O'Donoghue 			regulator_bulk_disable(csid->num_supplies,
6530d814017SBryan O'Donoghue 					       csid->supplies);
65402afa816STodor Tomov 			pm_runtime_put_sync(dev);
655ec6859b2STodor Tomov 			return ret;
656ec6859b2STodor Tomov 		}
657ec6859b2STodor Tomov 
658ae44829aSRadoslav Tsvetkov 		csid->res->hw_ops->hw_version(csid);
659ec6859b2STodor Tomov 	} else {
660ec6859b2STodor Tomov 		disable_irq(csid->irq);
661ec6859b2STodor Tomov 		camss_disable_clocks(csid->nclocks, csid->clock);
6620d814017SBryan O'Donoghue 		regulator_bulk_disable(csid->num_supplies,
6630d814017SBryan O'Donoghue 				       csid->supplies);
66402afa816STodor Tomov 		pm_runtime_put_sync(dev);
665*b1e6eef5SMilen Mitkov 		csid->res->parent_dev_ops->put(camss, csid->id);
666ec6859b2STodor Tomov 	}
667ec6859b2STodor Tomov 
668ec6859b2STodor Tomov 	return ret;
669ec6859b2STodor Tomov }
670ec6859b2STodor Tomov 
671ec6859b2STodor Tomov /*
672ec6859b2STodor Tomov  * csid_set_stream - Enable/disable streaming on CSID module
673ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
674ec6859b2STodor Tomov  * @enable: Requested streaming state
675ec6859b2STodor Tomov  *
676ec6859b2STodor Tomov  * Main configuration of CSID module is also done here.
677ec6859b2STodor Tomov  *
678ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
679ec6859b2STodor Tomov  */
csid_set_stream(struct v4l2_subdev * sd,int enable)680ec6859b2STodor Tomov static int csid_set_stream(struct v4l2_subdev *sd, int enable)
681ec6859b2STodor Tomov {
682ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
683ec6859b2STodor Tomov 	int ret;
684ec6859b2STodor Tomov 
68576005817SRobert Foss 	if (enable) {
686ec6859b2STodor Tomov 		ret = v4l2_ctrl_handler_setup(&csid->ctrls);
687ec6859b2STodor Tomov 		if (ret < 0) {
6889c3e59deSTodor Tomov 			dev_err(csid->camss->dev,
689ec6859b2STodor Tomov 				"could not sync v4l2 controls: %d\n", ret);
690ec6859b2STodor Tomov 			return ret;
691ec6859b2STodor Tomov 		}
692ec6859b2STodor Tomov 
69376005817SRobert Foss 		if (!csid->testgen.enabled &&
694b2e44430SLaurent Pinchart 		    !media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK]))
695ec6859b2STodor Tomov 			return -ENOLINK;
696ec6859b2STodor Tomov 	}
697ec6859b2STodor Tomov 
6983c4ed72aSMilen Mitkov 	if (csid->phy.need_vc_update) {
699ae44829aSRadoslav Tsvetkov 		csid->res->hw_ops->configure_stream(csid, enable);
7003c4ed72aSMilen Mitkov 		csid->phy.need_vc_update = false;
7013c4ed72aSMilen Mitkov 	}
702ec6859b2STodor Tomov 
703ec6859b2STodor Tomov 	return 0;
704ec6859b2STodor Tomov }
705ec6859b2STodor Tomov 
706ec6859b2STodor Tomov /*
707ec6859b2STodor Tomov  * __csid_get_format - Get pointer to format structure
708ec6859b2STodor Tomov  * @csid: CSID device
709c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
710ec6859b2STodor Tomov  * @pad: pad from which format is requested
711ec6859b2STodor Tomov  * @which: TRY or ACTIVE format
712ec6859b2STodor Tomov  *
713ec6859b2STodor Tomov  * Return pointer to TRY or ACTIVE format structure
714ec6859b2STodor Tomov  */
715ec6859b2STodor Tomov static struct v4l2_mbus_framefmt *
__csid_get_format(struct csid_device * csid,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)716ec6859b2STodor Tomov __csid_get_format(struct csid_device *csid,
7170d346d2aSTomi Valkeinen 		  struct v4l2_subdev_state *sd_state,
718ec6859b2STodor Tomov 		  unsigned int pad,
719ec6859b2STodor Tomov 		  enum v4l2_subdev_format_whence which)
720ec6859b2STodor Tomov {
721ec6859b2STodor Tomov 	if (which == V4L2_SUBDEV_FORMAT_TRY)
722bc0e8d91SSakari Ailus 		return v4l2_subdev_state_get_format(sd_state, pad);
723ec6859b2STodor Tomov 
724ec6859b2STodor Tomov 	return &csid->fmt[pad];
725ec6859b2STodor Tomov }
726ec6859b2STodor Tomov 
727ec6859b2STodor Tomov /*
728ec6859b2STodor Tomov  * csid_try_format - Handle try format by pad subdev method
729ec6859b2STodor Tomov  * @csid: CSID device
730c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
731ec6859b2STodor Tomov  * @pad: pad on which format is requested
732ec6859b2STodor Tomov  * @fmt: pointer to v4l2 format structure
733ec6859b2STodor Tomov  * @which: wanted subdev format
734ec6859b2STodor Tomov  */
csid_try_format(struct csid_device * csid,struct v4l2_subdev_state * sd_state,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)735ec6859b2STodor Tomov static void csid_try_format(struct csid_device *csid,
7360d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
737ec6859b2STodor Tomov 			    unsigned int pad,
738ec6859b2STodor Tomov 			    struct v4l2_mbus_framefmt *fmt,
739ec6859b2STodor Tomov 			    enum v4l2_subdev_format_whence which)
740ec6859b2STodor Tomov {
741ec6859b2STodor Tomov 	unsigned int i;
742ec6859b2STodor Tomov 
743ec6859b2STodor Tomov 	switch (pad) {
744ec6859b2STodor Tomov 	case MSM_CSID_PAD_SINK:
745ec6859b2STodor Tomov 		/* Set format on sink pad */
746ec6859b2STodor Tomov 
74757cf33ccSRadoslav Tsvetkov 		for (i = 0; i < csid->res->formats->nformats; i++)
74857cf33ccSRadoslav Tsvetkov 			if (fmt->code == csid->res->formats->formats[i].code)
749ec6859b2STodor Tomov 				break;
750ec6859b2STodor Tomov 
751ec6859b2STodor Tomov 		/* If not found, use UYVY as default */
75257cf33ccSRadoslav Tsvetkov 		if (i >= csid->res->formats->nformats)
75389936bfbSMartin Dørum 			fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
754ec6859b2STodor Tomov 
755ec6859b2STodor Tomov 		fmt->width = clamp_t(u32, fmt->width, 1, 8191);
756ec6859b2STodor Tomov 		fmt->height = clamp_t(u32, fmt->height, 1, 8191);
757ec6859b2STodor Tomov 
758ec6859b2STodor Tomov 		fmt->field = V4L2_FIELD_NONE;
759ec6859b2STodor Tomov 		fmt->colorspace = V4L2_COLORSPACE_SRGB;
760ec6859b2STodor Tomov 
761ec6859b2STodor Tomov 		break;
762ec6859b2STodor Tomov 
763ec6859b2STodor Tomov 	case MSM_CSID_PAD_SRC:
764ec6859b2STodor Tomov 		if (csid->testgen_mode->cur.val == 0) {
7657e37f47fSTodor Tomov 			/* Test generator is disabled, */
7667e37f47fSTodor Tomov 			/* keep pad formats in sync */
7677e37f47fSTodor Tomov 			u32 code = fmt->code;
768ec6859b2STodor Tomov 
7690d346d2aSTomi Valkeinen 			*fmt = *__csid_get_format(csid, sd_state,
770ec6859b2STodor Tomov 						      MSM_CSID_PAD_SINK, which);
771ae44829aSRadoslav Tsvetkov 			fmt->code = csid->res->hw_ops->src_pad_code(csid, fmt->code, 0, code);
772ec6859b2STodor Tomov 		} else {
773ec6859b2STodor Tomov 			/* Test generator is enabled, set format on source */
774ec6859b2STodor Tomov 			/* pad to allow test generator usage */
775ec6859b2STodor Tomov 
77657cf33ccSRadoslav Tsvetkov 			for (i = 0; i < csid->res->formats->nformats; i++)
77757cf33ccSRadoslav Tsvetkov 				if (csid->res->formats->formats[i].code == fmt->code)
778ec6859b2STodor Tomov 					break;
779ec6859b2STodor Tomov 
780ec6859b2STodor Tomov 			/* If not found, use UYVY as default */
78157cf33ccSRadoslav Tsvetkov 			if (i >= csid->res->formats->nformats)
78289936bfbSMartin Dørum 				fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
783ec6859b2STodor Tomov 
784ec6859b2STodor Tomov 			fmt->width = clamp_t(u32, fmt->width, 1, 8191);
785ec6859b2STodor Tomov 			fmt->height = clamp_t(u32, fmt->height, 1, 8191);
786ec6859b2STodor Tomov 
787ec6859b2STodor Tomov 			fmt->field = V4L2_FIELD_NONE;
788ec6859b2STodor Tomov 		}
789ec6859b2STodor Tomov 		break;
790ec6859b2STodor Tomov 	}
791ec6859b2STodor Tomov 
792ec6859b2STodor Tomov 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
793ec6859b2STodor Tomov }
794ec6859b2STodor Tomov 
795ec6859b2STodor Tomov /*
796ec6859b2STodor Tomov  * csid_enum_mbus_code - Handle pixel format enumeration
797ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
798c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
799ec6859b2STodor Tomov  * @code: pointer to v4l2_subdev_mbus_code_enum structure
800ec6859b2STodor Tomov  * return -EINVAL or zero on success
801ec6859b2STodor Tomov  */
csid_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)802ec6859b2STodor Tomov static int csid_enum_mbus_code(struct v4l2_subdev *sd,
8030d346d2aSTomi Valkeinen 			       struct v4l2_subdev_state *sd_state,
804ec6859b2STodor Tomov 			       struct v4l2_subdev_mbus_code_enum *code)
805ec6859b2STodor Tomov {
806ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
807ec6859b2STodor Tomov 
808ec6859b2STodor Tomov 	if (code->pad == MSM_CSID_PAD_SINK) {
80957cf33ccSRadoslav Tsvetkov 		if (code->index >= csid->res->formats->nformats)
810ec6859b2STodor Tomov 			return -EINVAL;
811ec6859b2STodor Tomov 
81257cf33ccSRadoslav Tsvetkov 		code->code = csid->res->formats->formats[code->index].code;
813ec6859b2STodor Tomov 	} else {
814ec6859b2STodor Tomov 		if (csid->testgen_mode->cur.val == 0) {
8157e37f47fSTodor Tomov 			struct v4l2_mbus_framefmt *sink_fmt;
816ec6859b2STodor Tomov 
8170d346d2aSTomi Valkeinen 			sink_fmt = __csid_get_format(csid, sd_state,
8187e37f47fSTodor Tomov 						     MSM_CSID_PAD_SINK,
819ec6859b2STodor Tomov 						     code->which);
820ec6859b2STodor Tomov 
821ae44829aSRadoslav Tsvetkov 			code->code = csid->res->hw_ops->src_pad_code(csid, sink_fmt->code,
8227e37f47fSTodor Tomov 								     code->index, 0);
8237e37f47fSTodor Tomov 			if (!code->code)
8247e37f47fSTodor Tomov 				return -EINVAL;
825ec6859b2STodor Tomov 		} else {
82657cf33ccSRadoslav Tsvetkov 			if (code->index >= csid->res->formats->nformats)
827ec6859b2STodor Tomov 				return -EINVAL;
828ec6859b2STodor Tomov 
82957cf33ccSRadoslav Tsvetkov 			code->code = csid->res->formats->formats[code->index].code;
830ec6859b2STodor Tomov 		}
831ec6859b2STodor Tomov 	}
832ec6859b2STodor Tomov 
833ec6859b2STodor Tomov 	return 0;
834ec6859b2STodor Tomov }
835ec6859b2STodor Tomov 
836ec6859b2STodor Tomov /*
837ec6859b2STodor Tomov  * csid_enum_frame_size - Handle frame size enumeration
838ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
839c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
840ec6859b2STodor Tomov  * @fse: pointer to v4l2_subdev_frame_size_enum structure
841ec6859b2STodor Tomov  * return -EINVAL or zero on success
842ec6859b2STodor Tomov  */
csid_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)843ec6859b2STodor Tomov static int csid_enum_frame_size(struct v4l2_subdev *sd,
8440d346d2aSTomi Valkeinen 				struct v4l2_subdev_state *sd_state,
845ec6859b2STodor Tomov 				struct v4l2_subdev_frame_size_enum *fse)
846ec6859b2STodor Tomov {
847ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
848ec6859b2STodor Tomov 	struct v4l2_mbus_framefmt format;
849ec6859b2STodor Tomov 
850ec6859b2STodor Tomov 	if (fse->index != 0)
851ec6859b2STodor Tomov 		return -EINVAL;
852ec6859b2STodor Tomov 
853ec6859b2STodor Tomov 	format.code = fse->code;
854ec6859b2STodor Tomov 	format.width = 1;
855ec6859b2STodor Tomov 	format.height = 1;
8560d346d2aSTomi Valkeinen 	csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
857ec6859b2STodor Tomov 	fse->min_width = format.width;
858ec6859b2STodor Tomov 	fse->min_height = format.height;
859ec6859b2STodor Tomov 
860ec6859b2STodor Tomov 	if (format.code != fse->code)
861ec6859b2STodor Tomov 		return -EINVAL;
862ec6859b2STodor Tomov 
863ec6859b2STodor Tomov 	format.code = fse->code;
864ec6859b2STodor Tomov 	format.width = -1;
865ec6859b2STodor Tomov 	format.height = -1;
8660d346d2aSTomi Valkeinen 	csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
867ec6859b2STodor Tomov 	fse->max_width = format.width;
868ec6859b2STodor Tomov 	fse->max_height = format.height;
869ec6859b2STodor Tomov 
870ec6859b2STodor Tomov 	return 0;
871ec6859b2STodor Tomov }
872ec6859b2STodor Tomov 
873ec6859b2STodor Tomov /*
874ec6859b2STodor Tomov  * csid_get_format - Handle get format by pads subdev method
875ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
876c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
877ec6859b2STodor Tomov  * @fmt: pointer to v4l2 subdev format structure
878ec6859b2STodor Tomov  *
879ec6859b2STodor Tomov  * Return -EINVAL or zero on success
880ec6859b2STodor Tomov  */
csid_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)881ec6859b2STodor Tomov static int csid_get_format(struct v4l2_subdev *sd,
8820d346d2aSTomi Valkeinen 			   struct v4l2_subdev_state *sd_state,
883ec6859b2STodor Tomov 			   struct v4l2_subdev_format *fmt)
884ec6859b2STodor Tomov {
885ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
886ec6859b2STodor Tomov 	struct v4l2_mbus_framefmt *format;
887ec6859b2STodor Tomov 
8880d346d2aSTomi Valkeinen 	format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
889ec6859b2STodor Tomov 	if (format == NULL)
890ec6859b2STodor Tomov 		return -EINVAL;
891ec6859b2STodor Tomov 
892ec6859b2STodor Tomov 	fmt->format = *format;
893ec6859b2STodor Tomov 
894ec6859b2STodor Tomov 	return 0;
895ec6859b2STodor Tomov }
896ec6859b2STodor Tomov 
897ec6859b2STodor Tomov /*
898ec6859b2STodor Tomov  * csid_set_format - Handle set format by pads subdev method
899ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
900c1d96814SLaurent Pinchart  * @sd_state: V4L2 subdev state
901ec6859b2STodor Tomov  * @fmt: pointer to v4l2 subdev format structure
902ec6859b2STodor Tomov  *
903ec6859b2STodor Tomov  * Return -EINVAL or zero on success
904ec6859b2STodor Tomov  */
csid_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)905ec6859b2STodor Tomov static int csid_set_format(struct v4l2_subdev *sd,
9060d346d2aSTomi Valkeinen 			   struct v4l2_subdev_state *sd_state,
907ec6859b2STodor Tomov 			   struct v4l2_subdev_format *fmt)
908ec6859b2STodor Tomov {
909ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
910ec6859b2STodor Tomov 	struct v4l2_mbus_framefmt *format;
9113c4ed72aSMilen Mitkov 	int i;
912ec6859b2STodor Tomov 
9130d346d2aSTomi Valkeinen 	format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
914ec6859b2STodor Tomov 	if (format == NULL)
915ec6859b2STodor Tomov 		return -EINVAL;
916ec6859b2STodor Tomov 
9170d346d2aSTomi Valkeinen 	csid_try_format(csid, sd_state, fmt->pad, &fmt->format, fmt->which);
918ec6859b2STodor Tomov 	*format = fmt->format;
919ec6859b2STodor Tomov 
9203c4ed72aSMilen Mitkov 	/* Propagate the format from sink to source pads */
921ec6859b2STodor Tomov 	if (fmt->pad == MSM_CSID_PAD_SINK) {
9223c4ed72aSMilen Mitkov 		for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i) {
9233c4ed72aSMilen Mitkov 			format = __csid_get_format(csid, sd_state, i, fmt->which);
924ec6859b2STodor Tomov 
925ec6859b2STodor Tomov 			*format = fmt->format;
9263c4ed72aSMilen Mitkov 			csid_try_format(csid, sd_state, i, format, fmt->which);
9273c4ed72aSMilen Mitkov 		}
928ec6859b2STodor Tomov 	}
929ec6859b2STodor Tomov 
930ec6859b2STodor Tomov 	return 0;
931ec6859b2STodor Tomov }
932ec6859b2STodor Tomov 
933ec6859b2STodor Tomov /*
934ec6859b2STodor Tomov  * csid_init_formats - Initialize formats on all pads
935ec6859b2STodor Tomov  * @sd: CSID V4L2 subdevice
936ec6859b2STodor Tomov  * @fh: V4L2 subdev file handle
937ec6859b2STodor Tomov  *
938ec6859b2STodor Tomov  * Initialize all pad formats with default values.
939ec6859b2STodor Tomov  *
940ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
941ec6859b2STodor Tomov  */
csid_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)942ec6859b2STodor Tomov static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
943ec6859b2STodor Tomov {
944ec6859b2STodor Tomov 	struct v4l2_subdev_format format = {
945ec6859b2STodor Tomov 		.pad = MSM_CSID_PAD_SINK,
946ec6859b2STodor Tomov 		.which = fh ? V4L2_SUBDEV_FORMAT_TRY :
947ec6859b2STodor Tomov 			      V4L2_SUBDEV_FORMAT_ACTIVE,
948ec6859b2STodor Tomov 		.format = {
94989936bfbSMartin Dørum 			.code = MEDIA_BUS_FMT_UYVY8_1X16,
950ec6859b2STodor Tomov 			.width = 1920,
951ec6859b2STodor Tomov 			.height = 1080
952ec6859b2STodor Tomov 		}
953ec6859b2STodor Tomov 	};
954ec6859b2STodor Tomov 
9550d346d2aSTomi Valkeinen 	return csid_set_format(sd, fh ? fh->state : NULL, &format);
956ec6859b2STodor Tomov }
957ec6859b2STodor Tomov 
958ec6859b2STodor Tomov /*
959ec6859b2STodor Tomov  * csid_set_test_pattern - Set test generator's pattern mode
960ec6859b2STodor Tomov  * @csid: CSID device
961ec6859b2STodor Tomov  * @value: desired test pattern mode
962ec6859b2STodor Tomov  *
963ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
964ec6859b2STodor Tomov  */
csid_set_test_pattern(struct csid_device * csid,s32 value)965ec6859b2STodor Tomov static int csid_set_test_pattern(struct csid_device *csid, s32 value)
966ec6859b2STodor Tomov {
967ec6859b2STodor Tomov 	struct csid_testgen_config *tg = &csid->testgen;
968ec6859b2STodor Tomov 
969ec6859b2STodor Tomov 	/* If CSID is linked to CSIPHY, do not allow to enable test generator */
970b2e44430SLaurent Pinchart 	if (value && media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK]))
971ec6859b2STodor Tomov 		return -EBUSY;
972ec6859b2STodor Tomov 
973ec6859b2STodor Tomov 	tg->enabled = !!value;
974ec6859b2STodor Tomov 
975ae44829aSRadoslav Tsvetkov 	return csid->res->hw_ops->configure_testgen_pattern(csid, value);
976ec6859b2STodor Tomov }
977ec6859b2STodor Tomov 
978ec6859b2STodor Tomov /*
979ec6859b2STodor Tomov  * csid_s_ctrl - Handle set control subdev method
980ec6859b2STodor Tomov  * @ctrl: pointer to v4l2 control structure
981ec6859b2STodor Tomov  *
982ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
983ec6859b2STodor Tomov  */
csid_s_ctrl(struct v4l2_ctrl * ctrl)984ec6859b2STodor Tomov static int csid_s_ctrl(struct v4l2_ctrl *ctrl)
985ec6859b2STodor Tomov {
986ec6859b2STodor Tomov 	struct csid_device *csid = container_of(ctrl->handler,
987ec6859b2STodor Tomov 						struct csid_device, ctrls);
988ec6859b2STodor Tomov 	int ret = -EINVAL;
989ec6859b2STodor Tomov 
990ec6859b2STodor Tomov 	switch (ctrl->id) {
991ec6859b2STodor Tomov 	case V4L2_CID_TEST_PATTERN:
992ec6859b2STodor Tomov 		ret = csid_set_test_pattern(csid, ctrl->val);
993ec6859b2STodor Tomov 		break;
994ec6859b2STodor Tomov 	}
995ec6859b2STodor Tomov 
996ec6859b2STodor Tomov 	return ret;
997ec6859b2STodor Tomov }
998ec6859b2STodor Tomov 
999ec6859b2STodor Tomov static const struct v4l2_ctrl_ops csid_ctrl_ops = {
1000ec6859b2STodor Tomov 	.s_ctrl = csid_s_ctrl,
1001ec6859b2STodor Tomov };
1002ec6859b2STodor Tomov 
1003ec6859b2STodor Tomov /*
1004ec6859b2STodor Tomov  * msm_csid_subdev_init - Initialize CSID device structure and resources
1005ec6859b2STodor Tomov  * @csid: CSID device
1006ec6859b2STodor Tomov  * @res: CSID module resources table
1007ec6859b2STodor Tomov  * @id: CSID module id
1008ec6859b2STodor Tomov  *
1009ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
1010ec6859b2STodor Tomov  */
msm_csid_subdev_init(struct camss * camss,struct csid_device * csid,const struct camss_subdev_resources * res,u8 id)10119c3e59deSTodor Tomov int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
10121643b787SBryan O'Donoghue 			 const struct camss_subdev_resources *res, u8 id)
1013ec6859b2STodor Tomov {
10149c3e59deSTodor Tomov 	struct device *dev = camss->dev;
1015ec6859b2STodor Tomov 	struct platform_device *pdev = to_platform_device(dev);
1016ec6859b2STodor Tomov 	int i, j;
1017ec6859b2STodor Tomov 	int ret;
1018ec6859b2STodor Tomov 
10199c3e59deSTodor Tomov 	csid->camss = camss;
1020ec6859b2STodor Tomov 	csid->id = id;
1021ae44829aSRadoslav Tsvetkov 	csid->res = &res->csid;
1022ec6859b2STodor Tomov 
1023*b1e6eef5SMilen Mitkov 	if (dev_WARN_ONCE(dev, !csid->res->parent_dev_ops,
1024*b1e6eef5SMilen Mitkov 			  "Error: CSID depends on VFE/IFE device ops!\n")) {
1025*b1e6eef5SMilen Mitkov 		return -EINVAL;
1026*b1e6eef5SMilen Mitkov 	}
1027*b1e6eef5SMilen Mitkov 
1028ae44829aSRadoslav Tsvetkov 	csid->res->hw_ops->subdev_init(csid);
1029cba3819dSTodor Tomov 
1030ec6859b2STodor Tomov 	/* Memory */
1031ec6859b2STodor Tomov 
10325900b051SBryan O'Donoghue 	if (camss->res->version == CAMSS_8250) {
1033b4436a18SJonathan Marek 		/* for titan 480, CSID registers are inside the VFE region,
1034b4436a18SJonathan Marek 		 * between the VFE "top" and "bus" registers. this requires
1035b4436a18SJonathan Marek 		 * VFE to be initialized before CSID
1036b4436a18SJonathan Marek 		 */
1037b4436a18SJonathan Marek 		if (id >= 2) /* VFE/CSID lite */
1038*b1e6eef5SMilen Mitkov 			csid->base = csid->res->parent_dev_ops->get_base_address(camss, id)
1039*b1e6eef5SMilen Mitkov 				+ VFE_480_LITE_CSID_OFFSET;
1040b4436a18SJonathan Marek 		else
1041*b1e6eef5SMilen Mitkov 			csid->base = csid->res->parent_dev_ops->get_base_address(camss, id)
1042*b1e6eef5SMilen Mitkov 				 + VFE_480_CSID_OFFSET;
1043b4436a18SJonathan Marek 	} else {
1044414e0a64Sdingsenjie 		csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
10456c0ed6d4SYang Yingliang 		if (IS_ERR(csid->base))
1046ec6859b2STodor Tomov 			return PTR_ERR(csid->base);
1047b4436a18SJonathan Marek 	}
1048ec6859b2STodor Tomov 
1049ec6859b2STodor Tomov 	/* Interrupt */
1050ec6859b2STodor Tomov 
1051b416be3aSLad Prabhakar 	ret = platform_get_irq_byname(pdev, res->interrupt[0]);
1052b416be3aSLad Prabhakar 	if (ret < 0)
1053b416be3aSLad Prabhakar 		return ret;
1054ec6859b2STodor Tomov 
1055b416be3aSLad Prabhakar 	csid->irq = ret;
1056ec6859b2STodor Tomov 	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
1057ec6859b2STodor Tomov 		 dev_name(dev), MSM_CSID_NAME, csid->id);
1058ae44829aSRadoslav Tsvetkov 	ret = devm_request_irq(dev, csid->irq, csid->res->hw_ops->isr,
105914480e8dSTian Tao 			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
106014480e8dSTian Tao 			       csid->irq_name, csid);
1061ec6859b2STodor Tomov 	if (ret < 0) {
1062ec6859b2STodor Tomov 		dev_err(dev, "request_irq failed: %d\n", ret);
1063ec6859b2STodor Tomov 		return ret;
1064ec6859b2STodor Tomov 	}
1065ec6859b2STodor Tomov 
1066ec6859b2STodor Tomov 	/* Clocks */
1067ec6859b2STodor Tomov 
1068ec6859b2STodor Tomov 	csid->nclocks = 0;
1069ec6859b2STodor Tomov 	while (res->clock[csid->nclocks])
1070ec6859b2STodor Tomov 		csid->nclocks++;
1071ec6859b2STodor Tomov 
1072ec6859b2STodor Tomov 	csid->clock = devm_kcalloc(dev, csid->nclocks, sizeof(*csid->clock),
1073ec6859b2STodor Tomov 				    GFP_KERNEL);
1074ec6859b2STodor Tomov 	if (!csid->clock)
1075ec6859b2STodor Tomov 		return -ENOMEM;
1076ec6859b2STodor Tomov 
1077ec6859b2STodor Tomov 	for (i = 0; i < csid->nclocks; i++) {
1078ec6859b2STodor Tomov 		struct camss_clock *clock = &csid->clock[i];
1079ec6859b2STodor Tomov 
1080ec6859b2STodor Tomov 		clock->clk = devm_clk_get(dev, res->clock[i]);
1081ec6859b2STodor Tomov 		if (IS_ERR(clock->clk))
1082ec6859b2STodor Tomov 			return PTR_ERR(clock->clk);
1083ec6859b2STodor Tomov 
1084ec6859b2STodor Tomov 		clock->name = res->clock[i];
1085ec6859b2STodor Tomov 
1086ec6859b2STodor Tomov 		clock->nfreqs = 0;
1087ec6859b2STodor Tomov 		while (res->clock_rate[i][clock->nfreqs])
1088ec6859b2STodor Tomov 			clock->nfreqs++;
1089ec6859b2STodor Tomov 
1090ec6859b2STodor Tomov 		if (!clock->nfreqs) {
1091ec6859b2STodor Tomov 			clock->freq = NULL;
1092ec6859b2STodor Tomov 			continue;
1093ec6859b2STodor Tomov 		}
1094ec6859b2STodor Tomov 
1095ec6859b2STodor Tomov 		clock->freq = devm_kcalloc(dev,
1096ec6859b2STodor Tomov 					   clock->nfreqs,
1097ec6859b2STodor Tomov 					   sizeof(*clock->freq),
1098ec6859b2STodor Tomov 					   GFP_KERNEL);
1099ec6859b2STodor Tomov 		if (!clock->freq)
1100ec6859b2STodor Tomov 			return -ENOMEM;
1101ec6859b2STodor Tomov 
1102ec6859b2STodor Tomov 		for (j = 0; j < clock->nfreqs; j++)
1103ec6859b2STodor Tomov 			clock->freq[j] = res->clock_rate[i][j];
1104ec6859b2STodor Tomov 	}
1105ec6859b2STodor Tomov 
1106ec6859b2STodor Tomov 	/* Regulator */
11070d814017SBryan O'Donoghue 	for (i = 0; i < ARRAY_SIZE(res->regulators); i++) {
11080d814017SBryan O'Donoghue 		if (res->regulators[i])
11090d814017SBryan O'Donoghue 			csid->num_supplies++;
1110ec6859b2STodor Tomov 	}
1111ec6859b2STodor Tomov 
11120d814017SBryan O'Donoghue 	if (csid->num_supplies) {
11130d814017SBryan O'Donoghue 		csid->supplies = devm_kmalloc_array(camss->dev,
11140d814017SBryan O'Donoghue 						    csid->num_supplies,
11154c25384dSYang Yingliang 						    sizeof(*csid->supplies),
11160d814017SBryan O'Donoghue 						    GFP_KERNEL);
11170d814017SBryan O'Donoghue 		if (!csid->supplies)
11180d814017SBryan O'Donoghue 			return -ENOMEM;
11190d814017SBryan O'Donoghue 	}
11200d814017SBryan O'Donoghue 
11210d814017SBryan O'Donoghue 	for (i = 0; i < csid->num_supplies; i++)
11220d814017SBryan O'Donoghue 		csid->supplies[i].supply = res->regulators[i];
11230d814017SBryan O'Donoghue 
11240d814017SBryan O'Donoghue 	ret = devm_regulator_bulk_get(camss->dev, csid->num_supplies,
11250d814017SBryan O'Donoghue 				      csid->supplies);
11260d814017SBryan O'Donoghue 	if (ret)
11270d814017SBryan O'Donoghue 		return ret;
11280d814017SBryan O'Donoghue 
1129ec6859b2STodor Tomov 	init_completion(&csid->reset_complete);
1130ec6859b2STodor Tomov 
1131ec6859b2STodor Tomov 	return 0;
1132ec6859b2STodor Tomov }
1133ec6859b2STodor Tomov 
1134ec6859b2STodor Tomov /*
1135ec6859b2STodor Tomov  * msm_csid_get_csid_id - Get CSID HW module id
1136ec6859b2STodor Tomov  * @entity: Pointer to CSID media entity structure
1137ec6859b2STodor Tomov  * @id: Return CSID HW module id here
1138ec6859b2STodor Tomov  */
msm_csid_get_csid_id(struct media_entity * entity,u8 * id)1139ec6859b2STodor Tomov void msm_csid_get_csid_id(struct media_entity *entity, u8 *id)
1140ec6859b2STodor Tomov {
1141ec6859b2STodor Tomov 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1142ec6859b2STodor Tomov 	struct csid_device *csid = v4l2_get_subdevdata(sd);
1143ec6859b2STodor Tomov 
1144ec6859b2STodor Tomov 	*id = csid->id;
1145ec6859b2STodor Tomov }
1146ec6859b2STodor Tomov 
1147ec6859b2STodor Tomov /*
1148ec6859b2STodor Tomov  * csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter
1149ec6859b2STodor Tomov  * @lane_cfg - CSI2 lane configuration
1150ec6859b2STodor Tomov  *
1151ec6859b2STodor Tomov  * Return lane assign
1152ec6859b2STodor Tomov  */
csid_get_lane_assign(struct csiphy_lanes_cfg * lane_cfg)1153ec6859b2STodor Tomov static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg)
1154ec6859b2STodor Tomov {
1155ec6859b2STodor Tomov 	u32 lane_assign = 0;
1156ec6859b2STodor Tomov 	int i;
1157ec6859b2STodor Tomov 
1158ec6859b2STodor Tomov 	for (i = 0; i < lane_cfg->num_data; i++)
1159ec6859b2STodor Tomov 		lane_assign |= lane_cfg->data[i].pos << (i * 4);
1160ec6859b2STodor Tomov 
1161ec6859b2STodor Tomov 	return lane_assign;
1162ec6859b2STodor Tomov }
1163ec6859b2STodor Tomov 
1164ec6859b2STodor Tomov /*
1165ec6859b2STodor Tomov  * csid_link_setup - Setup CSID connections
1166ec6859b2STodor Tomov  * @entity: Pointer to media entity structure
1167ec6859b2STodor Tomov  * @local: Pointer to local pad
1168ec6859b2STodor Tomov  * @remote: Pointer to remote pad
1169ec6859b2STodor Tomov  * @flags: Link flags
1170ec6859b2STodor Tomov  *
1171ec6859b2STodor Tomov  * Return 0 on success
1172ec6859b2STodor Tomov  */
csid_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)1173ec6859b2STodor Tomov static int csid_link_setup(struct media_entity *entity,
1174ec6859b2STodor Tomov 			   const struct media_pad *local,
1175ec6859b2STodor Tomov 			   const struct media_pad *remote, u32 flags)
1176ec6859b2STodor Tomov {
1177ec6859b2STodor Tomov 	if (flags & MEDIA_LNK_FL_ENABLED)
1178b2e44430SLaurent Pinchart 		if (media_pad_remote_pad_first(local))
1179ec6859b2STodor Tomov 			return -EBUSY;
1180ec6859b2STodor Tomov 
1181ec6859b2STodor Tomov 	if ((local->flags & MEDIA_PAD_FL_SINK) &&
1182ec6859b2STodor Tomov 	    (flags & MEDIA_LNK_FL_ENABLED)) {
1183ec6859b2STodor Tomov 		struct v4l2_subdev *sd;
1184ec6859b2STodor Tomov 		struct csid_device *csid;
1185ec6859b2STodor Tomov 		struct csiphy_device *csiphy;
1186ec6859b2STodor Tomov 		struct csiphy_lanes_cfg *lane_cfg;
1187ec6859b2STodor Tomov 
1188ec6859b2STodor Tomov 		sd = media_entity_to_v4l2_subdev(entity);
1189ec6859b2STodor Tomov 		csid = v4l2_get_subdevdata(sd);
1190ec6859b2STodor Tomov 
1191ec6859b2STodor Tomov 		/* If test generator is enabled */
1192ec6859b2STodor Tomov 		/* do not allow a link from CSIPHY to CSID */
1193ec6859b2STodor Tomov 		if (csid->testgen_mode->cur.val != 0)
1194ec6859b2STodor Tomov 			return -EBUSY;
1195ec6859b2STodor Tomov 
1196ec6859b2STodor Tomov 		sd = media_entity_to_v4l2_subdev(remote->entity);
1197ec6859b2STodor Tomov 		csiphy = v4l2_get_subdevdata(sd);
1198ec6859b2STodor Tomov 
1199ec6859b2STodor Tomov 		/* If a sensor is not linked to CSIPHY */
1200ec6859b2STodor Tomov 		/* do no allow a link from CSIPHY to CSID */
1201ec6859b2STodor Tomov 		if (!csiphy->cfg.csi2)
1202ec6859b2STodor Tomov 			return -EPERM;
1203ec6859b2STodor Tomov 
1204ec6859b2STodor Tomov 		csid->phy.csiphy_id = csiphy->id;
1205ec6859b2STodor Tomov 
1206ec6859b2STodor Tomov 		lane_cfg = &csiphy->cfg.csi2->lane_cfg;
1207ec6859b2STodor Tomov 		csid->phy.lane_cnt = lane_cfg->num_data;
1208ec6859b2STodor Tomov 		csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
12093c4ed72aSMilen Mitkov 	}
12103c4ed72aSMilen Mitkov 	/* Decide which virtual channels to enable based on which source pads are enabled */
12113c4ed72aSMilen Mitkov 	if (local->flags & MEDIA_PAD_FL_SOURCE) {
12123c4ed72aSMilen Mitkov 		struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
12133c4ed72aSMilen Mitkov 		struct csid_device *csid = v4l2_get_subdevdata(sd);
12143c4ed72aSMilen Mitkov 		struct device *dev = csid->camss->dev;
1215ec6859b2STodor Tomov 
12163c4ed72aSMilen Mitkov 		if (flags & MEDIA_LNK_FL_ENABLED)
12173c4ed72aSMilen Mitkov 			csid->phy.en_vc |= BIT(local->index - 1);
12183c4ed72aSMilen Mitkov 		else
12193c4ed72aSMilen Mitkov 			csid->phy.en_vc &= ~BIT(local->index - 1);
12203c4ed72aSMilen Mitkov 
12213c4ed72aSMilen Mitkov 		csid->phy.need_vc_update = true;
12223c4ed72aSMilen Mitkov 
12233c4ed72aSMilen Mitkov 		dev_dbg(dev, "%s: Enabled CSID virtual channels mask 0x%x\n",
12243c4ed72aSMilen Mitkov 			__func__, csid->phy.en_vc);
1225ec6859b2STodor Tomov 	}
1226ec6859b2STodor Tomov 
1227ec6859b2STodor Tomov 	return 0;
1228ec6859b2STodor Tomov }
1229ec6859b2STodor Tomov 
1230ec6859b2STodor Tomov static const struct v4l2_subdev_core_ops csid_core_ops = {
1231ec6859b2STodor Tomov 	.s_power = csid_set_power,
1232988b3ae3STodor Tomov 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1233988b3ae3STodor Tomov 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1234ec6859b2STodor Tomov };
1235ec6859b2STodor Tomov 
1236ec6859b2STodor Tomov static const struct v4l2_subdev_video_ops csid_video_ops = {
1237ec6859b2STodor Tomov 	.s_stream = csid_set_stream,
1238ec6859b2STodor Tomov };
1239ec6859b2STodor Tomov 
1240ec6859b2STodor Tomov static const struct v4l2_subdev_pad_ops csid_pad_ops = {
1241ec6859b2STodor Tomov 	.enum_mbus_code = csid_enum_mbus_code,
1242ec6859b2STodor Tomov 	.enum_frame_size = csid_enum_frame_size,
1243ec6859b2STodor Tomov 	.get_fmt = csid_get_format,
1244ec6859b2STodor Tomov 	.set_fmt = csid_set_format,
1245ec6859b2STodor Tomov };
1246ec6859b2STodor Tomov 
1247ec6859b2STodor Tomov static const struct v4l2_subdev_ops csid_v4l2_ops = {
1248ec6859b2STodor Tomov 	.core = &csid_core_ops,
1249ec6859b2STodor Tomov 	.video = &csid_video_ops,
1250ec6859b2STodor Tomov 	.pad = &csid_pad_ops,
1251ec6859b2STodor Tomov };
1252ec6859b2STodor Tomov 
1253ec6859b2STodor Tomov static const struct v4l2_subdev_internal_ops csid_v4l2_internal_ops = {
1254ec6859b2STodor Tomov 	.open = csid_init_formats,
1255ec6859b2STodor Tomov };
1256ec6859b2STodor Tomov 
1257ec6859b2STodor Tomov static const struct media_entity_operations csid_media_ops = {
1258ec6859b2STodor Tomov 	.link_setup = csid_link_setup,
1259ec6859b2STodor Tomov 	.link_validate = v4l2_subdev_link_validate,
1260ec6859b2STodor Tomov };
1261ec6859b2STodor Tomov 
1262ec6859b2STodor Tomov /*
1263ec6859b2STodor Tomov  * msm_csid_register_entity - Register subdev node for CSID module
1264ec6859b2STodor Tomov  * @csid: CSID device
1265ec6859b2STodor Tomov  * @v4l2_dev: V4L2 device
1266ec6859b2STodor Tomov  *
1267ec6859b2STodor Tomov  * Return 0 on success or a negative error code otherwise
1268ec6859b2STodor Tomov  */
msm_csid_register_entity(struct csid_device * csid,struct v4l2_device * v4l2_dev)1269ec6859b2STodor Tomov int msm_csid_register_entity(struct csid_device *csid,
1270ec6859b2STodor Tomov 			     struct v4l2_device *v4l2_dev)
1271ec6859b2STodor Tomov {
1272ec6859b2STodor Tomov 	struct v4l2_subdev *sd = &csid->subdev;
1273ec6859b2STodor Tomov 	struct media_pad *pads = csid->pads;
12749c3e59deSTodor Tomov 	struct device *dev = csid->camss->dev;
12753c4ed72aSMilen Mitkov 	int i;
1276ec6859b2STodor Tomov 	int ret;
1277ec6859b2STodor Tomov 
1278ec6859b2STodor Tomov 	v4l2_subdev_init(sd, &csid_v4l2_ops);
1279ec6859b2STodor Tomov 	sd->internal_ops = &csid_v4l2_internal_ops;
1280988b3ae3STodor Tomov 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
1281988b3ae3STodor Tomov 		     V4L2_SUBDEV_FL_HAS_EVENTS;
1282ec6859b2STodor Tomov 	snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
1283ec6859b2STodor Tomov 		 MSM_CSID_NAME, csid->id);
1284ec6859b2STodor Tomov 	v4l2_set_subdevdata(sd, csid);
1285ec6859b2STodor Tomov 
1286ec6859b2STodor Tomov 	ret = v4l2_ctrl_handler_init(&csid->ctrls, 1);
1287ec6859b2STodor Tomov 	if (ret < 0) {
1288ec6859b2STodor Tomov 		dev_err(dev, "Failed to init ctrl handler: %d\n", ret);
1289ec6859b2STodor Tomov 		return ret;
1290ec6859b2STodor Tomov 	}
1291ec6859b2STodor Tomov 
1292ec6859b2STodor Tomov 	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
1293ec6859b2STodor Tomov 				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
129476005817SRobert Foss 				csid->testgen.nmodes, 0, 0,
129576005817SRobert Foss 				csid->testgen.modes);
1296ec6859b2STodor Tomov 
1297ec6859b2STodor Tomov 	if (csid->ctrls.error) {
1298ec6859b2STodor Tomov 		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
1299ec6859b2STodor Tomov 		ret = csid->ctrls.error;
1300ec6859b2STodor Tomov 		goto free_ctrl;
1301ec6859b2STodor Tomov 	}
1302ec6859b2STodor Tomov 
1303ec6859b2STodor Tomov 	csid->subdev.ctrl_handler = &csid->ctrls;
1304ec6859b2STodor Tomov 
1305ec6859b2STodor Tomov 	ret = csid_init_formats(sd, NULL);
1306ec6859b2STodor Tomov 	if (ret < 0) {
1307ec6859b2STodor Tomov 		dev_err(dev, "Failed to init format: %d\n", ret);
1308ec6859b2STodor Tomov 		goto free_ctrl;
1309ec6859b2STodor Tomov 	}
1310ec6859b2STodor Tomov 
1311ec6859b2STodor Tomov 	pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
13123c4ed72aSMilen Mitkov 	for (i = MSM_CSID_PAD_FIRST_SRC; i < MSM_CSID_PADS_NUM; ++i)
13133c4ed72aSMilen Mitkov 		pads[i].flags = MEDIA_PAD_FL_SOURCE;
1314ec6859b2STodor Tomov 
131550795910SAndrey Konovalov 	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
1316ec6859b2STodor Tomov 	sd->entity.ops = &csid_media_ops;
1317ec6859b2STodor Tomov 	ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads);
1318ec6859b2STodor Tomov 	if (ret < 0) {
1319ec6859b2STodor Tomov 		dev_err(dev, "Failed to init media entity: %d\n", ret);
1320ec6859b2STodor Tomov 		goto free_ctrl;
1321ec6859b2STodor Tomov 	}
1322ec6859b2STodor Tomov 
1323ec6859b2STodor Tomov 	ret = v4l2_device_register_subdev(v4l2_dev, sd);
1324ec6859b2STodor Tomov 	if (ret < 0) {
1325ec6859b2STodor Tomov 		dev_err(dev, "Failed to register subdev: %d\n", ret);
1326ec6859b2STodor Tomov 		goto media_cleanup;
1327ec6859b2STodor Tomov 	}
1328ec6859b2STodor Tomov 
1329ec6859b2STodor Tomov 	return 0;
1330ec6859b2STodor Tomov 
1331ec6859b2STodor Tomov media_cleanup:
1332ec6859b2STodor Tomov 	media_entity_cleanup(&sd->entity);
1333ec6859b2STodor Tomov free_ctrl:
1334ec6859b2STodor Tomov 	v4l2_ctrl_handler_free(&csid->ctrls);
1335ec6859b2STodor Tomov 
1336ec6859b2STodor Tomov 	return ret;
1337ec6859b2STodor Tomov }
1338ec6859b2STodor Tomov 
1339ec6859b2STodor Tomov /*
1340ec6859b2STodor Tomov  * msm_csid_unregister_entity - Unregister CSID module subdev node
1341ec6859b2STodor Tomov  * @csid: CSID device
1342ec6859b2STodor Tomov  */
msm_csid_unregister_entity(struct csid_device * csid)1343ec6859b2STodor Tomov void msm_csid_unregister_entity(struct csid_device *csid)
1344ec6859b2STodor Tomov {
1345ec6859b2STodor Tomov 	v4l2_device_unregister_subdev(&csid->subdev);
1346ec6859b2STodor Tomov 	media_entity_cleanup(&csid->subdev.entity);
1347ec6859b2STodor Tomov 	v4l2_ctrl_handler_free(&csid->ctrls);
1348ec6859b2STodor Tomov }
1349801ca0e7SMatti Lehtimäki 
csid_is_lite(struct csid_device * csid)1350801ca0e7SMatti Lehtimäki inline bool csid_is_lite(struct csid_device *csid)
1351801ca0e7SMatti Lehtimäki {
1352ae44829aSRadoslav Tsvetkov 	return csid->camss->res->csid_res[csid->id].csid.is_lite;
1353801ca0e7SMatti Lehtimäki }
1354