18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * camss-csid.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
88c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/completion.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
198c2ecf20Sopenharmony_ci#include <media/media-entity.h>
208c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
218c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
228c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "camss-csid.h"
258c2ecf20Sopenharmony_ci#include "camss.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define MSM_CSID_NAME "msm_csid"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define CAMSS_CSID_HW_VERSION		0x0
308c2ecf20Sopenharmony_ci#define CAMSS_CSID_CORE_CTRL_0		0x004
318c2ecf20Sopenharmony_ci#define CAMSS_CSID_CORE_CTRL_1		0x008
328c2ecf20Sopenharmony_ci#define CAMSS_CSID_RST_CMD(v)		((v) == CAMSS_8x16 ? 0x00c : 0x010)
338c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_LUT_VC_n(v, n)	\
348c2ecf20Sopenharmony_ci			(((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))
358c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG(v, n)	\
368c2ecf20Sopenharmony_ci			(((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))
378c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
388c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
398c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
408c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
418c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
428c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
438c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
448c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
458c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
468c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_CLEAR_CMD(v)	((v) == CAMSS_8x16 ? 0x060 : 0x064)
478c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_MASK(v)		((v) == CAMSS_8x16 ? 0x064 : 0x068)
488c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_STATUS(v)	((v) == CAMSS_8x16 ? 0x068 : 0x06c)
498c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL(v)		((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)
508c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
518c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
528c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG(v)		((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)
538c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
548c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
558c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)	\
568c2ecf20Sopenharmony_ci			(((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))
578c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)	\
588c2ecf20Sopenharmony_ci			(((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))
598c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)	\
608c2ecf20Sopenharmony_ci			(((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
638c2ecf20Sopenharmony_ci#define DATA_TYPE_YUV422_8BIT		0x1e
648c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_6BIT		0x28
658c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_8BIT		0x2a
668c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_10BIT		0x2b
678c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_12BIT		0x2c
688c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_14BIT		0x2d
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
718c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
728c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
738c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
748c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x8
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define CSID_RESET_TIMEOUT_MS 500
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct csid_format {
798c2ecf20Sopenharmony_ci	u32 code;
808c2ecf20Sopenharmony_ci	u8 data_type;
818c2ecf20Sopenharmony_ci	u8 decode_format;
828c2ecf20Sopenharmony_ci	u8 bpp;
838c2ecf20Sopenharmony_ci	u8 spp; /* bus samples per pixel */
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic const struct csid_format csid_formats_8x16[] = {
878c2ecf20Sopenharmony_ci	{
888c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_UYVY8_2X8,
898c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
908c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
918c2ecf20Sopenharmony_ci		8,
928c2ecf20Sopenharmony_ci		2,
938c2ecf20Sopenharmony_ci	},
948c2ecf20Sopenharmony_ci	{
958c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_VYUY8_2X8,
968c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
978c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
988c2ecf20Sopenharmony_ci		8,
998c2ecf20Sopenharmony_ci		2,
1008c2ecf20Sopenharmony_ci	},
1018c2ecf20Sopenharmony_ci	{
1028c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_YUYV8_2X8,
1038c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
1048c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1058c2ecf20Sopenharmony_ci		8,
1068c2ecf20Sopenharmony_ci		2,
1078c2ecf20Sopenharmony_ci	},
1088c2ecf20Sopenharmony_ci	{
1098c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_YVYU8_2X8,
1108c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
1118c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1128c2ecf20Sopenharmony_ci		8,
1138c2ecf20Sopenharmony_ci		2,
1148c2ecf20Sopenharmony_ci	},
1158c2ecf20Sopenharmony_ci	{
1168c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR8_1X8,
1178c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
1188c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1198c2ecf20Sopenharmony_ci		8,
1208c2ecf20Sopenharmony_ci		1,
1218c2ecf20Sopenharmony_ci	},
1228c2ecf20Sopenharmony_ci	{
1238c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG8_1X8,
1248c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
1258c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1268c2ecf20Sopenharmony_ci		8,
1278c2ecf20Sopenharmony_ci		1,
1288c2ecf20Sopenharmony_ci	},
1298c2ecf20Sopenharmony_ci	{
1308c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG8_1X8,
1318c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
1328c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1338c2ecf20Sopenharmony_ci		8,
1348c2ecf20Sopenharmony_ci		1,
1358c2ecf20Sopenharmony_ci	},
1368c2ecf20Sopenharmony_ci	{
1378c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB8_1X8,
1388c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
1398c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
1408c2ecf20Sopenharmony_ci		8,
1418c2ecf20Sopenharmony_ci		1,
1428c2ecf20Sopenharmony_ci	},
1438c2ecf20Sopenharmony_ci	{
1448c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR10_1X10,
1458c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
1468c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
1478c2ecf20Sopenharmony_ci		10,
1488c2ecf20Sopenharmony_ci		1,
1498c2ecf20Sopenharmony_ci	},
1508c2ecf20Sopenharmony_ci	{
1518c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG10_1X10,
1528c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
1538c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
1548c2ecf20Sopenharmony_ci		10,
1558c2ecf20Sopenharmony_ci		1,
1568c2ecf20Sopenharmony_ci	},
1578c2ecf20Sopenharmony_ci	{
1588c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG10_1X10,
1598c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
1608c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
1618c2ecf20Sopenharmony_ci		10,
1628c2ecf20Sopenharmony_ci		1,
1638c2ecf20Sopenharmony_ci	},
1648c2ecf20Sopenharmony_ci	{
1658c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB10_1X10,
1668c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
1678c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
1688c2ecf20Sopenharmony_ci		10,
1698c2ecf20Sopenharmony_ci		1,
1708c2ecf20Sopenharmony_ci	},
1718c2ecf20Sopenharmony_ci	{
1728c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR12_1X12,
1738c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
1748c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
1758c2ecf20Sopenharmony_ci		12,
1768c2ecf20Sopenharmony_ci		1,
1778c2ecf20Sopenharmony_ci	},
1788c2ecf20Sopenharmony_ci	{
1798c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG12_1X12,
1808c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
1818c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
1828c2ecf20Sopenharmony_ci		12,
1838c2ecf20Sopenharmony_ci		1,
1848c2ecf20Sopenharmony_ci	},
1858c2ecf20Sopenharmony_ci	{
1868c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG12_1X12,
1878c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
1888c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
1898c2ecf20Sopenharmony_ci		12,
1908c2ecf20Sopenharmony_ci		1,
1918c2ecf20Sopenharmony_ci	},
1928c2ecf20Sopenharmony_ci	{
1938c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB12_1X12,
1948c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
1958c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
1968c2ecf20Sopenharmony_ci		12,
1978c2ecf20Sopenharmony_ci		1,
1988c2ecf20Sopenharmony_ci	},
1998c2ecf20Sopenharmony_ci	{
2008c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_Y10_1X10,
2018c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
2028c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
2038c2ecf20Sopenharmony_ci		10,
2048c2ecf20Sopenharmony_ci		1,
2058c2ecf20Sopenharmony_ci	},
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic const struct csid_format csid_formats_8x96[] = {
2098c2ecf20Sopenharmony_ci	{
2108c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_UYVY8_2X8,
2118c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
2128c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2138c2ecf20Sopenharmony_ci		8,
2148c2ecf20Sopenharmony_ci		2,
2158c2ecf20Sopenharmony_ci	},
2168c2ecf20Sopenharmony_ci	{
2178c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_VYUY8_2X8,
2188c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
2198c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2208c2ecf20Sopenharmony_ci		8,
2218c2ecf20Sopenharmony_ci		2,
2228c2ecf20Sopenharmony_ci	},
2238c2ecf20Sopenharmony_ci	{
2248c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_YUYV8_2X8,
2258c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
2268c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2278c2ecf20Sopenharmony_ci		8,
2288c2ecf20Sopenharmony_ci		2,
2298c2ecf20Sopenharmony_ci	},
2308c2ecf20Sopenharmony_ci	{
2318c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_YVYU8_2X8,
2328c2ecf20Sopenharmony_ci		DATA_TYPE_YUV422_8BIT,
2338c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2348c2ecf20Sopenharmony_ci		8,
2358c2ecf20Sopenharmony_ci		2,
2368c2ecf20Sopenharmony_ci	},
2378c2ecf20Sopenharmony_ci	{
2388c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR8_1X8,
2398c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
2408c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2418c2ecf20Sopenharmony_ci		8,
2428c2ecf20Sopenharmony_ci		1,
2438c2ecf20Sopenharmony_ci	},
2448c2ecf20Sopenharmony_ci	{
2458c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG8_1X8,
2468c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
2478c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2488c2ecf20Sopenharmony_ci		8,
2498c2ecf20Sopenharmony_ci		1,
2508c2ecf20Sopenharmony_ci	},
2518c2ecf20Sopenharmony_ci	{
2528c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG8_1X8,
2538c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
2548c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2558c2ecf20Sopenharmony_ci		8,
2568c2ecf20Sopenharmony_ci		1,
2578c2ecf20Sopenharmony_ci	},
2588c2ecf20Sopenharmony_ci	{
2598c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB8_1X8,
2608c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_8BIT,
2618c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
2628c2ecf20Sopenharmony_ci		8,
2638c2ecf20Sopenharmony_ci		1,
2648c2ecf20Sopenharmony_ci	},
2658c2ecf20Sopenharmony_ci	{
2668c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR10_1X10,
2678c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
2688c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
2698c2ecf20Sopenharmony_ci		10,
2708c2ecf20Sopenharmony_ci		1,
2718c2ecf20Sopenharmony_ci	},
2728c2ecf20Sopenharmony_ci	{
2738c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG10_1X10,
2748c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
2758c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
2768c2ecf20Sopenharmony_ci		10,
2778c2ecf20Sopenharmony_ci		1,
2788c2ecf20Sopenharmony_ci	},
2798c2ecf20Sopenharmony_ci	{
2808c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG10_1X10,
2818c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
2828c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
2838c2ecf20Sopenharmony_ci		10,
2848c2ecf20Sopenharmony_ci		1,
2858c2ecf20Sopenharmony_ci	},
2868c2ecf20Sopenharmony_ci	{
2878c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB10_1X10,
2888c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
2898c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
2908c2ecf20Sopenharmony_ci		10,
2918c2ecf20Sopenharmony_ci		1,
2928c2ecf20Sopenharmony_ci	},
2938c2ecf20Sopenharmony_ci	{
2948c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR12_1X12,
2958c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
2968c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
2978c2ecf20Sopenharmony_ci		12,
2988c2ecf20Sopenharmony_ci		1,
2998c2ecf20Sopenharmony_ci	},
3008c2ecf20Sopenharmony_ci	{
3018c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG12_1X12,
3028c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
3038c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
3048c2ecf20Sopenharmony_ci		12,
3058c2ecf20Sopenharmony_ci		1,
3068c2ecf20Sopenharmony_ci	},
3078c2ecf20Sopenharmony_ci	{
3088c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG12_1X12,
3098c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
3108c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
3118c2ecf20Sopenharmony_ci		12,
3128c2ecf20Sopenharmony_ci		1,
3138c2ecf20Sopenharmony_ci	},
3148c2ecf20Sopenharmony_ci	{
3158c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB12_1X12,
3168c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_12BIT,
3178c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
3188c2ecf20Sopenharmony_ci		12,
3198c2ecf20Sopenharmony_ci		1,
3208c2ecf20Sopenharmony_ci	},
3218c2ecf20Sopenharmony_ci	{
3228c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SBGGR14_1X14,
3238c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_14BIT,
3248c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
3258c2ecf20Sopenharmony_ci		14,
3268c2ecf20Sopenharmony_ci		1,
3278c2ecf20Sopenharmony_ci	},
3288c2ecf20Sopenharmony_ci	{
3298c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGBRG14_1X14,
3308c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_14BIT,
3318c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
3328c2ecf20Sopenharmony_ci		14,
3338c2ecf20Sopenharmony_ci		1,
3348c2ecf20Sopenharmony_ci	},
3358c2ecf20Sopenharmony_ci	{
3368c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SGRBG14_1X14,
3378c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_14BIT,
3388c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
3398c2ecf20Sopenharmony_ci		14,
3408c2ecf20Sopenharmony_ci		1,
3418c2ecf20Sopenharmony_ci	},
3428c2ecf20Sopenharmony_ci	{
3438c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_SRGGB14_1X14,
3448c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_14BIT,
3458c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
3468c2ecf20Sopenharmony_ci		14,
3478c2ecf20Sopenharmony_ci		1,
3488c2ecf20Sopenharmony_ci	},
3498c2ecf20Sopenharmony_ci	{
3508c2ecf20Sopenharmony_ci		MEDIA_BUS_FMT_Y10_1X10,
3518c2ecf20Sopenharmony_ci		DATA_TYPE_RAW_10BIT,
3528c2ecf20Sopenharmony_ci		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
3538c2ecf20Sopenharmony_ci		10,
3548c2ecf20Sopenharmony_ci		1,
3558c2ecf20Sopenharmony_ci	},
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic u32 csid_find_code(u32 *code, unsigned int n_code,
3598c2ecf20Sopenharmony_ci			  unsigned int index, u32 req_code)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	int i;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (!req_code && (index >= n_code))
3648c2ecf20Sopenharmony_ci		return 0;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	for (i = 0; i < n_code; i++)
3678c2ecf20Sopenharmony_ci		if (req_code) {
3688c2ecf20Sopenharmony_ci			if (req_code == code[i])
3698c2ecf20Sopenharmony_ci				return req_code;
3708c2ecf20Sopenharmony_ci		} else {
3718c2ecf20Sopenharmony_ci			if (i == index)
3728c2ecf20Sopenharmony_ci				return code[i];
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return code[0];
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
3798c2ecf20Sopenharmony_ci			     unsigned int index, u32 src_req_code)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	if (csid->camss->version == CAMSS_8x16) {
3828c2ecf20Sopenharmony_ci		if (index > 0)
3838c2ecf20Sopenharmony_ci			return 0;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		return sink_code;
3868c2ecf20Sopenharmony_ci	} else if (csid->camss->version == CAMSS_8x96) {
3878c2ecf20Sopenharmony_ci		switch (sink_code) {
3888c2ecf20Sopenharmony_ci		case MEDIA_BUS_FMT_SBGGR10_1X10:
3898c2ecf20Sopenharmony_ci		{
3908c2ecf20Sopenharmony_ci			u32 src_code[] = {
3918c2ecf20Sopenharmony_ci				MEDIA_BUS_FMT_SBGGR10_1X10,
3928c2ecf20Sopenharmony_ci				MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
3938c2ecf20Sopenharmony_ci			};
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci			return csid_find_code(src_code, ARRAY_SIZE(src_code),
3968c2ecf20Sopenharmony_ci					      index, src_req_code);
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci		case MEDIA_BUS_FMT_Y10_1X10:
3998c2ecf20Sopenharmony_ci		{
4008c2ecf20Sopenharmony_ci			u32 src_code[] = {
4018c2ecf20Sopenharmony_ci				MEDIA_BUS_FMT_Y10_1X10,
4028c2ecf20Sopenharmony_ci				MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
4038c2ecf20Sopenharmony_ci			};
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci			return csid_find_code(src_code, ARRAY_SIZE(src_code),
4068c2ecf20Sopenharmony_ci					      index, src_req_code);
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci		default:
4098c2ecf20Sopenharmony_ci			if (index > 0)
4108c2ecf20Sopenharmony_ci				return 0;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci			return sink_code;
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci	} else {
4158c2ecf20Sopenharmony_ci		return 0;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic const struct csid_format *csid_get_fmt_entry(
4208c2ecf20Sopenharmony_ci					const struct csid_format *formats,
4218c2ecf20Sopenharmony_ci					unsigned int nformat,
4228c2ecf20Sopenharmony_ci					u32 code)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	unsigned int i;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	for (i = 0; i < nformat; i++)
4278c2ecf20Sopenharmony_ci		if (code == formats[i].code)
4288c2ecf20Sopenharmony_ci			return &formats[i];
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	WARN(1, "Unknown format\n");
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return &formats[0];
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/*
4368c2ecf20Sopenharmony_ci * csid_isr - CSID module interrupt handler
4378c2ecf20Sopenharmony_ci * @irq: Interrupt line
4388c2ecf20Sopenharmony_ci * @dev: CSID device
4398c2ecf20Sopenharmony_ci *
4408c2ecf20Sopenharmony_ci * Return IRQ_HANDLED on success
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic irqreturn_t csid_isr(int irq, void *dev)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	struct csid_device *csid = dev;
4458c2ecf20Sopenharmony_ci	enum camss_version ver = csid->camss->version;
4468c2ecf20Sopenharmony_ci	u32 value;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));
4498c2ecf20Sopenharmony_ci	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if ((value >> 11) & 0x1)
4528c2ecf20Sopenharmony_ci		complete(&csid->reset_complete);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci/*
4588c2ecf20Sopenharmony_ci * csid_set_clock_rates - Calculate and set clock rates on CSID module
4598c2ecf20Sopenharmony_ci * @csiphy: CSID device
4608c2ecf20Sopenharmony_ci */
4618c2ecf20Sopenharmony_cistatic int csid_set_clock_rates(struct csid_device *csid)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct device *dev = csid->camss->dev;
4648c2ecf20Sopenharmony_ci	u32 pixel_clock;
4658c2ecf20Sopenharmony_ci	int i, j;
4668c2ecf20Sopenharmony_ci	int ret;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	ret = camss_get_pixel_clock(&csid->subdev.entity, &pixel_clock);
4698c2ecf20Sopenharmony_ci	if (ret)
4708c2ecf20Sopenharmony_ci		pixel_clock = 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	for (i = 0; i < csid->nclocks; i++) {
4738c2ecf20Sopenharmony_ci		struct camss_clock *clock = &csid->clock[i];
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		if (!strcmp(clock->name, "csi0") ||
4768c2ecf20Sopenharmony_ci		    !strcmp(clock->name, "csi1") ||
4778c2ecf20Sopenharmony_ci		    !strcmp(clock->name, "csi2") ||
4788c2ecf20Sopenharmony_ci		    !strcmp(clock->name, "csi3")) {
4798c2ecf20Sopenharmony_ci			const struct csid_format *f = csid_get_fmt_entry(
4808c2ecf20Sopenharmony_ci				csid->formats,
4818c2ecf20Sopenharmony_ci				csid->nformats,
4828c2ecf20Sopenharmony_ci				csid->fmt[MSM_CSIPHY_PAD_SINK].code);
4838c2ecf20Sopenharmony_ci			u8 num_lanes = csid->phy.lane_cnt;
4848c2ecf20Sopenharmony_ci			u64 min_rate = pixel_clock * f->bpp /
4858c2ecf20Sopenharmony_ci							(2 * num_lanes * 4);
4868c2ecf20Sopenharmony_ci			long rate;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci			camss_add_clock_margin(&min_rate);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci			for (j = 0; j < clock->nfreqs; j++)
4918c2ecf20Sopenharmony_ci				if (min_rate < clock->freq[j])
4928c2ecf20Sopenharmony_ci					break;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci			if (j == clock->nfreqs) {
4958c2ecf20Sopenharmony_ci				dev_err(dev,
4968c2ecf20Sopenharmony_ci					"Pixel clock is too high for CSID\n");
4978c2ecf20Sopenharmony_ci				return -EINVAL;
4988c2ecf20Sopenharmony_ci			}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci			/* if sensor pixel clock is not available */
5018c2ecf20Sopenharmony_ci			/* set highest possible CSID clock rate */
5028c2ecf20Sopenharmony_ci			if (min_rate == 0)
5038c2ecf20Sopenharmony_ci				j = clock->nfreqs - 1;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci			rate = clk_round_rate(clock->clk, clock->freq[j]);
5068c2ecf20Sopenharmony_ci			if (rate < 0) {
5078c2ecf20Sopenharmony_ci				dev_err(dev, "clk round rate failed: %ld\n",
5088c2ecf20Sopenharmony_ci					rate);
5098c2ecf20Sopenharmony_ci				return -EINVAL;
5108c2ecf20Sopenharmony_ci			}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci			ret = clk_set_rate(clock->clk, rate);
5138c2ecf20Sopenharmony_ci			if (ret < 0) {
5148c2ecf20Sopenharmony_ci				dev_err(dev, "clk set rate failed: %d\n", ret);
5158c2ecf20Sopenharmony_ci				return ret;
5168c2ecf20Sopenharmony_ci			}
5178c2ecf20Sopenharmony_ci		}
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return 0;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/*
5248c2ecf20Sopenharmony_ci * csid_reset - Trigger reset on CSID module and wait to complete
5258c2ecf20Sopenharmony_ci * @csid: CSID device
5268c2ecf20Sopenharmony_ci *
5278c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
5288c2ecf20Sopenharmony_ci */
5298c2ecf20Sopenharmony_cistatic int csid_reset(struct csid_device *csid)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	unsigned long time;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	reinit_completion(&csid->reset_complete);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	writel_relaxed(0x7fff, csid->base +
5368c2ecf20Sopenharmony_ci		       CAMSS_CSID_RST_CMD(csid->camss->version));
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	time = wait_for_completion_timeout(&csid->reset_complete,
5398c2ecf20Sopenharmony_ci		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
5408c2ecf20Sopenharmony_ci	if (!time) {
5418c2ecf20Sopenharmony_ci		dev_err(csid->camss->dev, "CSID reset timeout\n");
5428c2ecf20Sopenharmony_ci		return -EIO;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return 0;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/*
5498c2ecf20Sopenharmony_ci * csid_set_power - Power on/off CSID module
5508c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
5518c2ecf20Sopenharmony_ci * @on: Requested power state
5528c2ecf20Sopenharmony_ci *
5538c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
5548c2ecf20Sopenharmony_ci */
5558c2ecf20Sopenharmony_cistatic int csid_set_power(struct v4l2_subdev *sd, int on)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
5588c2ecf20Sopenharmony_ci	struct device *dev = csid->camss->dev;
5598c2ecf20Sopenharmony_ci	int ret;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (on) {
5628c2ecf20Sopenharmony_ci		u32 hw_version;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		ret = pm_runtime_get_sync(dev);
5658c2ecf20Sopenharmony_ci		if (ret < 0) {
5668c2ecf20Sopenharmony_ci			pm_runtime_put_sync(dev);
5678c2ecf20Sopenharmony_ci			return ret;
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		ret = regulator_enable(csid->vdda);
5718c2ecf20Sopenharmony_ci		if (ret < 0) {
5728c2ecf20Sopenharmony_ci			pm_runtime_put_sync(dev);
5738c2ecf20Sopenharmony_ci			return ret;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		ret = csid_set_clock_rates(csid);
5778c2ecf20Sopenharmony_ci		if (ret < 0) {
5788c2ecf20Sopenharmony_ci			regulator_disable(csid->vdda);
5798c2ecf20Sopenharmony_ci			pm_runtime_put_sync(dev);
5808c2ecf20Sopenharmony_ci			return ret;
5818c2ecf20Sopenharmony_ci		}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		ret = camss_enable_clocks(csid->nclocks, csid->clock, dev);
5848c2ecf20Sopenharmony_ci		if (ret < 0) {
5858c2ecf20Sopenharmony_ci			regulator_disable(csid->vdda);
5868c2ecf20Sopenharmony_ci			pm_runtime_put_sync(dev);
5878c2ecf20Sopenharmony_ci			return ret;
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		enable_irq(csid->irq);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		ret = csid_reset(csid);
5938c2ecf20Sopenharmony_ci		if (ret < 0) {
5948c2ecf20Sopenharmony_ci			disable_irq(csid->irq);
5958c2ecf20Sopenharmony_ci			camss_disable_clocks(csid->nclocks, csid->clock);
5968c2ecf20Sopenharmony_ci			regulator_disable(csid->vdda);
5978c2ecf20Sopenharmony_ci			pm_runtime_put_sync(dev);
5988c2ecf20Sopenharmony_ci			return ret;
5998c2ecf20Sopenharmony_ci		}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
6028c2ecf20Sopenharmony_ci		dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);
6038c2ecf20Sopenharmony_ci	} else {
6048c2ecf20Sopenharmony_ci		disable_irq(csid->irq);
6058c2ecf20Sopenharmony_ci		camss_disable_clocks(csid->nclocks, csid->clock);
6068c2ecf20Sopenharmony_ci		ret = regulator_disable(csid->vdda);
6078c2ecf20Sopenharmony_ci		pm_runtime_put_sync(dev);
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return ret;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/*
6148c2ecf20Sopenharmony_ci * csid_set_stream - Enable/disable streaming on CSID module
6158c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
6168c2ecf20Sopenharmony_ci * @enable: Requested streaming state
6178c2ecf20Sopenharmony_ci *
6188c2ecf20Sopenharmony_ci * Main configuration of CSID module is also done here.
6198c2ecf20Sopenharmony_ci *
6208c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
6218c2ecf20Sopenharmony_ci */
6228c2ecf20Sopenharmony_cistatic int csid_set_stream(struct v4l2_subdev *sd, int enable)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
6258c2ecf20Sopenharmony_ci	struct csid_testgen_config *tg = &csid->testgen;
6268c2ecf20Sopenharmony_ci	enum camss_version ver = csid->camss->version;
6278c2ecf20Sopenharmony_ci	u32 val;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (enable) {
6308c2ecf20Sopenharmony_ci		u8 vc = 0; /* Virtual Channel 0 */
6318c2ecf20Sopenharmony_ci		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
6328c2ecf20Sopenharmony_ci		u8 dt, dt_shift, df;
6338c2ecf20Sopenharmony_ci		int ret;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		ret = v4l2_ctrl_handler_setup(&csid->ctrls);
6368c2ecf20Sopenharmony_ci		if (ret < 0) {
6378c2ecf20Sopenharmony_ci			dev_err(csid->camss->dev,
6388c2ecf20Sopenharmony_ci				"could not sync v4l2 controls: %d\n", ret);
6398c2ecf20Sopenharmony_ci			return ret;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		if (!tg->enabled &&
6438c2ecf20Sopenharmony_ci		    !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
6448c2ecf20Sopenharmony_ci			return -ENOLINK;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci		if (tg->enabled) {
6478c2ecf20Sopenharmony_ci			/* Config Test Generator */
6488c2ecf20Sopenharmony_ci			struct v4l2_mbus_framefmt *f =
6498c2ecf20Sopenharmony_ci					&csid->fmt[MSM_CSID_PAD_SRC];
6508c2ecf20Sopenharmony_ci			const struct csid_format *format = csid_get_fmt_entry(
6518c2ecf20Sopenharmony_ci					csid->formats, csid->nformats, f->code);
6528c2ecf20Sopenharmony_ci			u32 num_bytes_per_line =
6538c2ecf20Sopenharmony_ci				f->width * format->bpp * format->spp / 8;
6548c2ecf20Sopenharmony_ci			u32 num_lines = f->height;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
6578c2ecf20Sopenharmony_ci			/* 1:0 VC */
6588c2ecf20Sopenharmony_ci			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
6598c2ecf20Sopenharmony_ci			      ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
6608c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
6618c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_VC_CFG(ver));
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci			/* 28:16 bytes per lines, 12:0 num of lines */
6648c2ecf20Sopenharmony_ci			val = ((num_bytes_per_line & 0x1fff) << 16) |
6658c2ecf20Sopenharmony_ci			      (num_lines & 0x1fff);
6668c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
6678c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci			dt = format->data_type;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci			/* 5:0 data type */
6728c2ecf20Sopenharmony_ci			val = dt;
6738c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
6748c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci			/* 2:0 output test pattern */
6778c2ecf20Sopenharmony_ci			val = tg->payload_mode;
6788c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
6798c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci			df = format->decode_format;
6828c2ecf20Sopenharmony_ci		} else {
6838c2ecf20Sopenharmony_ci			struct v4l2_mbus_framefmt *f =
6848c2ecf20Sopenharmony_ci					&csid->fmt[MSM_CSID_PAD_SINK];
6858c2ecf20Sopenharmony_ci			const struct csid_format *format = csid_get_fmt_entry(
6868c2ecf20Sopenharmony_ci					csid->formats, csid->nformats, f->code);
6878c2ecf20Sopenharmony_ci			struct csid_phy_config *phy = &csid->phy;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci			val = phy->lane_cnt - 1;
6908c2ecf20Sopenharmony_ci			val |= phy->lane_assign << 4;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci			writel_relaxed(val,
6938c2ecf20Sopenharmony_ci				       csid->base + CAMSS_CSID_CORE_CTRL_0);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci			val = phy->csiphy_id << 17;
6968c2ecf20Sopenharmony_ci			val |= 0x9;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci			writel_relaxed(val,
6998c2ecf20Sopenharmony_ci				       csid->base + CAMSS_CSID_CORE_CTRL_1);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci			dt = format->data_type;
7028c2ecf20Sopenharmony_ci			df = format->decode_format;
7038c2ecf20Sopenharmony_ci		}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		/* Config LUT */
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		dt_shift = (cid % 4) * 8;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		val = readl_relaxed(csid->base +
7108c2ecf20Sopenharmony_ci				    CAMSS_CSID_CID_LUT_VC_n(ver, vc));
7118c2ecf20Sopenharmony_ci		val &= ~(0xff << dt_shift);
7128c2ecf20Sopenharmony_ci		val |= dt << dt_shift;
7138c2ecf20Sopenharmony_ci		writel_relaxed(val, csid->base +
7148c2ecf20Sopenharmony_ci			       CAMSS_CSID_CID_LUT_VC_n(ver, vc));
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
7178c2ecf20Sopenharmony_ci		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
7188c2ecf20Sopenharmony_ci		val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
7198c2ecf20Sopenharmony_ci		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		if (csid->camss->version == CAMSS_8x96) {
7228c2ecf20Sopenharmony_ci			u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
7238c2ecf20Sopenharmony_ci			u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci			if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
7268c2ecf20Sopenharmony_ci			     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
7278c2ecf20Sopenharmony_ci			    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
7288c2ecf20Sopenharmony_ci			     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
7298c2ecf20Sopenharmony_ci				val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
7308c2ecf20Sopenharmony_ci				val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
7318c2ecf20Sopenharmony_ci				val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
7328c2ecf20Sopenharmony_ci			}
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		writel_relaxed(val, csid->base +
7368c2ecf20Sopenharmony_ci			       CAMSS_CSID_CID_n_CFG(ver, cid));
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		if (tg->enabled) {
7398c2ecf20Sopenharmony_ci			val = CAMSS_CSID_TG_CTRL_ENABLE;
7408c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
7418c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_CTRL(ver));
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci	} else {
7448c2ecf20Sopenharmony_ci		if (tg->enabled) {
7458c2ecf20Sopenharmony_ci			val = CAMSS_CSID_TG_CTRL_DISABLE;
7468c2ecf20Sopenharmony_ci			writel_relaxed(val, csid->base +
7478c2ecf20Sopenharmony_ci				       CAMSS_CSID_TG_CTRL(ver));
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci/*
7558c2ecf20Sopenharmony_ci * __csid_get_format - Get pointer to format structure
7568c2ecf20Sopenharmony_ci * @csid: CSID device
7578c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
7588c2ecf20Sopenharmony_ci * @pad: pad from which format is requested
7598c2ecf20Sopenharmony_ci * @which: TRY or ACTIVE format
7608c2ecf20Sopenharmony_ci *
7618c2ecf20Sopenharmony_ci * Return pointer to TRY or ACTIVE format structure
7628c2ecf20Sopenharmony_ci */
7638c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt *
7648c2ecf20Sopenharmony_ci__csid_get_format(struct csid_device *csid,
7658c2ecf20Sopenharmony_ci		  struct v4l2_subdev_pad_config *cfg,
7668c2ecf20Sopenharmony_ci		  unsigned int pad,
7678c2ecf20Sopenharmony_ci		  enum v4l2_subdev_format_whence which)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	if (which == V4L2_SUBDEV_FORMAT_TRY)
7708c2ecf20Sopenharmony_ci		return v4l2_subdev_get_try_format(&csid->subdev, cfg, pad);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	return &csid->fmt[pad];
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci/*
7768c2ecf20Sopenharmony_ci * csid_try_format - Handle try format by pad subdev method
7778c2ecf20Sopenharmony_ci * @csid: CSID device
7788c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
7798c2ecf20Sopenharmony_ci * @pad: pad on which format is requested
7808c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 format structure
7818c2ecf20Sopenharmony_ci * @which: wanted subdev format
7828c2ecf20Sopenharmony_ci */
7838c2ecf20Sopenharmony_cistatic void csid_try_format(struct csid_device *csid,
7848c2ecf20Sopenharmony_ci			    struct v4l2_subdev_pad_config *cfg,
7858c2ecf20Sopenharmony_ci			    unsigned int pad,
7868c2ecf20Sopenharmony_ci			    struct v4l2_mbus_framefmt *fmt,
7878c2ecf20Sopenharmony_ci			    enum v4l2_subdev_format_whence which)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	unsigned int i;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	switch (pad) {
7928c2ecf20Sopenharmony_ci	case MSM_CSID_PAD_SINK:
7938c2ecf20Sopenharmony_ci		/* Set format on sink pad */
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		for (i = 0; i < csid->nformats; i++)
7968c2ecf20Sopenharmony_ci			if (fmt->code == csid->formats[i].code)
7978c2ecf20Sopenharmony_ci				break;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci		/* If not found, use UYVY as default */
8008c2ecf20Sopenharmony_ci		if (i >= csid->nformats)
8018c2ecf20Sopenharmony_ci			fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci		fmt->width = clamp_t(u32, fmt->width, 1, 8191);
8048c2ecf20Sopenharmony_ci		fmt->height = clamp_t(u32, fmt->height, 1, 8191);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci		fmt->field = V4L2_FIELD_NONE;
8078c2ecf20Sopenharmony_ci		fmt->colorspace = V4L2_COLORSPACE_SRGB;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci		break;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	case MSM_CSID_PAD_SRC:
8128c2ecf20Sopenharmony_ci		if (csid->testgen_mode->cur.val == 0) {
8138c2ecf20Sopenharmony_ci			/* Test generator is disabled, */
8148c2ecf20Sopenharmony_ci			/* keep pad formats in sync */
8158c2ecf20Sopenharmony_ci			u32 code = fmt->code;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci			*fmt = *__csid_get_format(csid, cfg,
8188c2ecf20Sopenharmony_ci						      MSM_CSID_PAD_SINK, which);
8198c2ecf20Sopenharmony_ci			fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);
8208c2ecf20Sopenharmony_ci		} else {
8218c2ecf20Sopenharmony_ci			/* Test generator is enabled, set format on source */
8228c2ecf20Sopenharmony_ci			/* pad to allow test generator usage */
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci			for (i = 0; i < csid->nformats; i++)
8258c2ecf20Sopenharmony_ci				if (csid->formats[i].code == fmt->code)
8268c2ecf20Sopenharmony_ci					break;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci			/* If not found, use UYVY as default */
8298c2ecf20Sopenharmony_ci			if (i >= csid->nformats)
8308c2ecf20Sopenharmony_ci				fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci			fmt->width = clamp_t(u32, fmt->width, 1, 8191);
8338c2ecf20Sopenharmony_ci			fmt->height = clamp_t(u32, fmt->height, 1, 8191);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci			fmt->field = V4L2_FIELD_NONE;
8368c2ecf20Sopenharmony_ci		}
8378c2ecf20Sopenharmony_ci		break;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	fmt->colorspace = V4L2_COLORSPACE_SRGB;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci/*
8448c2ecf20Sopenharmony_ci * csid_enum_mbus_code - Handle pixel format enumeration
8458c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
8468c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
8478c2ecf20Sopenharmony_ci * @code: pointer to v4l2_subdev_mbus_code_enum structure
8488c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
8498c2ecf20Sopenharmony_ci */
8508c2ecf20Sopenharmony_cistatic int csid_enum_mbus_code(struct v4l2_subdev *sd,
8518c2ecf20Sopenharmony_ci			       struct v4l2_subdev_pad_config *cfg,
8528c2ecf20Sopenharmony_ci			       struct v4l2_subdev_mbus_code_enum *code)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	if (code->pad == MSM_CSID_PAD_SINK) {
8578c2ecf20Sopenharmony_ci		if (code->index >= csid->nformats)
8588c2ecf20Sopenharmony_ci			return -EINVAL;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci		code->code = csid->formats[code->index].code;
8618c2ecf20Sopenharmony_ci	} else {
8628c2ecf20Sopenharmony_ci		if (csid->testgen_mode->cur.val == 0) {
8638c2ecf20Sopenharmony_ci			struct v4l2_mbus_framefmt *sink_fmt;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci			sink_fmt = __csid_get_format(csid, cfg,
8668c2ecf20Sopenharmony_ci						     MSM_CSID_PAD_SINK,
8678c2ecf20Sopenharmony_ci						     code->which);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci			code->code = csid_src_pad_code(csid, sink_fmt->code,
8708c2ecf20Sopenharmony_ci						       code->index, 0);
8718c2ecf20Sopenharmony_ci			if (!code->code)
8728c2ecf20Sopenharmony_ci				return -EINVAL;
8738c2ecf20Sopenharmony_ci		} else {
8748c2ecf20Sopenharmony_ci			if (code->index >= csid->nformats)
8758c2ecf20Sopenharmony_ci				return -EINVAL;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci			code->code = csid->formats[code->index].code;
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return 0;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci/*
8858c2ecf20Sopenharmony_ci * csid_enum_frame_size - Handle frame size enumeration
8868c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
8878c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
8888c2ecf20Sopenharmony_ci * @fse: pointer to v4l2_subdev_frame_size_enum structure
8898c2ecf20Sopenharmony_ci * return -EINVAL or zero on success
8908c2ecf20Sopenharmony_ci */
8918c2ecf20Sopenharmony_cistatic int csid_enum_frame_size(struct v4l2_subdev *sd,
8928c2ecf20Sopenharmony_ci				struct v4l2_subdev_pad_config *cfg,
8938c2ecf20Sopenharmony_ci				struct v4l2_subdev_frame_size_enum *fse)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
8968c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt format;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (fse->index != 0)
8998c2ecf20Sopenharmony_ci		return -EINVAL;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	format.code = fse->code;
9028c2ecf20Sopenharmony_ci	format.width = 1;
9038c2ecf20Sopenharmony_ci	format.height = 1;
9048c2ecf20Sopenharmony_ci	csid_try_format(csid, cfg, fse->pad, &format, fse->which);
9058c2ecf20Sopenharmony_ci	fse->min_width = format.width;
9068c2ecf20Sopenharmony_ci	fse->min_height = format.height;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (format.code != fse->code)
9098c2ecf20Sopenharmony_ci		return -EINVAL;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	format.code = fse->code;
9128c2ecf20Sopenharmony_ci	format.width = -1;
9138c2ecf20Sopenharmony_ci	format.height = -1;
9148c2ecf20Sopenharmony_ci	csid_try_format(csid, cfg, fse->pad, &format, fse->which);
9158c2ecf20Sopenharmony_ci	fse->max_width = format.width;
9168c2ecf20Sopenharmony_ci	fse->max_height = format.height;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	return 0;
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci/*
9228c2ecf20Sopenharmony_ci * csid_get_format - Handle get format by pads subdev method
9238c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
9248c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
9258c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
9268c2ecf20Sopenharmony_ci *
9278c2ecf20Sopenharmony_ci * Return -EINVAL or zero on success
9288c2ecf20Sopenharmony_ci */
9298c2ecf20Sopenharmony_cistatic int csid_get_format(struct v4l2_subdev *sd,
9308c2ecf20Sopenharmony_ci			   struct v4l2_subdev_pad_config *cfg,
9318c2ecf20Sopenharmony_ci			   struct v4l2_subdev_format *fmt)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
9348c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
9378c2ecf20Sopenharmony_ci	if (format == NULL)
9388c2ecf20Sopenharmony_ci		return -EINVAL;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	fmt->format = *format;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return 0;
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci/*
9468c2ecf20Sopenharmony_ci * csid_set_format - Handle set format by pads subdev method
9478c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
9488c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration
9498c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure
9508c2ecf20Sopenharmony_ci *
9518c2ecf20Sopenharmony_ci * Return -EINVAL or zero on success
9528c2ecf20Sopenharmony_ci */
9538c2ecf20Sopenharmony_cistatic int csid_set_format(struct v4l2_subdev *sd,
9548c2ecf20Sopenharmony_ci			   struct v4l2_subdev_pad_config *cfg,
9558c2ecf20Sopenharmony_ci			   struct v4l2_subdev_format *fmt)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
9588c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
9618c2ecf20Sopenharmony_ci	if (format == NULL)
9628c2ecf20Sopenharmony_ci		return -EINVAL;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	csid_try_format(csid, cfg, fmt->pad, &fmt->format, fmt->which);
9658c2ecf20Sopenharmony_ci	*format = fmt->format;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/* Propagate the format from sink to source */
9688c2ecf20Sopenharmony_ci	if (fmt->pad == MSM_CSID_PAD_SINK) {
9698c2ecf20Sopenharmony_ci		format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SRC,
9708c2ecf20Sopenharmony_ci					   fmt->which);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci		*format = fmt->format;
9738c2ecf20Sopenharmony_ci		csid_try_format(csid, cfg, MSM_CSID_PAD_SRC, format,
9748c2ecf20Sopenharmony_ci				fmt->which);
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	return 0;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/*
9818c2ecf20Sopenharmony_ci * csid_init_formats - Initialize formats on all pads
9828c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice
9838c2ecf20Sopenharmony_ci * @fh: V4L2 subdev file handle
9848c2ecf20Sopenharmony_ci *
9858c2ecf20Sopenharmony_ci * Initialize all pad formats with default values.
9868c2ecf20Sopenharmony_ci *
9878c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
9888c2ecf20Sopenharmony_ci */
9898c2ecf20Sopenharmony_cistatic int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	struct v4l2_subdev_format format = {
9928c2ecf20Sopenharmony_ci		.pad = MSM_CSID_PAD_SINK,
9938c2ecf20Sopenharmony_ci		.which = fh ? V4L2_SUBDEV_FORMAT_TRY :
9948c2ecf20Sopenharmony_ci			      V4L2_SUBDEV_FORMAT_ACTIVE,
9958c2ecf20Sopenharmony_ci		.format = {
9968c2ecf20Sopenharmony_ci			.code = MEDIA_BUS_FMT_UYVY8_2X8,
9978c2ecf20Sopenharmony_ci			.width = 1920,
9988c2ecf20Sopenharmony_ci			.height = 1080
9998c2ecf20Sopenharmony_ci		}
10008c2ecf20Sopenharmony_ci	};
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	return csid_set_format(sd, fh ? fh->pad : NULL, &format);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic const char * const csid_test_pattern_menu[] = {
10068c2ecf20Sopenharmony_ci	"Disabled",
10078c2ecf20Sopenharmony_ci	"Incrementing",
10088c2ecf20Sopenharmony_ci	"Alternating 0x55/0xAA",
10098c2ecf20Sopenharmony_ci	"All Zeros 0x00",
10108c2ecf20Sopenharmony_ci	"All Ones 0xFF",
10118c2ecf20Sopenharmony_ci	"Pseudo-random Data",
10128c2ecf20Sopenharmony_ci};
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci/*
10158c2ecf20Sopenharmony_ci * csid_set_test_pattern - Set test generator's pattern mode
10168c2ecf20Sopenharmony_ci * @csid: CSID device
10178c2ecf20Sopenharmony_ci * @value: desired test pattern mode
10188c2ecf20Sopenharmony_ci *
10198c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
10208c2ecf20Sopenharmony_ci */
10218c2ecf20Sopenharmony_cistatic int csid_set_test_pattern(struct csid_device *csid, s32 value)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct csid_testgen_config *tg = &csid->testgen;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* If CSID is linked to CSIPHY, do not allow to enable test generator */
10268c2ecf20Sopenharmony_ci	if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
10278c2ecf20Sopenharmony_ci		return -EBUSY;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	tg->enabled = !!value;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	switch (value) {
10328c2ecf20Sopenharmony_ci	case 1:
10338c2ecf20Sopenharmony_ci		tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;
10348c2ecf20Sopenharmony_ci		break;
10358c2ecf20Sopenharmony_ci	case 2:
10368c2ecf20Sopenharmony_ci		tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;
10378c2ecf20Sopenharmony_ci		break;
10388c2ecf20Sopenharmony_ci	case 3:
10398c2ecf20Sopenharmony_ci		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;
10408c2ecf20Sopenharmony_ci		break;
10418c2ecf20Sopenharmony_ci	case 4:
10428c2ecf20Sopenharmony_ci		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;
10438c2ecf20Sopenharmony_ci		break;
10448c2ecf20Sopenharmony_ci	case 5:
10458c2ecf20Sopenharmony_ci		tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;
10468c2ecf20Sopenharmony_ci		break;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return 0;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci/*
10538c2ecf20Sopenharmony_ci * csid_s_ctrl - Handle set control subdev method
10548c2ecf20Sopenharmony_ci * @ctrl: pointer to v4l2 control structure
10558c2ecf20Sopenharmony_ci *
10568c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
10578c2ecf20Sopenharmony_ci */
10588c2ecf20Sopenharmony_cistatic int csid_s_ctrl(struct v4l2_ctrl *ctrl)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	struct csid_device *csid = container_of(ctrl->handler,
10618c2ecf20Sopenharmony_ci						struct csid_device, ctrls);
10628c2ecf20Sopenharmony_ci	int ret = -EINVAL;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	switch (ctrl->id) {
10658c2ecf20Sopenharmony_ci	case V4L2_CID_TEST_PATTERN:
10668c2ecf20Sopenharmony_ci		ret = csid_set_test_pattern(csid, ctrl->val);
10678c2ecf20Sopenharmony_ci		break;
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	return ret;
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops csid_ctrl_ops = {
10748c2ecf20Sopenharmony_ci	.s_ctrl = csid_s_ctrl,
10758c2ecf20Sopenharmony_ci};
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/*
10788c2ecf20Sopenharmony_ci * msm_csid_subdev_init - Initialize CSID device structure and resources
10798c2ecf20Sopenharmony_ci * @csid: CSID device
10808c2ecf20Sopenharmony_ci * @res: CSID module resources table
10818c2ecf20Sopenharmony_ci * @id: CSID module id
10828c2ecf20Sopenharmony_ci *
10838c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
10848c2ecf20Sopenharmony_ci */
10858c2ecf20Sopenharmony_ciint msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
10868c2ecf20Sopenharmony_ci			 const struct resources *res, u8 id)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	struct device *dev = camss->dev;
10898c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
10908c2ecf20Sopenharmony_ci	struct resource *r;
10918c2ecf20Sopenharmony_ci	int i, j;
10928c2ecf20Sopenharmony_ci	int ret;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	csid->camss = camss;
10958c2ecf20Sopenharmony_ci	csid->id = id;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x16) {
10988c2ecf20Sopenharmony_ci		csid->formats = csid_formats_8x16;
10998c2ecf20Sopenharmony_ci		csid->nformats =
11008c2ecf20Sopenharmony_ci				ARRAY_SIZE(csid_formats_8x16);
11018c2ecf20Sopenharmony_ci	} else if (camss->version == CAMSS_8x96) {
11028c2ecf20Sopenharmony_ci		csid->formats = csid_formats_8x96;
11038c2ecf20Sopenharmony_ci		csid->nformats =
11048c2ecf20Sopenharmony_ci				ARRAY_SIZE(csid_formats_8x96);
11058c2ecf20Sopenharmony_ci	} else {
11068c2ecf20Sopenharmony_ci		return -EINVAL;
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/* Memory */
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
11128c2ecf20Sopenharmony_ci	csid->base = devm_ioremap_resource(dev, r);
11138c2ecf20Sopenharmony_ci	if (IS_ERR(csid->base)) {
11148c2ecf20Sopenharmony_ci		dev_err(dev, "could not map memory\n");
11158c2ecf20Sopenharmony_ci		return PTR_ERR(csid->base);
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	/* Interrupt */
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
11218c2ecf20Sopenharmony_ci					 res->interrupt[0]);
11228c2ecf20Sopenharmony_ci	if (!r) {
11238c2ecf20Sopenharmony_ci		dev_err(dev, "missing IRQ\n");
11248c2ecf20Sopenharmony_ci		return -EINVAL;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	csid->irq = r->start;
11288c2ecf20Sopenharmony_ci	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
11298c2ecf20Sopenharmony_ci		 dev_name(dev), MSM_CSID_NAME, csid->id);
11308c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, csid->irq, csid_isr,
11318c2ecf20Sopenharmony_ci		IRQF_TRIGGER_RISING, csid->irq_name, csid);
11328c2ecf20Sopenharmony_ci	if (ret < 0) {
11338c2ecf20Sopenharmony_ci		dev_err(dev, "request_irq failed: %d\n", ret);
11348c2ecf20Sopenharmony_ci		return ret;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	disable_irq(csid->irq);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* Clocks */
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	csid->nclocks = 0;
11428c2ecf20Sopenharmony_ci	while (res->clock[csid->nclocks])
11438c2ecf20Sopenharmony_ci		csid->nclocks++;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	csid->clock = devm_kcalloc(dev, csid->nclocks, sizeof(*csid->clock),
11468c2ecf20Sopenharmony_ci				    GFP_KERNEL);
11478c2ecf20Sopenharmony_ci	if (!csid->clock)
11488c2ecf20Sopenharmony_ci		return -ENOMEM;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	for (i = 0; i < csid->nclocks; i++) {
11518c2ecf20Sopenharmony_ci		struct camss_clock *clock = &csid->clock[i];
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci		clock->clk = devm_clk_get(dev, res->clock[i]);
11548c2ecf20Sopenharmony_ci		if (IS_ERR(clock->clk))
11558c2ecf20Sopenharmony_ci			return PTR_ERR(clock->clk);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		clock->name = res->clock[i];
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci		clock->nfreqs = 0;
11608c2ecf20Sopenharmony_ci		while (res->clock_rate[i][clock->nfreqs])
11618c2ecf20Sopenharmony_ci			clock->nfreqs++;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		if (!clock->nfreqs) {
11648c2ecf20Sopenharmony_ci			clock->freq = NULL;
11658c2ecf20Sopenharmony_ci			continue;
11668c2ecf20Sopenharmony_ci		}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		clock->freq = devm_kcalloc(dev,
11698c2ecf20Sopenharmony_ci					   clock->nfreqs,
11708c2ecf20Sopenharmony_ci					   sizeof(*clock->freq),
11718c2ecf20Sopenharmony_ci					   GFP_KERNEL);
11728c2ecf20Sopenharmony_ci		if (!clock->freq)
11738c2ecf20Sopenharmony_ci			return -ENOMEM;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci		for (j = 0; j < clock->nfreqs; j++)
11768c2ecf20Sopenharmony_ci			clock->freq[j] = res->clock_rate[i][j];
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	/* Regulator */
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	csid->vdda = devm_regulator_get(dev, res->regulator[0]);
11828c2ecf20Sopenharmony_ci	if (IS_ERR(csid->vdda)) {
11838c2ecf20Sopenharmony_ci		dev_err(dev, "could not get regulator\n");
11848c2ecf20Sopenharmony_ci		return PTR_ERR(csid->vdda);
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	init_completion(&csid->reset_complete);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	return 0;
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci/*
11938c2ecf20Sopenharmony_ci * msm_csid_get_csid_id - Get CSID HW module id
11948c2ecf20Sopenharmony_ci * @entity: Pointer to CSID media entity structure
11958c2ecf20Sopenharmony_ci * @id: Return CSID HW module id here
11968c2ecf20Sopenharmony_ci */
11978c2ecf20Sopenharmony_civoid msm_csid_get_csid_id(struct media_entity *entity, u8 *id)
11988c2ecf20Sopenharmony_ci{
11998c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
12008c2ecf20Sopenharmony_ci	struct csid_device *csid = v4l2_get_subdevdata(sd);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	*id = csid->id;
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci/*
12068c2ecf20Sopenharmony_ci * csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter
12078c2ecf20Sopenharmony_ci * @lane_cfg - CSI2 lane configuration
12088c2ecf20Sopenharmony_ci *
12098c2ecf20Sopenharmony_ci * Return lane assign
12108c2ecf20Sopenharmony_ci */
12118c2ecf20Sopenharmony_cistatic u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	u32 lane_assign = 0;
12148c2ecf20Sopenharmony_ci	int i;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	for (i = 0; i < lane_cfg->num_data; i++)
12178c2ecf20Sopenharmony_ci		lane_assign |= lane_cfg->data[i].pos << (i * 4);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	return lane_assign;
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci/*
12238c2ecf20Sopenharmony_ci * csid_link_setup - Setup CSID connections
12248c2ecf20Sopenharmony_ci * @entity: Pointer to media entity structure
12258c2ecf20Sopenharmony_ci * @local: Pointer to local pad
12268c2ecf20Sopenharmony_ci * @remote: Pointer to remote pad
12278c2ecf20Sopenharmony_ci * @flags: Link flags
12288c2ecf20Sopenharmony_ci *
12298c2ecf20Sopenharmony_ci * Return 0 on success
12308c2ecf20Sopenharmony_ci */
12318c2ecf20Sopenharmony_cistatic int csid_link_setup(struct media_entity *entity,
12328c2ecf20Sopenharmony_ci			   const struct media_pad *local,
12338c2ecf20Sopenharmony_ci			   const struct media_pad *remote, u32 flags)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	if (flags & MEDIA_LNK_FL_ENABLED)
12368c2ecf20Sopenharmony_ci		if (media_entity_remote_pad(local))
12378c2ecf20Sopenharmony_ci			return -EBUSY;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if ((local->flags & MEDIA_PAD_FL_SINK) &&
12408c2ecf20Sopenharmony_ci	    (flags & MEDIA_LNK_FL_ENABLED)) {
12418c2ecf20Sopenharmony_ci		struct v4l2_subdev *sd;
12428c2ecf20Sopenharmony_ci		struct csid_device *csid;
12438c2ecf20Sopenharmony_ci		struct csiphy_device *csiphy;
12448c2ecf20Sopenharmony_ci		struct csiphy_lanes_cfg *lane_cfg;
12458c2ecf20Sopenharmony_ci		struct v4l2_subdev_format format = { 0 };
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci		sd = media_entity_to_v4l2_subdev(entity);
12488c2ecf20Sopenharmony_ci		csid = v4l2_get_subdevdata(sd);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci		/* If test generator is enabled */
12518c2ecf20Sopenharmony_ci		/* do not allow a link from CSIPHY to CSID */
12528c2ecf20Sopenharmony_ci		if (csid->testgen_mode->cur.val != 0)
12538c2ecf20Sopenharmony_ci			return -EBUSY;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci		sd = media_entity_to_v4l2_subdev(remote->entity);
12568c2ecf20Sopenharmony_ci		csiphy = v4l2_get_subdevdata(sd);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		/* If a sensor is not linked to CSIPHY */
12598c2ecf20Sopenharmony_ci		/* do no allow a link from CSIPHY to CSID */
12608c2ecf20Sopenharmony_ci		if (!csiphy->cfg.csi2)
12618c2ecf20Sopenharmony_ci			return -EPERM;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci		csid->phy.csiphy_id = csiphy->id;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		lane_cfg = &csiphy->cfg.csi2->lane_cfg;
12668c2ecf20Sopenharmony_ci		csid->phy.lane_cnt = lane_cfg->num_data;
12678c2ecf20Sopenharmony_ci		csid->phy.lane_assign = csid_get_lane_assign(lane_cfg);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci		/* Reset format on source pad to sink pad format */
12708c2ecf20Sopenharmony_ci		format.pad = MSM_CSID_PAD_SRC;
12718c2ecf20Sopenharmony_ci		format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
12728c2ecf20Sopenharmony_ci		csid_set_format(&csid->subdev, NULL, &format);
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	return 0;
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops csid_core_ops = {
12798c2ecf20Sopenharmony_ci	.s_power = csid_set_power,
12808c2ecf20Sopenharmony_ci	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
12818c2ecf20Sopenharmony_ci	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
12828c2ecf20Sopenharmony_ci};
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops csid_video_ops = {
12858c2ecf20Sopenharmony_ci	.s_stream = csid_set_stream,
12868c2ecf20Sopenharmony_ci};
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops csid_pad_ops = {
12898c2ecf20Sopenharmony_ci	.enum_mbus_code = csid_enum_mbus_code,
12908c2ecf20Sopenharmony_ci	.enum_frame_size = csid_enum_frame_size,
12918c2ecf20Sopenharmony_ci	.get_fmt = csid_get_format,
12928c2ecf20Sopenharmony_ci	.set_fmt = csid_set_format,
12938c2ecf20Sopenharmony_ci};
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops csid_v4l2_ops = {
12968c2ecf20Sopenharmony_ci	.core = &csid_core_ops,
12978c2ecf20Sopenharmony_ci	.video = &csid_video_ops,
12988c2ecf20Sopenharmony_ci	.pad = &csid_pad_ops,
12998c2ecf20Sopenharmony_ci};
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops csid_v4l2_internal_ops = {
13028c2ecf20Sopenharmony_ci	.open = csid_init_formats,
13038c2ecf20Sopenharmony_ci};
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_cistatic const struct media_entity_operations csid_media_ops = {
13068c2ecf20Sopenharmony_ci	.link_setup = csid_link_setup,
13078c2ecf20Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
13088c2ecf20Sopenharmony_ci};
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci/*
13118c2ecf20Sopenharmony_ci * msm_csid_register_entity - Register subdev node for CSID module
13128c2ecf20Sopenharmony_ci * @csid: CSID device
13138c2ecf20Sopenharmony_ci * @v4l2_dev: V4L2 device
13148c2ecf20Sopenharmony_ci *
13158c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
13168c2ecf20Sopenharmony_ci */
13178c2ecf20Sopenharmony_ciint msm_csid_register_entity(struct csid_device *csid,
13188c2ecf20Sopenharmony_ci			     struct v4l2_device *v4l2_dev)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = &csid->subdev;
13218c2ecf20Sopenharmony_ci	struct media_pad *pads = csid->pads;
13228c2ecf20Sopenharmony_ci	struct device *dev = csid->camss->dev;
13238c2ecf20Sopenharmony_ci	int ret;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	v4l2_subdev_init(sd, &csid_v4l2_ops);
13268c2ecf20Sopenharmony_ci	sd->internal_ops = &csid_v4l2_internal_ops;
13278c2ecf20Sopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
13288c2ecf20Sopenharmony_ci		     V4L2_SUBDEV_FL_HAS_EVENTS;
13298c2ecf20Sopenharmony_ci	snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
13308c2ecf20Sopenharmony_ci		 MSM_CSID_NAME, csid->id);
13318c2ecf20Sopenharmony_ci	v4l2_set_subdevdata(sd, csid);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	ret = v4l2_ctrl_handler_init(&csid->ctrls, 1);
13348c2ecf20Sopenharmony_ci	if (ret < 0) {
13358c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to init ctrl handler: %d\n", ret);
13368c2ecf20Sopenharmony_ci		return ret;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
13408c2ecf20Sopenharmony_ci				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
13418c2ecf20Sopenharmony_ci				ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,
13428c2ecf20Sopenharmony_ci				csid_test_pattern_menu);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	if (csid->ctrls.error) {
13458c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
13468c2ecf20Sopenharmony_ci		ret = csid->ctrls.error;
13478c2ecf20Sopenharmony_ci		goto free_ctrl;
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	csid->subdev.ctrl_handler = &csid->ctrls;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	ret = csid_init_formats(sd, NULL);
13538c2ecf20Sopenharmony_ci	if (ret < 0) {
13548c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to init format: %d\n", ret);
13558c2ecf20Sopenharmony_ci		goto free_ctrl;
13568c2ecf20Sopenharmony_ci	}
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
13598c2ecf20Sopenharmony_ci	pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
13628c2ecf20Sopenharmony_ci	sd->entity.ops = &csid_media_ops;
13638c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads);
13648c2ecf20Sopenharmony_ci	if (ret < 0) {
13658c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to init media entity: %d\n", ret);
13668c2ecf20Sopenharmony_ci		goto free_ctrl;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	ret = v4l2_device_register_subdev(v4l2_dev, sd);
13708c2ecf20Sopenharmony_ci	if (ret < 0) {
13718c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register subdev: %d\n", ret);
13728c2ecf20Sopenharmony_ci		goto media_cleanup;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	return 0;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_cimedia_cleanup:
13788c2ecf20Sopenharmony_ci	media_entity_cleanup(&sd->entity);
13798c2ecf20Sopenharmony_cifree_ctrl:
13808c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&csid->ctrls);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	return ret;
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci/*
13868c2ecf20Sopenharmony_ci * msm_csid_unregister_entity - Unregister CSID module subdev node
13878c2ecf20Sopenharmony_ci * @csid: CSID device
13888c2ecf20Sopenharmony_ci */
13898c2ecf20Sopenharmony_civoid msm_csid_unregister_entity(struct csid_device *csid)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	v4l2_device_unregister_subdev(&csid->subdev);
13928c2ecf20Sopenharmony_ci	media_entity_cleanup(&csid->subdev.entity);
13938c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&csid->ctrls);
13948c2ecf20Sopenharmony_ci}
1395