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