162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * camss.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Qualcomm MSM Camera Subsystem - Core
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2015, The Linux Foundation. All rights reserved.
862306a36Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/interconnect.h>
1262306a36Sopenharmony_ci#include <linux/media-bus-format.h>
1362306a36Sopenharmony_ci#include <linux/media.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/of_graph.h>
1862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1962306a36Sopenharmony_ci#include <linux/pm_domain.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/videodev2.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <media/media-device.h>
2462306a36Sopenharmony_ci#include <media/v4l2-async.h>
2562306a36Sopenharmony_ci#include <media/v4l2-device.h>
2662306a36Sopenharmony_ci#include <media/v4l2-mc.h>
2762306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "camss.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define CAMSS_CLOCK_MARGIN_NUMERATOR 105
3262306a36Sopenharmony_ci#define CAMSS_CLOCK_MARGIN_DENOMINATOR 100
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const struct resources csiphy_res_8x16[] = {
3562306a36Sopenharmony_ci	/* CSIPHY0 */
3662306a36Sopenharmony_ci	{
3762306a36Sopenharmony_ci		.regulators = {},
3862306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" },
3962306a36Sopenharmony_ci		.clock_rate = { { 0 },
4062306a36Sopenharmony_ci				{ 0 },
4162306a36Sopenharmony_ci				{ 0 },
4262306a36Sopenharmony_ci				{ 100000000, 200000000 } },
4362306a36Sopenharmony_ci		.reg = { "csiphy0", "csiphy0_clk_mux" },
4462306a36Sopenharmony_ci		.interrupt = { "csiphy0" }
4562306a36Sopenharmony_ci	},
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* CSIPHY1 */
4862306a36Sopenharmony_ci	{
4962306a36Sopenharmony_ci		.regulators = {},
5062306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" },
5162306a36Sopenharmony_ci		.clock_rate = { { 0 },
5262306a36Sopenharmony_ci				{ 0 },
5362306a36Sopenharmony_ci				{ 0 },
5462306a36Sopenharmony_ci				{ 100000000, 200000000 } },
5562306a36Sopenharmony_ci		.reg = { "csiphy1", "csiphy1_clk_mux" },
5662306a36Sopenharmony_ci		.interrupt = { "csiphy1" }
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic const struct resources csid_res_8x16[] = {
6162306a36Sopenharmony_ci	/* CSID0 */
6262306a36Sopenharmony_ci	{
6362306a36Sopenharmony_ci		.regulators = { "vdda" },
6462306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
6562306a36Sopenharmony_ci			   "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" },
6662306a36Sopenharmony_ci		.clock_rate = { { 0 },
6762306a36Sopenharmony_ci				{ 0 },
6862306a36Sopenharmony_ci				{ 0 },
6962306a36Sopenharmony_ci				{ 0 },
7062306a36Sopenharmony_ci				{ 100000000, 200000000 },
7162306a36Sopenharmony_ci				{ 0 },
7262306a36Sopenharmony_ci				{ 0 },
7362306a36Sopenharmony_ci				{ 0 } },
7462306a36Sopenharmony_ci		.reg = { "csid0" },
7562306a36Sopenharmony_ci		.interrupt = { "csid0" }
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* CSID1 */
7962306a36Sopenharmony_ci	{
8062306a36Sopenharmony_ci		.regulators = { "vdda" },
8162306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
8262306a36Sopenharmony_ci			   "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" },
8362306a36Sopenharmony_ci		.clock_rate = { { 0 },
8462306a36Sopenharmony_ci				{ 0 },
8562306a36Sopenharmony_ci				{ 0 },
8662306a36Sopenharmony_ci				{ 0 },
8762306a36Sopenharmony_ci				{ 100000000, 200000000 },
8862306a36Sopenharmony_ci				{ 0 },
8962306a36Sopenharmony_ci				{ 0 },
9062306a36Sopenharmony_ci				{ 0 } },
9162306a36Sopenharmony_ci		.reg = { "csid1" },
9262306a36Sopenharmony_ci		.interrupt = { "csid1" }
9362306a36Sopenharmony_ci	},
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic const struct resources_ispif ispif_res_8x16 = {
9762306a36Sopenharmony_ci	/* ISPIF */
9862306a36Sopenharmony_ci	.clock = { "top_ahb", "ahb", "ispif_ahb",
9962306a36Sopenharmony_ci		   "csi0", "csi0_pix", "csi0_rdi",
10062306a36Sopenharmony_ci		   "csi1", "csi1_pix", "csi1_rdi" },
10162306a36Sopenharmony_ci	.clock_for_reset = { "vfe0", "csi_vfe0" },
10262306a36Sopenharmony_ci	.reg = { "ispif", "csi_clk_mux" },
10362306a36Sopenharmony_ci	.interrupt = "ispif"
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const struct resources vfe_res_8x16[] = {
10862306a36Sopenharmony_ci	/* VFE0 */
10962306a36Sopenharmony_ci	{
11062306a36Sopenharmony_ci		.regulators = {},
11162306a36Sopenharmony_ci		.clock = { "top_ahb", "vfe0", "csi_vfe0",
11262306a36Sopenharmony_ci			   "vfe_ahb", "vfe_axi", "ahb" },
11362306a36Sopenharmony_ci		.clock_rate = { { 0 },
11462306a36Sopenharmony_ci				{ 50000000, 80000000, 100000000, 160000000,
11562306a36Sopenharmony_ci				  177780000, 200000000, 266670000, 320000000,
11662306a36Sopenharmony_ci				  400000000, 465000000 },
11762306a36Sopenharmony_ci				{ 0 },
11862306a36Sopenharmony_ci				{ 0 },
11962306a36Sopenharmony_ci				{ 0 },
12062306a36Sopenharmony_ci				{ 0 },
12162306a36Sopenharmony_ci				{ 0 },
12262306a36Sopenharmony_ci				{ 0 },
12362306a36Sopenharmony_ci				{ 0 } },
12462306a36Sopenharmony_ci		.reg = { "vfe0" },
12562306a36Sopenharmony_ci		.interrupt = { "vfe0" }
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic const struct resources csiphy_res_8x96[] = {
13062306a36Sopenharmony_ci	/* CSIPHY0 */
13162306a36Sopenharmony_ci	{
13262306a36Sopenharmony_ci		.regulators = {},
13362306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" },
13462306a36Sopenharmony_ci		.clock_rate = { { 0 },
13562306a36Sopenharmony_ci				{ 0 },
13662306a36Sopenharmony_ci				{ 0 },
13762306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
13862306a36Sopenharmony_ci		.reg = { "csiphy0", "csiphy0_clk_mux" },
13962306a36Sopenharmony_ci		.interrupt = { "csiphy0" }
14062306a36Sopenharmony_ci	},
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* CSIPHY1 */
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		.regulators = {},
14562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" },
14662306a36Sopenharmony_ci		.clock_rate = { { 0 },
14762306a36Sopenharmony_ci				{ 0 },
14862306a36Sopenharmony_ci				{ 0 },
14962306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
15062306a36Sopenharmony_ci		.reg = { "csiphy1", "csiphy1_clk_mux" },
15162306a36Sopenharmony_ci		.interrupt = { "csiphy1" }
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* CSIPHY2 */
15562306a36Sopenharmony_ci	{
15662306a36Sopenharmony_ci		.regulators = {},
15762306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer" },
15862306a36Sopenharmony_ci		.clock_rate = { { 0 },
15962306a36Sopenharmony_ci				{ 0 },
16062306a36Sopenharmony_ci				{ 0 },
16162306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
16262306a36Sopenharmony_ci		.reg = { "csiphy2", "csiphy2_clk_mux" },
16362306a36Sopenharmony_ci		.interrupt = { "csiphy2" }
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic const struct resources csid_res_8x96[] = {
16862306a36Sopenharmony_ci	/* CSID0 */
16962306a36Sopenharmony_ci	{
17062306a36Sopenharmony_ci		.regulators = { "vdda" },
17162306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
17262306a36Sopenharmony_ci			   "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" },
17362306a36Sopenharmony_ci		.clock_rate = { { 0 },
17462306a36Sopenharmony_ci				{ 0 },
17562306a36Sopenharmony_ci				{ 0 },
17662306a36Sopenharmony_ci				{ 0 },
17762306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
17862306a36Sopenharmony_ci				{ 0 },
17962306a36Sopenharmony_ci				{ 0 },
18062306a36Sopenharmony_ci				{ 0 } },
18162306a36Sopenharmony_ci		.reg = { "csid0" },
18262306a36Sopenharmony_ci		.interrupt = { "csid0" }
18362306a36Sopenharmony_ci	},
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* CSID1 */
18662306a36Sopenharmony_ci	{
18762306a36Sopenharmony_ci		.regulators = { "vdda" },
18862306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
18962306a36Sopenharmony_ci			   "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" },
19062306a36Sopenharmony_ci		.clock_rate = { { 0 },
19162306a36Sopenharmony_ci				{ 0 },
19262306a36Sopenharmony_ci				{ 0 },
19362306a36Sopenharmony_ci				{ 0 },
19462306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
19562306a36Sopenharmony_ci				{ 0 },
19662306a36Sopenharmony_ci				{ 0 },
19762306a36Sopenharmony_ci				{ 0 } },
19862306a36Sopenharmony_ci		.reg = { "csid1" },
19962306a36Sopenharmony_ci		.interrupt = { "csid1" }
20062306a36Sopenharmony_ci	},
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* CSID2 */
20362306a36Sopenharmony_ci	{
20462306a36Sopenharmony_ci		.regulators = { "vdda" },
20562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
20662306a36Sopenharmony_ci			   "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" },
20762306a36Sopenharmony_ci		.clock_rate = { { 0 },
20862306a36Sopenharmony_ci				{ 0 },
20962306a36Sopenharmony_ci				{ 0 },
21062306a36Sopenharmony_ci				{ 0 },
21162306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
21262306a36Sopenharmony_ci				{ 0 },
21362306a36Sopenharmony_ci				{ 0 },
21462306a36Sopenharmony_ci				{ 0 } },
21562306a36Sopenharmony_ci		.reg = { "csid2" },
21662306a36Sopenharmony_ci		.interrupt = { "csid2" }
21762306a36Sopenharmony_ci	},
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* CSID3 */
22062306a36Sopenharmony_ci	{
22162306a36Sopenharmony_ci		.regulators = { "vdda" },
22262306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb",
22362306a36Sopenharmony_ci			   "csi3", "csi3_phy", "csi3_pix", "csi3_rdi" },
22462306a36Sopenharmony_ci		.clock_rate = { { 0 },
22562306a36Sopenharmony_ci				{ 0 },
22662306a36Sopenharmony_ci				{ 0 },
22762306a36Sopenharmony_ci				{ 0 },
22862306a36Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
22962306a36Sopenharmony_ci				{ 0 },
23062306a36Sopenharmony_ci				{ 0 },
23162306a36Sopenharmony_ci				{ 0 } },
23262306a36Sopenharmony_ci		.reg = { "csid3" },
23362306a36Sopenharmony_ci		.interrupt = { "csid3" }
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const struct resources_ispif ispif_res_8x96 = {
23862306a36Sopenharmony_ci	/* ISPIF */
23962306a36Sopenharmony_ci	.clock = { "top_ahb", "ahb", "ispif_ahb",
24062306a36Sopenharmony_ci		   "csi0", "csi0_pix", "csi0_rdi",
24162306a36Sopenharmony_ci		   "csi1", "csi1_pix", "csi1_rdi",
24262306a36Sopenharmony_ci		   "csi2", "csi2_pix", "csi2_rdi",
24362306a36Sopenharmony_ci		   "csi3", "csi3_pix", "csi3_rdi" },
24462306a36Sopenharmony_ci	.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
24562306a36Sopenharmony_ci	.reg = { "ispif", "csi_clk_mux" },
24662306a36Sopenharmony_ci	.interrupt = "ispif"
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic const struct resources vfe_res_8x96[] = {
25062306a36Sopenharmony_ci	/* VFE0 */
25162306a36Sopenharmony_ci	{
25262306a36Sopenharmony_ci		.regulators = {},
25362306a36Sopenharmony_ci		.clock = { "top_ahb", "ahb", "vfe0", "csi_vfe0", "vfe_ahb",
25462306a36Sopenharmony_ci			   "vfe0_ahb", "vfe_axi", "vfe0_stream"},
25562306a36Sopenharmony_ci		.clock_rate = { { 0 },
25662306a36Sopenharmony_ci				{ 0 },
25762306a36Sopenharmony_ci				{ 75000000, 100000000, 300000000,
25862306a36Sopenharmony_ci				  320000000, 480000000, 600000000 },
25962306a36Sopenharmony_ci				{ 0 },
26062306a36Sopenharmony_ci				{ 0 },
26162306a36Sopenharmony_ci				{ 0 },
26262306a36Sopenharmony_ci				{ 0 },
26362306a36Sopenharmony_ci				{ 0 } },
26462306a36Sopenharmony_ci		.reg = { "vfe0" },
26562306a36Sopenharmony_ci		.interrupt = { "vfe0" }
26662306a36Sopenharmony_ci	},
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* VFE1 */
26962306a36Sopenharmony_ci	{
27062306a36Sopenharmony_ci		.regulators = {},
27162306a36Sopenharmony_ci		.clock = { "top_ahb", "ahb", "vfe1", "csi_vfe1", "vfe_ahb",
27262306a36Sopenharmony_ci			   "vfe1_ahb", "vfe_axi", "vfe1_stream"},
27362306a36Sopenharmony_ci		.clock_rate = { { 0 },
27462306a36Sopenharmony_ci				{ 0 },
27562306a36Sopenharmony_ci				{ 75000000, 100000000, 300000000,
27662306a36Sopenharmony_ci				  320000000, 480000000, 600000000 },
27762306a36Sopenharmony_ci				{ 0 },
27862306a36Sopenharmony_ci				{ 0 },
27962306a36Sopenharmony_ci				{ 0 },
28062306a36Sopenharmony_ci				{ 0 },
28162306a36Sopenharmony_ci				{ 0 } },
28262306a36Sopenharmony_ci		.reg = { "vfe1" },
28362306a36Sopenharmony_ci		.interrupt = { "vfe1" }
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic const struct resources csiphy_res_660[] = {
28862306a36Sopenharmony_ci	/* CSIPHY0 */
28962306a36Sopenharmony_ci	{
29062306a36Sopenharmony_ci		.regulators = {},
29162306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer",
29262306a36Sopenharmony_ci			   "csi0_phy", "csiphy_ahb2crif" },
29362306a36Sopenharmony_ci		.clock_rate = { { 0 },
29462306a36Sopenharmony_ci				{ 0 },
29562306a36Sopenharmony_ci				{ 0 },
29662306a36Sopenharmony_ci				{ 100000000, 200000000, 269333333 },
29762306a36Sopenharmony_ci				{ 0 } },
29862306a36Sopenharmony_ci		.reg = { "csiphy0", "csiphy0_clk_mux" },
29962306a36Sopenharmony_ci		.interrupt = { "csiphy0" }
30062306a36Sopenharmony_ci	},
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* CSIPHY1 */
30362306a36Sopenharmony_ci	{
30462306a36Sopenharmony_ci		.regulators = {},
30562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer",
30662306a36Sopenharmony_ci			   "csi1_phy", "csiphy_ahb2crif" },
30762306a36Sopenharmony_ci		.clock_rate = { { 0 },
30862306a36Sopenharmony_ci				{ 0 },
30962306a36Sopenharmony_ci				{ 0 },
31062306a36Sopenharmony_ci				{ 100000000, 200000000, 269333333 },
31162306a36Sopenharmony_ci				{ 0 } },
31262306a36Sopenharmony_ci		.reg = { "csiphy1", "csiphy1_clk_mux" },
31362306a36Sopenharmony_ci		.interrupt = { "csiphy1" }
31462306a36Sopenharmony_ci	},
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* CSIPHY2 */
31762306a36Sopenharmony_ci	{
31862306a36Sopenharmony_ci		.regulators = {},
31962306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer",
32062306a36Sopenharmony_ci			   "csi2_phy", "csiphy_ahb2crif" },
32162306a36Sopenharmony_ci		.clock_rate = { { 0 },
32262306a36Sopenharmony_ci				{ 0 },
32362306a36Sopenharmony_ci				{ 0 },
32462306a36Sopenharmony_ci				{ 100000000, 200000000, 269333333 },
32562306a36Sopenharmony_ci				{ 0 } },
32662306a36Sopenharmony_ci		.reg = { "csiphy2", "csiphy2_clk_mux" },
32762306a36Sopenharmony_ci		.interrupt = { "csiphy2" }
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic const struct resources csid_res_660[] = {
33262306a36Sopenharmony_ci	/* CSID0 */
33362306a36Sopenharmony_ci	{
33462306a36Sopenharmony_ci		.regulators = { "vdda", "vdd_sec" },
33562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
33662306a36Sopenharmony_ci			   "csi0", "csi0_phy", "csi0_pix", "csi0_rdi",
33762306a36Sopenharmony_ci			   "cphy_csid0" },
33862306a36Sopenharmony_ci		.clock_rate = { { 0 },
33962306a36Sopenharmony_ci				{ 0 },
34062306a36Sopenharmony_ci				{ 0 },
34162306a36Sopenharmony_ci				{ 0 },
34262306a36Sopenharmony_ci				{ 100000000, 200000000, 310000000,
34362306a36Sopenharmony_ci				  404000000, 465000000 },
34462306a36Sopenharmony_ci				{ 0 },
34562306a36Sopenharmony_ci				{ 0 },
34662306a36Sopenharmony_ci				{ 0 },
34762306a36Sopenharmony_ci				{ 0 } },
34862306a36Sopenharmony_ci		.reg = { "csid0" },
34962306a36Sopenharmony_ci		.interrupt = { "csid0" }
35062306a36Sopenharmony_ci	},
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* CSID1 */
35362306a36Sopenharmony_ci	{
35462306a36Sopenharmony_ci		.regulators = { "vdda", "vdd_sec" },
35562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
35662306a36Sopenharmony_ci			   "csi1", "csi1_phy", "csi1_pix", "csi1_rdi",
35762306a36Sopenharmony_ci			   "cphy_csid1" },
35862306a36Sopenharmony_ci		.clock_rate = { { 0 },
35962306a36Sopenharmony_ci				{ 0 },
36062306a36Sopenharmony_ci				{ 0 },
36162306a36Sopenharmony_ci				{ 0 },
36262306a36Sopenharmony_ci				{ 100000000, 200000000, 310000000,
36362306a36Sopenharmony_ci				  404000000, 465000000 },
36462306a36Sopenharmony_ci				{ 0 },
36562306a36Sopenharmony_ci				{ 0 },
36662306a36Sopenharmony_ci				{ 0 },
36762306a36Sopenharmony_ci				{ 0 } },
36862306a36Sopenharmony_ci		.reg = { "csid1" },
36962306a36Sopenharmony_ci		.interrupt = { "csid1" }
37062306a36Sopenharmony_ci	},
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* CSID2 */
37362306a36Sopenharmony_ci	{
37462306a36Sopenharmony_ci		.regulators = { "vdda", "vdd_sec" },
37562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
37662306a36Sopenharmony_ci			   "csi2", "csi2_phy", "csi2_pix", "csi2_rdi",
37762306a36Sopenharmony_ci			   "cphy_csid2" },
37862306a36Sopenharmony_ci		.clock_rate = { { 0 },
37962306a36Sopenharmony_ci				{ 0 },
38062306a36Sopenharmony_ci				{ 0 },
38162306a36Sopenharmony_ci				{ 0 },
38262306a36Sopenharmony_ci				{ 100000000, 200000000, 310000000,
38362306a36Sopenharmony_ci				  404000000, 465000000 },
38462306a36Sopenharmony_ci				{ 0 },
38562306a36Sopenharmony_ci				{ 0 },
38662306a36Sopenharmony_ci				{ 0 },
38762306a36Sopenharmony_ci				{ 0 } },
38862306a36Sopenharmony_ci		.reg = { "csid2" },
38962306a36Sopenharmony_ci		.interrupt = { "csid2" }
39062306a36Sopenharmony_ci	},
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* CSID3 */
39362306a36Sopenharmony_ci	{
39462306a36Sopenharmony_ci		.regulators = { "vdda", "vdd_sec" },
39562306a36Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb",
39662306a36Sopenharmony_ci			   "csi3", "csi3_phy", "csi3_pix", "csi3_rdi",
39762306a36Sopenharmony_ci			   "cphy_csid3" },
39862306a36Sopenharmony_ci		.clock_rate = { { 0 },
39962306a36Sopenharmony_ci				{ 0 },
40062306a36Sopenharmony_ci				{ 0 },
40162306a36Sopenharmony_ci				{ 0 },
40262306a36Sopenharmony_ci				{ 100000000, 200000000, 310000000,
40362306a36Sopenharmony_ci				  404000000, 465000000 },
40462306a36Sopenharmony_ci				{ 0 },
40562306a36Sopenharmony_ci				{ 0 },
40662306a36Sopenharmony_ci				{ 0 },
40762306a36Sopenharmony_ci				{ 0 } },
40862306a36Sopenharmony_ci		.reg = { "csid3" },
40962306a36Sopenharmony_ci		.interrupt = { "csid3" }
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci};
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic const struct resources_ispif ispif_res_660 = {
41462306a36Sopenharmony_ci	/* ISPIF */
41562306a36Sopenharmony_ci	.clock = { "top_ahb", "ahb", "ispif_ahb",
41662306a36Sopenharmony_ci		   "csi0", "csi0_pix", "csi0_rdi",
41762306a36Sopenharmony_ci		   "csi1", "csi1_pix", "csi1_rdi",
41862306a36Sopenharmony_ci		   "csi2", "csi2_pix", "csi2_rdi",
41962306a36Sopenharmony_ci		   "csi3", "csi3_pix", "csi3_rdi" },
42062306a36Sopenharmony_ci	.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
42162306a36Sopenharmony_ci	.reg = { "ispif", "csi_clk_mux" },
42262306a36Sopenharmony_ci	.interrupt = "ispif"
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic const struct resources vfe_res_660[] = {
42662306a36Sopenharmony_ci	/* VFE0 */
42762306a36Sopenharmony_ci	{
42862306a36Sopenharmony_ci		.regulators = {},
42962306a36Sopenharmony_ci		.clock = { "throttle_axi", "top_ahb", "ahb", "vfe0",
43062306a36Sopenharmony_ci			   "csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi",
43162306a36Sopenharmony_ci			   "vfe0_stream"},
43262306a36Sopenharmony_ci		.clock_rate = { { 0 },
43362306a36Sopenharmony_ci				{ 0 },
43462306a36Sopenharmony_ci				{ 0 },
43562306a36Sopenharmony_ci				{ 120000000, 200000000, 256000000,
43662306a36Sopenharmony_ci				  300000000, 404000000, 480000000,
43762306a36Sopenharmony_ci				  540000000, 576000000 },
43862306a36Sopenharmony_ci				{ 0 },
43962306a36Sopenharmony_ci				{ 0 },
44062306a36Sopenharmony_ci				{ 0 },
44162306a36Sopenharmony_ci				{ 0 },
44262306a36Sopenharmony_ci				{ 0 } },
44362306a36Sopenharmony_ci		.reg = { "vfe0" },
44462306a36Sopenharmony_ci		.interrupt = { "vfe0" }
44562306a36Sopenharmony_ci	},
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* VFE1 */
44862306a36Sopenharmony_ci	{
44962306a36Sopenharmony_ci		.regulators = {},
45062306a36Sopenharmony_ci		.clock = { "throttle_axi", "top_ahb", "ahb", "vfe1",
45162306a36Sopenharmony_ci			   "csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi",
45262306a36Sopenharmony_ci			   "vfe1_stream"},
45362306a36Sopenharmony_ci		.clock_rate = { { 0 },
45462306a36Sopenharmony_ci				{ 0 },
45562306a36Sopenharmony_ci				{ 0 },
45662306a36Sopenharmony_ci				{ 120000000, 200000000, 256000000,
45762306a36Sopenharmony_ci				  300000000, 404000000, 480000000,
45862306a36Sopenharmony_ci				  540000000, 576000000 },
45962306a36Sopenharmony_ci				{ 0 },
46062306a36Sopenharmony_ci				{ 0 },
46162306a36Sopenharmony_ci				{ 0 },
46262306a36Sopenharmony_ci				{ 0 },
46362306a36Sopenharmony_ci				{ 0 } },
46462306a36Sopenharmony_ci		.reg = { "vfe1" },
46562306a36Sopenharmony_ci		.interrupt = { "vfe1" }
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci};
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic const struct resources csiphy_res_845[] = {
47062306a36Sopenharmony_ci	/* CSIPHY0 */
47162306a36Sopenharmony_ci	{
47262306a36Sopenharmony_ci		.regulators = {},
47362306a36Sopenharmony_ci		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
47462306a36Sopenharmony_ci				"cpas_ahb", "cphy_rx_src", "csiphy0",
47562306a36Sopenharmony_ci				"csiphy0_timer_src", "csiphy0_timer" },
47662306a36Sopenharmony_ci		.clock_rate = { { 0 },
47762306a36Sopenharmony_ci				{ 0 },
47862306a36Sopenharmony_ci				{ 0 },
47962306a36Sopenharmony_ci				{ 0 },
48062306a36Sopenharmony_ci				{ 0 },
48162306a36Sopenharmony_ci				{ 0 },
48262306a36Sopenharmony_ci				{ 0 },
48362306a36Sopenharmony_ci				{ 19200000, 240000000, 269333333 } },
48462306a36Sopenharmony_ci		.reg = { "csiphy0" },
48562306a36Sopenharmony_ci		.interrupt = { "csiphy0" }
48662306a36Sopenharmony_ci	},
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* CSIPHY1 */
48962306a36Sopenharmony_ci	{
49062306a36Sopenharmony_ci		.regulators = {},
49162306a36Sopenharmony_ci		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
49262306a36Sopenharmony_ci				"cpas_ahb", "cphy_rx_src", "csiphy1",
49362306a36Sopenharmony_ci				"csiphy1_timer_src", "csiphy1_timer" },
49462306a36Sopenharmony_ci		.clock_rate = { { 0 },
49562306a36Sopenharmony_ci				{ 0 },
49662306a36Sopenharmony_ci				{ 0 },
49762306a36Sopenharmony_ci				{ 0 },
49862306a36Sopenharmony_ci				{ 0 },
49962306a36Sopenharmony_ci				{ 0 },
50062306a36Sopenharmony_ci				{ 0 },
50162306a36Sopenharmony_ci				{ 19200000, 240000000, 269333333 } },
50262306a36Sopenharmony_ci		.reg = { "csiphy1" },
50362306a36Sopenharmony_ci		.interrupt = { "csiphy1" }
50462306a36Sopenharmony_ci	},
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* CSIPHY2 */
50762306a36Sopenharmony_ci	{
50862306a36Sopenharmony_ci		.regulators = {},
50962306a36Sopenharmony_ci		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
51062306a36Sopenharmony_ci				"cpas_ahb", "cphy_rx_src", "csiphy2",
51162306a36Sopenharmony_ci				"csiphy2_timer_src", "csiphy2_timer" },
51262306a36Sopenharmony_ci		.clock_rate = { { 0 },
51362306a36Sopenharmony_ci				{ 0 },
51462306a36Sopenharmony_ci				{ 0 },
51562306a36Sopenharmony_ci				{ 0 },
51662306a36Sopenharmony_ci				{ 0 },
51762306a36Sopenharmony_ci				{ 0 },
51862306a36Sopenharmony_ci				{ 0 },
51962306a36Sopenharmony_ci				{ 19200000, 240000000, 269333333 } },
52062306a36Sopenharmony_ci		.reg = { "csiphy2" },
52162306a36Sopenharmony_ci		.interrupt = { "csiphy2" }
52262306a36Sopenharmony_ci	},
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* CSIPHY3 */
52562306a36Sopenharmony_ci	{
52662306a36Sopenharmony_ci		.regulators = {},
52762306a36Sopenharmony_ci		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
52862306a36Sopenharmony_ci				"cpas_ahb", "cphy_rx_src", "csiphy3",
52962306a36Sopenharmony_ci				"csiphy3_timer_src", "csiphy3_timer" },
53062306a36Sopenharmony_ci		.clock_rate = { { 0 },
53162306a36Sopenharmony_ci				{ 0 },
53262306a36Sopenharmony_ci				{ 0 },
53362306a36Sopenharmony_ci				{ 0 },
53462306a36Sopenharmony_ci				{ 0 },
53562306a36Sopenharmony_ci				{ 0 },
53662306a36Sopenharmony_ci				{ 0 },
53762306a36Sopenharmony_ci				{ 19200000, 240000000, 269333333 } },
53862306a36Sopenharmony_ci		.reg = { "csiphy3" },
53962306a36Sopenharmony_ci		.interrupt = { "csiphy3" }
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci};
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic const struct resources csid_res_845[] = {
54462306a36Sopenharmony_ci	/* CSID0 */
54562306a36Sopenharmony_ci	{
54662306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
54762306a36Sopenharmony_ci		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
54862306a36Sopenharmony_ci				"soc_ahb", "vfe0", "vfe0_src",
54962306a36Sopenharmony_ci				"vfe0_cphy_rx", "csi0",
55062306a36Sopenharmony_ci				"csi0_src" },
55162306a36Sopenharmony_ci		.clock_rate = { { 0 },
55262306a36Sopenharmony_ci				{ 384000000 },
55362306a36Sopenharmony_ci				{ 80000000 },
55462306a36Sopenharmony_ci				{ 0 },
55562306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
55662306a36Sopenharmony_ci				{ 320000000 },
55762306a36Sopenharmony_ci				{ 0 },
55862306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
55962306a36Sopenharmony_ci				{ 384000000 } },
56062306a36Sopenharmony_ci		.reg = { "csid0" },
56162306a36Sopenharmony_ci		.interrupt = { "csid0" }
56262306a36Sopenharmony_ci	},
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* CSID1 */
56562306a36Sopenharmony_ci	{
56662306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
56762306a36Sopenharmony_ci		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
56862306a36Sopenharmony_ci				"soc_ahb", "vfe1", "vfe1_src",
56962306a36Sopenharmony_ci				"vfe1_cphy_rx", "csi1",
57062306a36Sopenharmony_ci				"csi1_src" },
57162306a36Sopenharmony_ci		.clock_rate = { { 0 },
57262306a36Sopenharmony_ci				{ 384000000 },
57362306a36Sopenharmony_ci				{ 80000000 },
57462306a36Sopenharmony_ci				{ 0 },
57562306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
57662306a36Sopenharmony_ci				{ 320000000 },
57762306a36Sopenharmony_ci				{ 0 },
57862306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
57962306a36Sopenharmony_ci				{ 384000000 } },
58062306a36Sopenharmony_ci		.reg = { "csid1" },
58162306a36Sopenharmony_ci		.interrupt = { "csid1" }
58262306a36Sopenharmony_ci	},
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* CSID2 */
58562306a36Sopenharmony_ci	{
58662306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
58762306a36Sopenharmony_ci		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
58862306a36Sopenharmony_ci				"soc_ahb", "vfe_lite", "vfe_lite_src",
58962306a36Sopenharmony_ci				"vfe_lite_cphy_rx", "csi2",
59062306a36Sopenharmony_ci				"csi2_src" },
59162306a36Sopenharmony_ci		.clock_rate = { { 0 },
59262306a36Sopenharmony_ci				{ 384000000 },
59362306a36Sopenharmony_ci				{ 80000000 },
59462306a36Sopenharmony_ci				{ 0 },
59562306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
59662306a36Sopenharmony_ci				{ 320000000 },
59762306a36Sopenharmony_ci				{ 0 },
59862306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
59962306a36Sopenharmony_ci				{ 384000000 } },
60062306a36Sopenharmony_ci		.reg = { "csid2" },
60162306a36Sopenharmony_ci		.interrupt = { "csid2" }
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci};
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic const struct resources vfe_res_845[] = {
60662306a36Sopenharmony_ci	/* VFE0 */
60762306a36Sopenharmony_ci	{
60862306a36Sopenharmony_ci		.regulators = {},
60962306a36Sopenharmony_ci		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
61062306a36Sopenharmony_ci				"soc_ahb", "vfe0", "vfe0_axi",
61162306a36Sopenharmony_ci				"vfe0_src", "csi0",
61262306a36Sopenharmony_ci				"csi0_src"},
61362306a36Sopenharmony_ci		.clock_rate = { { 0 },
61462306a36Sopenharmony_ci				{ 0 },
61562306a36Sopenharmony_ci				{ 80000000 },
61662306a36Sopenharmony_ci				{ 0 },
61762306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
61862306a36Sopenharmony_ci				{ 0 },
61962306a36Sopenharmony_ci				{ 320000000 },
62062306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
62162306a36Sopenharmony_ci				{ 384000000 } },
62262306a36Sopenharmony_ci		.reg = { "vfe0" },
62362306a36Sopenharmony_ci		.interrupt = { "vfe0" }
62462306a36Sopenharmony_ci	},
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* VFE1 */
62762306a36Sopenharmony_ci	{
62862306a36Sopenharmony_ci		.regulators = {},
62962306a36Sopenharmony_ci		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
63062306a36Sopenharmony_ci				"soc_ahb", "vfe1", "vfe1_axi",
63162306a36Sopenharmony_ci				"vfe1_src", "csi1",
63262306a36Sopenharmony_ci				"csi1_src"},
63362306a36Sopenharmony_ci		.clock_rate = { { 0 },
63462306a36Sopenharmony_ci				{ 0 },
63562306a36Sopenharmony_ci				{ 80000000 },
63662306a36Sopenharmony_ci				{ 0 },
63762306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
63862306a36Sopenharmony_ci				{ 0 },
63962306a36Sopenharmony_ci				{ 320000000 },
64062306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
64162306a36Sopenharmony_ci				{ 384000000 } },
64262306a36Sopenharmony_ci		.reg = { "vfe1" },
64362306a36Sopenharmony_ci		.interrupt = { "vfe1" }
64462306a36Sopenharmony_ci	},
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* VFE-lite */
64762306a36Sopenharmony_ci	{
64862306a36Sopenharmony_ci		.regulators = {},
64962306a36Sopenharmony_ci		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
65062306a36Sopenharmony_ci				"soc_ahb", "vfe_lite",
65162306a36Sopenharmony_ci				"vfe_lite_src", "csi2",
65262306a36Sopenharmony_ci				"csi2_src"},
65362306a36Sopenharmony_ci		.clock_rate = { { 0 },
65462306a36Sopenharmony_ci				{ 0 },
65562306a36Sopenharmony_ci				{ 80000000 },
65662306a36Sopenharmony_ci				{ 0 },
65762306a36Sopenharmony_ci				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
65862306a36Sopenharmony_ci				{ 320000000 },
65962306a36Sopenharmony_ci				{ 19200000, 75000000, 384000000, 538666667 },
66062306a36Sopenharmony_ci				{ 384000000 } },
66162306a36Sopenharmony_ci		.reg = { "vfe_lite" },
66262306a36Sopenharmony_ci		.interrupt = { "vfe_lite" }
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci};
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic const struct resources csiphy_res_8250[] = {
66762306a36Sopenharmony_ci	/* CSIPHY0 */
66862306a36Sopenharmony_ci	{
66962306a36Sopenharmony_ci		.regulators = {},
67062306a36Sopenharmony_ci		.clock = { "csiphy0", "csiphy0_timer" },
67162306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
67262306a36Sopenharmony_ci				{ 300000000 } },
67362306a36Sopenharmony_ci		.reg = { "csiphy0" },
67462306a36Sopenharmony_ci		.interrupt = { "csiphy0" }
67562306a36Sopenharmony_ci	},
67662306a36Sopenharmony_ci	/* CSIPHY1 */
67762306a36Sopenharmony_ci	{
67862306a36Sopenharmony_ci		.regulators = {},
67962306a36Sopenharmony_ci		.clock = { "csiphy1", "csiphy1_timer" },
68062306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
68162306a36Sopenharmony_ci				{ 300000000 } },
68262306a36Sopenharmony_ci		.reg = { "csiphy1" },
68362306a36Sopenharmony_ci		.interrupt = { "csiphy1" }
68462306a36Sopenharmony_ci	},
68562306a36Sopenharmony_ci	/* CSIPHY2 */
68662306a36Sopenharmony_ci	{
68762306a36Sopenharmony_ci		.regulators = {},
68862306a36Sopenharmony_ci		.clock = { "csiphy2", "csiphy2_timer" },
68962306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
69062306a36Sopenharmony_ci				{ 300000000 } },
69162306a36Sopenharmony_ci		.reg = { "csiphy2" },
69262306a36Sopenharmony_ci		.interrupt = { "csiphy2" }
69362306a36Sopenharmony_ci	},
69462306a36Sopenharmony_ci	/* CSIPHY3 */
69562306a36Sopenharmony_ci	{
69662306a36Sopenharmony_ci		.regulators = {},
69762306a36Sopenharmony_ci		.clock = { "csiphy3", "csiphy3_timer" },
69862306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
69962306a36Sopenharmony_ci				{ 300000000 } },
70062306a36Sopenharmony_ci		.reg = { "csiphy3" },
70162306a36Sopenharmony_ci		.interrupt = { "csiphy3" }
70262306a36Sopenharmony_ci	},
70362306a36Sopenharmony_ci	/* CSIPHY4 */
70462306a36Sopenharmony_ci	{
70562306a36Sopenharmony_ci		.regulators = {},
70662306a36Sopenharmony_ci		.clock = { "csiphy4", "csiphy4_timer" },
70762306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
70862306a36Sopenharmony_ci				{ 300000000 } },
70962306a36Sopenharmony_ci		.reg = { "csiphy4" },
71062306a36Sopenharmony_ci		.interrupt = { "csiphy4" }
71162306a36Sopenharmony_ci	},
71262306a36Sopenharmony_ci	/* CSIPHY5 */
71362306a36Sopenharmony_ci	{
71462306a36Sopenharmony_ci		.regulators = {},
71562306a36Sopenharmony_ci		.clock = { "csiphy5", "csiphy5_timer" },
71662306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
71762306a36Sopenharmony_ci				{ 300000000 } },
71862306a36Sopenharmony_ci		.reg = { "csiphy5" },
71962306a36Sopenharmony_ci		.interrupt = { "csiphy5" }
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci};
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic const struct resources csid_res_8250[] = {
72462306a36Sopenharmony_ci	/* CSID0 */
72562306a36Sopenharmony_ci	{
72662306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
72762306a36Sopenharmony_ci		.clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" },
72862306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
72962306a36Sopenharmony_ci				{ 400000000 },
73062306a36Sopenharmony_ci				{ 350000000, 475000000, 576000000, 720000000 },
73162306a36Sopenharmony_ci				{ 100000000, 200000000, 300000000, 400000000 },
73262306a36Sopenharmony_ci				{ 0 } },
73362306a36Sopenharmony_ci		.reg = { "csid0" },
73462306a36Sopenharmony_ci		.interrupt = { "csid0" }
73562306a36Sopenharmony_ci	},
73662306a36Sopenharmony_ci	/* CSID1 */
73762306a36Sopenharmony_ci	{
73862306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
73962306a36Sopenharmony_ci		.clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" },
74062306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
74162306a36Sopenharmony_ci				{ 400000000 },
74262306a36Sopenharmony_ci				{ 350000000, 475000000, 576000000, 720000000 },
74362306a36Sopenharmony_ci				{ 100000000, 200000000, 300000000, 400000000 },
74462306a36Sopenharmony_ci				{ 0 } },
74562306a36Sopenharmony_ci		.reg = { "csid1" },
74662306a36Sopenharmony_ci		.interrupt = { "csid1" }
74762306a36Sopenharmony_ci	},
74862306a36Sopenharmony_ci	/* CSID2 */
74962306a36Sopenharmony_ci	{
75062306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
75162306a36Sopenharmony_ci		.clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite",  "vfe_lite_ahb" },
75262306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
75362306a36Sopenharmony_ci				{ 400000000 },
75462306a36Sopenharmony_ci				{ 400000000, 480000000 },
75562306a36Sopenharmony_ci				{ 0 } },
75662306a36Sopenharmony_ci		.reg = { "csid2" },
75762306a36Sopenharmony_ci		.interrupt = { "csid2" }
75862306a36Sopenharmony_ci	},
75962306a36Sopenharmony_ci	/* CSID3 */
76062306a36Sopenharmony_ci	{
76162306a36Sopenharmony_ci		.regulators = { "vdda-phy", "vdda-pll" },
76262306a36Sopenharmony_ci		.clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite",  "vfe_lite_ahb" },
76362306a36Sopenharmony_ci		.clock_rate = { { 400000000 },
76462306a36Sopenharmony_ci				{ 400000000 },
76562306a36Sopenharmony_ci				{ 400000000, 480000000 },
76662306a36Sopenharmony_ci				{ 0 } },
76762306a36Sopenharmony_ci		.reg = { "csid3" },
76862306a36Sopenharmony_ci		.interrupt = { "csid3" }
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci};
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic const struct resources vfe_res_8250[] = {
77362306a36Sopenharmony_ci	/* VFE0 */
77462306a36Sopenharmony_ci	{
77562306a36Sopenharmony_ci		.regulators = {},
77662306a36Sopenharmony_ci		.clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb",
77762306a36Sopenharmony_ci			   "camnoc_axi", "vfe0_ahb", "vfe0_areg", "vfe0",
77862306a36Sopenharmony_ci			   "vfe0_axi", "cam_hf_axi" },
77962306a36Sopenharmony_ci		.clock_rate = { { 19200000, 300000000, 400000000, 480000000 },
78062306a36Sopenharmony_ci				{ 19200000, 80000000 },
78162306a36Sopenharmony_ci				{ 19200000 },
78262306a36Sopenharmony_ci				{ 0 },
78362306a36Sopenharmony_ci				{ 0 },
78462306a36Sopenharmony_ci				{ 100000000, 200000000, 300000000, 400000000 },
78562306a36Sopenharmony_ci				{ 350000000, 475000000, 576000000, 720000000 },
78662306a36Sopenharmony_ci				{ 0 },
78762306a36Sopenharmony_ci				{ 0 } },
78862306a36Sopenharmony_ci		.reg = { "vfe0" },
78962306a36Sopenharmony_ci		.interrupt = { "vfe0" }
79062306a36Sopenharmony_ci	},
79162306a36Sopenharmony_ci	/* VFE1 */
79262306a36Sopenharmony_ci	{
79362306a36Sopenharmony_ci		.regulators = {},
79462306a36Sopenharmony_ci		.clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb",
79562306a36Sopenharmony_ci			   "camnoc_axi", "vfe1_ahb", "vfe1_areg", "vfe1",
79662306a36Sopenharmony_ci			   "vfe1_axi", "cam_hf_axi" },
79762306a36Sopenharmony_ci		.clock_rate = { { 19200000, 300000000, 400000000, 480000000 },
79862306a36Sopenharmony_ci				{ 19200000, 80000000 },
79962306a36Sopenharmony_ci				{ 19200000 },
80062306a36Sopenharmony_ci				{ 0 },
80162306a36Sopenharmony_ci				{ 0 },
80262306a36Sopenharmony_ci				{ 100000000, 200000000, 300000000, 400000000 },
80362306a36Sopenharmony_ci				{ 350000000, 475000000, 576000000, 720000000 },
80462306a36Sopenharmony_ci				{ 0 },
80562306a36Sopenharmony_ci				{ 0 } },
80662306a36Sopenharmony_ci		.reg = { "vfe1" },
80762306a36Sopenharmony_ci		.interrupt = { "vfe1" }
80862306a36Sopenharmony_ci	},
80962306a36Sopenharmony_ci	/* VFE2 (lite) */
81062306a36Sopenharmony_ci	{
81162306a36Sopenharmony_ci		.regulators = {},
81262306a36Sopenharmony_ci		.clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb",
81362306a36Sopenharmony_ci			   "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi",
81462306a36Sopenharmony_ci			   "vfe_lite", "cam_hf_axi" },
81562306a36Sopenharmony_ci		.clock_rate = { { 19200000, 300000000, 400000000, 480000000 },
81662306a36Sopenharmony_ci				{ 19200000, 80000000 },
81762306a36Sopenharmony_ci				{ 19200000 },
81862306a36Sopenharmony_ci				{ 0 },
81962306a36Sopenharmony_ci				{ 0 },
82062306a36Sopenharmony_ci				{ 0 },
82162306a36Sopenharmony_ci				{ 400000000, 480000000 },
82262306a36Sopenharmony_ci				{ 0 } },
82362306a36Sopenharmony_ci		.reg = { "vfe_lite0" },
82462306a36Sopenharmony_ci		.interrupt = { "vfe_lite0" }
82562306a36Sopenharmony_ci	},
82662306a36Sopenharmony_ci	/* VFE3 (lite) */
82762306a36Sopenharmony_ci	{
82862306a36Sopenharmony_ci		.regulators = {},
82962306a36Sopenharmony_ci		.clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb",
83062306a36Sopenharmony_ci			   "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi",
83162306a36Sopenharmony_ci			   "vfe_lite", "cam_hf_axi" },
83262306a36Sopenharmony_ci		.clock_rate = { { 19200000, 300000000, 400000000, 480000000 },
83362306a36Sopenharmony_ci				{ 19200000, 80000000 },
83462306a36Sopenharmony_ci				{ 19200000 },
83562306a36Sopenharmony_ci				{ 0 },
83662306a36Sopenharmony_ci				{ 0 },
83762306a36Sopenharmony_ci				{ 0 },
83862306a36Sopenharmony_ci				{ 400000000, 480000000 },
83962306a36Sopenharmony_ci				{ 0 } },
84062306a36Sopenharmony_ci		.reg = { "vfe_lite1" },
84162306a36Sopenharmony_ci		.interrupt = { "vfe_lite1" }
84262306a36Sopenharmony_ci	},
84362306a36Sopenharmony_ci};
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic const struct resources_icc icc_res_sm8250[] = {
84662306a36Sopenharmony_ci	{
84762306a36Sopenharmony_ci		.name = "cam_ahb",
84862306a36Sopenharmony_ci		.icc_bw_tbl.avg = 38400,
84962306a36Sopenharmony_ci		.icc_bw_tbl.peak = 76800,
85062306a36Sopenharmony_ci	},
85162306a36Sopenharmony_ci	{
85262306a36Sopenharmony_ci		.name = "cam_hf_0_mnoc",
85362306a36Sopenharmony_ci		.icc_bw_tbl.avg = 2097152,
85462306a36Sopenharmony_ci		.icc_bw_tbl.peak = 2097152,
85562306a36Sopenharmony_ci	},
85662306a36Sopenharmony_ci	{
85762306a36Sopenharmony_ci		.name = "cam_sf_0_mnoc",
85862306a36Sopenharmony_ci		.icc_bw_tbl.avg = 0,
85962306a36Sopenharmony_ci		.icc_bw_tbl.peak = 2097152,
86062306a36Sopenharmony_ci	},
86162306a36Sopenharmony_ci	{
86262306a36Sopenharmony_ci		.name = "cam_sf_icp_mnoc",
86362306a36Sopenharmony_ci		.icc_bw_tbl.avg = 2097152,
86462306a36Sopenharmony_ci		.icc_bw_tbl.peak = 2097152,
86562306a36Sopenharmony_ci	},
86662306a36Sopenharmony_ci};
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/*
86962306a36Sopenharmony_ci * camss_add_clock_margin - Add margin to clock frequency rate
87062306a36Sopenharmony_ci * @rate: Clock frequency rate
87162306a36Sopenharmony_ci *
87262306a36Sopenharmony_ci * When making calculations with physical clock frequency values
87362306a36Sopenharmony_ci * some safety margin must be added. Add it.
87462306a36Sopenharmony_ci */
87562306a36Sopenharmony_ciinline void camss_add_clock_margin(u64 *rate)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	*rate *= CAMSS_CLOCK_MARGIN_NUMERATOR;
87862306a36Sopenharmony_ci	*rate = div_u64(*rate, CAMSS_CLOCK_MARGIN_DENOMINATOR);
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci/*
88262306a36Sopenharmony_ci * camss_enable_clocks - Enable multiple clocks
88362306a36Sopenharmony_ci * @nclocks: Number of clocks in clock array
88462306a36Sopenharmony_ci * @clock: Clock array
88562306a36Sopenharmony_ci * @dev: Device
88662306a36Sopenharmony_ci *
88762306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise
88862306a36Sopenharmony_ci */
88962306a36Sopenharmony_ciint camss_enable_clocks(int nclocks, struct camss_clock *clock,
89062306a36Sopenharmony_ci			struct device *dev)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	int ret;
89362306a36Sopenharmony_ci	int i;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	for (i = 0; i < nclocks; i++) {
89662306a36Sopenharmony_ci		ret = clk_prepare_enable(clock[i].clk);
89762306a36Sopenharmony_ci		if (ret) {
89862306a36Sopenharmony_ci			dev_err(dev, "clock enable failed: %d\n", ret);
89962306a36Sopenharmony_ci			goto error;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	return 0;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cierror:
90662306a36Sopenharmony_ci	for (i--; i >= 0; i--)
90762306a36Sopenharmony_ci		clk_disable_unprepare(clock[i].clk);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	return ret;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci/*
91362306a36Sopenharmony_ci * camss_disable_clocks - Disable multiple clocks
91462306a36Sopenharmony_ci * @nclocks: Number of clocks in clock array
91562306a36Sopenharmony_ci * @clock: Clock array
91662306a36Sopenharmony_ci */
91762306a36Sopenharmony_civoid camss_disable_clocks(int nclocks, struct camss_clock *clock)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	int i;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	for (i = nclocks - 1; i >= 0; i--)
92262306a36Sopenharmony_ci		clk_disable_unprepare(clock[i].clk);
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/*
92662306a36Sopenharmony_ci * camss_find_sensor - Find a linked media entity which represents a sensor
92762306a36Sopenharmony_ci * @entity: Media entity to start searching from
92862306a36Sopenharmony_ci *
92962306a36Sopenharmony_ci * Return a pointer to sensor media entity or NULL if not found
93062306a36Sopenharmony_ci */
93162306a36Sopenharmony_cistruct media_entity *camss_find_sensor(struct media_entity *entity)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	struct media_pad *pad;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	while (1) {
93662306a36Sopenharmony_ci		pad = &entity->pads[0];
93762306a36Sopenharmony_ci		if (!(pad->flags & MEDIA_PAD_FL_SINK))
93862306a36Sopenharmony_ci			return NULL;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		pad = media_pad_remote_pad_first(pad);
94162306a36Sopenharmony_ci		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
94262306a36Sopenharmony_ci			return NULL;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		entity = pad->entity;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
94762306a36Sopenharmony_ci			return entity;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci/**
95262306a36Sopenharmony_ci * camss_get_link_freq - Get link frequency from sensor
95362306a36Sopenharmony_ci * @entity: Media entity in the current pipeline
95462306a36Sopenharmony_ci * @bpp: Number of bits per pixel for the current format
95562306a36Sopenharmony_ci * @lanes: Number of lanes in the link to the sensor
95662306a36Sopenharmony_ci *
95762306a36Sopenharmony_ci * Return link frequency on success or a negative error code otherwise
95862306a36Sopenharmony_ci */
95962306a36Sopenharmony_cis64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp,
96062306a36Sopenharmony_ci			unsigned int lanes)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	struct media_entity *sensor;
96362306a36Sopenharmony_ci	struct v4l2_subdev *subdev;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	sensor = camss_find_sensor(entity);
96662306a36Sopenharmony_ci	if (!sensor)
96762306a36Sopenharmony_ci		return -ENODEV;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	subdev = media_entity_to_v4l2_subdev(sensor);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return v4l2_get_link_freq(subdev->ctrl_handler, bpp, 2 * lanes);
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/*
97562306a36Sopenharmony_ci * camss_get_pixel_clock - Get pixel clock rate from sensor
97662306a36Sopenharmony_ci * @entity: Media entity in the current pipeline
97762306a36Sopenharmony_ci * @pixel_clock: Received pixel clock value
97862306a36Sopenharmony_ci *
97962306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise
98062306a36Sopenharmony_ci */
98162306a36Sopenharmony_ciint camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct media_entity *sensor;
98462306a36Sopenharmony_ci	struct v4l2_subdev *subdev;
98562306a36Sopenharmony_ci	struct v4l2_ctrl *ctrl;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	sensor = camss_find_sensor(entity);
98862306a36Sopenharmony_ci	if (!sensor)
98962306a36Sopenharmony_ci		return -ENODEV;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	subdev = media_entity_to_v4l2_subdev(sensor);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (!ctrl)
99662306a36Sopenharmony_ci		return -EINVAL;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	*pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ciint camss_pm_domain_on(struct camss *camss, int id)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	int ret = 0;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (id < camss->vfe_num) {
100862306a36Sopenharmony_ci		struct vfe_device *vfe = &camss->vfe[id];
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		ret = vfe->ops->pm_domain_on(vfe);
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	return ret;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_civoid camss_pm_domain_off(struct camss *camss, int id)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	if (id < camss->vfe_num) {
101962306a36Sopenharmony_ci		struct vfe_device *vfe = &camss->vfe[id];
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		vfe->ops->pm_domain_off(vfe);
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci/*
102662306a36Sopenharmony_ci * camss_of_parse_endpoint_node - Parse port endpoint node
102762306a36Sopenharmony_ci * @dev: Device
102862306a36Sopenharmony_ci * @node: Device node to be parsed
102962306a36Sopenharmony_ci * @csd: Parsed data from port endpoint node
103062306a36Sopenharmony_ci *
103162306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure
103262306a36Sopenharmony_ci */
103362306a36Sopenharmony_cistatic int camss_of_parse_endpoint_node(struct device *dev,
103462306a36Sopenharmony_ci					struct device_node *node,
103562306a36Sopenharmony_ci					struct camss_async_subdev *csd)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg;
103862306a36Sopenharmony_ci	struct v4l2_mbus_config_mipi_csi2 *mipi_csi2;
103962306a36Sopenharmony_ci	struct v4l2_fwnode_endpoint vep = { { 0 } };
104062306a36Sopenharmony_ci	unsigned int i;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	csd->interface.csiphy_id = vep.base.port;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	mipi_csi2 = &vep.bus.mipi_csi2;
104762306a36Sopenharmony_ci	lncfg->clk.pos = mipi_csi2->clock_lane;
104862306a36Sopenharmony_ci	lncfg->clk.pol = mipi_csi2->lane_polarities[0];
104962306a36Sopenharmony_ci	lncfg->num_data = mipi_csi2->num_data_lanes;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	lncfg->data = devm_kcalloc(dev,
105262306a36Sopenharmony_ci				   lncfg->num_data, sizeof(*lncfg->data),
105362306a36Sopenharmony_ci				   GFP_KERNEL);
105462306a36Sopenharmony_ci	if (!lncfg->data)
105562306a36Sopenharmony_ci		return -ENOMEM;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	for (i = 0; i < lncfg->num_data; i++) {
105862306a36Sopenharmony_ci		lncfg->data[i].pos = mipi_csi2->data_lanes[i];
105962306a36Sopenharmony_ci		lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1];
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	return 0;
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci/*
106662306a36Sopenharmony_ci * camss_of_parse_ports - Parse ports node
106762306a36Sopenharmony_ci * @dev: Device
106862306a36Sopenharmony_ci * @notifier: v4l2_device notifier data
106962306a36Sopenharmony_ci *
107062306a36Sopenharmony_ci * Return number of "port" nodes found in "ports" node
107162306a36Sopenharmony_ci */
107262306a36Sopenharmony_cistatic int camss_of_parse_ports(struct camss *camss)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct device *dev = camss->dev;
107562306a36Sopenharmony_ci	struct device_node *node = NULL;
107662306a36Sopenharmony_ci	struct device_node *remote = NULL;
107762306a36Sopenharmony_ci	int ret, num_subdevs = 0;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	for_each_endpoint_of_node(dev->of_node, node) {
108062306a36Sopenharmony_ci		struct camss_async_subdev *csd;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		if (!of_device_is_available(node))
108362306a36Sopenharmony_ci			continue;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		remote = of_graph_get_remote_port_parent(node);
108662306a36Sopenharmony_ci		if (!remote) {
108762306a36Sopenharmony_ci			dev_err(dev, "Cannot get remote parent\n");
108862306a36Sopenharmony_ci			ret = -EINVAL;
108962306a36Sopenharmony_ci			goto err_cleanup;
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		csd = v4l2_async_nf_add_fwnode(&camss->notifier,
109362306a36Sopenharmony_ci					       of_fwnode_handle(remote),
109462306a36Sopenharmony_ci					       struct camss_async_subdev);
109562306a36Sopenharmony_ci		of_node_put(remote);
109662306a36Sopenharmony_ci		if (IS_ERR(csd)) {
109762306a36Sopenharmony_ci			ret = PTR_ERR(csd);
109862306a36Sopenharmony_ci			goto err_cleanup;
109962306a36Sopenharmony_ci		}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		ret = camss_of_parse_endpoint_node(dev, node, csd);
110262306a36Sopenharmony_ci		if (ret < 0)
110362306a36Sopenharmony_ci			goto err_cleanup;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		num_subdevs++;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return num_subdevs;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cierr_cleanup:
111162306a36Sopenharmony_ci	of_node_put(node);
111262306a36Sopenharmony_ci	return ret;
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci/*
111662306a36Sopenharmony_ci * camss_init_subdevices - Initialize subdev structures and resources
111762306a36Sopenharmony_ci * @camss: CAMSS device
111862306a36Sopenharmony_ci *
111962306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure
112062306a36Sopenharmony_ci */
112162306a36Sopenharmony_cistatic int camss_init_subdevices(struct camss *camss)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	const struct resources *csiphy_res;
112462306a36Sopenharmony_ci	const struct resources *csid_res;
112562306a36Sopenharmony_ci	const struct resources_ispif *ispif_res;
112662306a36Sopenharmony_ci	const struct resources *vfe_res;
112762306a36Sopenharmony_ci	unsigned int i;
112862306a36Sopenharmony_ci	int ret;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (camss->version == CAMSS_8x16) {
113162306a36Sopenharmony_ci		csiphy_res = csiphy_res_8x16;
113262306a36Sopenharmony_ci		csid_res = csid_res_8x16;
113362306a36Sopenharmony_ci		ispif_res = &ispif_res_8x16;
113462306a36Sopenharmony_ci		vfe_res = vfe_res_8x16;
113562306a36Sopenharmony_ci	} else if (camss->version == CAMSS_8x96) {
113662306a36Sopenharmony_ci		csiphy_res = csiphy_res_8x96;
113762306a36Sopenharmony_ci		csid_res = csid_res_8x96;
113862306a36Sopenharmony_ci		ispif_res = &ispif_res_8x96;
113962306a36Sopenharmony_ci		vfe_res = vfe_res_8x96;
114062306a36Sopenharmony_ci	} else if (camss->version == CAMSS_660) {
114162306a36Sopenharmony_ci		csiphy_res = csiphy_res_660;
114262306a36Sopenharmony_ci		csid_res = csid_res_660;
114362306a36Sopenharmony_ci		ispif_res = &ispif_res_660;
114462306a36Sopenharmony_ci		vfe_res = vfe_res_660;
114562306a36Sopenharmony_ci	}  else if (camss->version == CAMSS_845) {
114662306a36Sopenharmony_ci		csiphy_res = csiphy_res_845;
114762306a36Sopenharmony_ci		csid_res = csid_res_845;
114862306a36Sopenharmony_ci		/* Titan VFEs don't have an ISPIF  */
114962306a36Sopenharmony_ci		ispif_res = NULL;
115062306a36Sopenharmony_ci		vfe_res = vfe_res_845;
115162306a36Sopenharmony_ci	} else if (camss->version == CAMSS_8250) {
115262306a36Sopenharmony_ci		csiphy_res = csiphy_res_8250;
115362306a36Sopenharmony_ci		csid_res = csid_res_8250;
115462306a36Sopenharmony_ci		/* Titan VFEs don't have an ISPIF  */
115562306a36Sopenharmony_ci		ispif_res = NULL;
115662306a36Sopenharmony_ci		vfe_res = vfe_res_8250;
115762306a36Sopenharmony_ci	} else {
115862306a36Sopenharmony_ci		return -EINVAL;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
116262306a36Sopenharmony_ci		ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i],
116362306a36Sopenharmony_ci					     &csiphy_res[i], i);
116462306a36Sopenharmony_ci		if (ret < 0) {
116562306a36Sopenharmony_ci			dev_err(camss->dev,
116662306a36Sopenharmony_ci				"Failed to init csiphy%d sub-device: %d\n",
116762306a36Sopenharmony_ci				i, ret);
116862306a36Sopenharmony_ci			return ret;
116962306a36Sopenharmony_ci		}
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	/* note: SM8250 requires VFE to be initialized before CSID */
117362306a36Sopenharmony_ci	for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) {
117462306a36Sopenharmony_ci		ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
117562306a36Sopenharmony_ci					  &vfe_res[i], i);
117662306a36Sopenharmony_ci		if (ret < 0) {
117762306a36Sopenharmony_ci			dev_err(camss->dev,
117862306a36Sopenharmony_ci				"Fail to init vfe%d sub-device: %d\n", i, ret);
117962306a36Sopenharmony_ci			return ret;
118062306a36Sopenharmony_ci		}
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++) {
118462306a36Sopenharmony_ci		ret = msm_csid_subdev_init(camss, &camss->csid[i],
118562306a36Sopenharmony_ci					   &csid_res[i], i);
118662306a36Sopenharmony_ci		if (ret < 0) {
118762306a36Sopenharmony_ci			dev_err(camss->dev,
118862306a36Sopenharmony_ci				"Failed to init csid%d sub-device: %d\n",
118962306a36Sopenharmony_ci				i, ret);
119062306a36Sopenharmony_ci			return ret;
119162306a36Sopenharmony_ci		}
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	ret = msm_ispif_subdev_init(camss, ispif_res);
119562306a36Sopenharmony_ci	if (ret < 0) {
119662306a36Sopenharmony_ci		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
119762306a36Sopenharmony_ci		ret);
119862306a36Sopenharmony_ci		return ret;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	return 0;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/*
120562306a36Sopenharmony_ci * camss_register_entities - Register subdev nodes and create links
120662306a36Sopenharmony_ci * @camss: CAMSS device
120762306a36Sopenharmony_ci *
120862306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure
120962306a36Sopenharmony_ci */
121062306a36Sopenharmony_cistatic int camss_register_entities(struct camss *camss)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	int i, j, k;
121362306a36Sopenharmony_ci	int ret;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
121662306a36Sopenharmony_ci		ret = msm_csiphy_register_entity(&camss->csiphy[i],
121762306a36Sopenharmony_ci						 &camss->v4l2_dev);
121862306a36Sopenharmony_ci		if (ret < 0) {
121962306a36Sopenharmony_ci			dev_err(camss->dev,
122062306a36Sopenharmony_ci				"Failed to register csiphy%d entity: %d\n",
122162306a36Sopenharmony_ci				i, ret);
122262306a36Sopenharmony_ci			goto err_reg_csiphy;
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++) {
122762306a36Sopenharmony_ci		ret = msm_csid_register_entity(&camss->csid[i],
122862306a36Sopenharmony_ci					       &camss->v4l2_dev);
122962306a36Sopenharmony_ci		if (ret < 0) {
123062306a36Sopenharmony_ci			dev_err(camss->dev,
123162306a36Sopenharmony_ci				"Failed to register csid%d entity: %d\n",
123262306a36Sopenharmony_ci				i, ret);
123362306a36Sopenharmony_ci			goto err_reg_csid;
123462306a36Sopenharmony_ci		}
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	ret = msm_ispif_register_entities(camss->ispif,
123862306a36Sopenharmony_ci					  &camss->v4l2_dev);
123962306a36Sopenharmony_ci	if (ret < 0) {
124062306a36Sopenharmony_ci		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
124162306a36Sopenharmony_ci		ret);
124262306a36Sopenharmony_ci		goto err_reg_ispif;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) {
124662306a36Sopenharmony_ci		ret = msm_vfe_register_entities(&camss->vfe[i],
124762306a36Sopenharmony_ci						&camss->v4l2_dev);
124862306a36Sopenharmony_ci		if (ret < 0) {
124962306a36Sopenharmony_ci			dev_err(camss->dev,
125062306a36Sopenharmony_ci				"Failed to register vfe%d entities: %d\n",
125162306a36Sopenharmony_ci				i, ret);
125262306a36Sopenharmony_ci			goto err_reg_vfe;
125362306a36Sopenharmony_ci		}
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
125762306a36Sopenharmony_ci		for (j = 0; j < camss->csid_num; j++) {
125862306a36Sopenharmony_ci			ret = media_create_pad_link(
125962306a36Sopenharmony_ci				&camss->csiphy[i].subdev.entity,
126062306a36Sopenharmony_ci				MSM_CSIPHY_PAD_SRC,
126162306a36Sopenharmony_ci				&camss->csid[j].subdev.entity,
126262306a36Sopenharmony_ci				MSM_CSID_PAD_SINK,
126362306a36Sopenharmony_ci				0);
126462306a36Sopenharmony_ci			if (ret < 0) {
126562306a36Sopenharmony_ci				dev_err(camss->dev,
126662306a36Sopenharmony_ci					"Failed to link %s->%s entities: %d\n",
126762306a36Sopenharmony_ci					camss->csiphy[i].subdev.entity.name,
126862306a36Sopenharmony_ci					camss->csid[j].subdev.entity.name,
126962306a36Sopenharmony_ci					ret);
127062306a36Sopenharmony_ci				goto err_link;
127162306a36Sopenharmony_ci			}
127262306a36Sopenharmony_ci		}
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	if (camss->ispif) {
127662306a36Sopenharmony_ci		for (i = 0; i < camss->csid_num; i++) {
127762306a36Sopenharmony_ci			for (j = 0; j < camss->ispif->line_num; j++) {
127862306a36Sopenharmony_ci				ret = media_create_pad_link(
127962306a36Sopenharmony_ci					&camss->csid[i].subdev.entity,
128062306a36Sopenharmony_ci					MSM_CSID_PAD_SRC,
128162306a36Sopenharmony_ci					&camss->ispif->line[j].subdev.entity,
128262306a36Sopenharmony_ci					MSM_ISPIF_PAD_SINK,
128362306a36Sopenharmony_ci					0);
128462306a36Sopenharmony_ci				if (ret < 0) {
128562306a36Sopenharmony_ci					dev_err(camss->dev,
128662306a36Sopenharmony_ci						"Failed to link %s->%s entities: %d\n",
128762306a36Sopenharmony_ci						camss->csid[i].subdev.entity.name,
128862306a36Sopenharmony_ci						camss->ispif->line[j].subdev.entity.name,
128962306a36Sopenharmony_ci						ret);
129062306a36Sopenharmony_ci					goto err_link;
129162306a36Sopenharmony_ci				}
129262306a36Sopenharmony_ci			}
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		for (i = 0; i < camss->ispif->line_num; i++)
129662306a36Sopenharmony_ci			for (k = 0; k < camss->vfe_num; k++)
129762306a36Sopenharmony_ci				for (j = 0; j < camss->vfe[k].line_num; j++) {
129862306a36Sopenharmony_ci					struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev;
129962306a36Sopenharmony_ci					struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci					ret = media_create_pad_link(&ispif->entity,
130262306a36Sopenharmony_ci								    MSM_ISPIF_PAD_SRC,
130362306a36Sopenharmony_ci								    &vfe->entity,
130462306a36Sopenharmony_ci								    MSM_VFE_PAD_SINK,
130562306a36Sopenharmony_ci								    0);
130662306a36Sopenharmony_ci					if (ret < 0) {
130762306a36Sopenharmony_ci						dev_err(camss->dev,
130862306a36Sopenharmony_ci							"Failed to link %s->%s entities: %d\n",
130962306a36Sopenharmony_ci							ispif->entity.name,
131062306a36Sopenharmony_ci							vfe->entity.name,
131162306a36Sopenharmony_ci							ret);
131262306a36Sopenharmony_ci						goto err_link;
131362306a36Sopenharmony_ci					}
131462306a36Sopenharmony_ci				}
131562306a36Sopenharmony_ci	} else {
131662306a36Sopenharmony_ci		for (i = 0; i < camss->csid_num; i++)
131762306a36Sopenharmony_ci			for (k = 0; k < camss->vfe_num + camss->vfe_lite_num; k++)
131862306a36Sopenharmony_ci				for (j = 0; j < camss->vfe[k].line_num; j++) {
131962306a36Sopenharmony_ci					struct v4l2_subdev *csid = &camss->csid[i].subdev;
132062306a36Sopenharmony_ci					struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci					ret = media_create_pad_link(&csid->entity,
132362306a36Sopenharmony_ci								    MSM_CSID_PAD_FIRST_SRC + j,
132462306a36Sopenharmony_ci								    &vfe->entity,
132562306a36Sopenharmony_ci								    MSM_VFE_PAD_SINK,
132662306a36Sopenharmony_ci								    0);
132762306a36Sopenharmony_ci					if (ret < 0) {
132862306a36Sopenharmony_ci						dev_err(camss->dev,
132962306a36Sopenharmony_ci							"Failed to link %s->%s entities: %d\n",
133062306a36Sopenharmony_ci							csid->entity.name,
133162306a36Sopenharmony_ci							vfe->entity.name,
133262306a36Sopenharmony_ci							ret);
133362306a36Sopenharmony_ci						goto err_link;
133462306a36Sopenharmony_ci					}
133562306a36Sopenharmony_ci				}
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	return 0;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cierr_link:
134162306a36Sopenharmony_ci	i = camss->vfe_num + camss->vfe_lite_num;
134262306a36Sopenharmony_cierr_reg_vfe:
134362306a36Sopenharmony_ci	for (i--; i >= 0; i--)
134462306a36Sopenharmony_ci		msm_vfe_unregister_entities(&camss->vfe[i]);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cierr_reg_ispif:
134762306a36Sopenharmony_ci	msm_ispif_unregister_entities(camss->ispif);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	i = camss->csid_num;
135062306a36Sopenharmony_cierr_reg_csid:
135162306a36Sopenharmony_ci	for (i--; i >= 0; i--)
135262306a36Sopenharmony_ci		msm_csid_unregister_entity(&camss->csid[i]);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	i = camss->csiphy_num;
135562306a36Sopenharmony_cierr_reg_csiphy:
135662306a36Sopenharmony_ci	for (i--; i >= 0; i--)
135762306a36Sopenharmony_ci		msm_csiphy_unregister_entity(&camss->csiphy[i]);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	return ret;
136062306a36Sopenharmony_ci}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci/*
136362306a36Sopenharmony_ci * camss_unregister_entities - Unregister subdev nodes
136462306a36Sopenharmony_ci * @camss: CAMSS device
136562306a36Sopenharmony_ci *
136662306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure
136762306a36Sopenharmony_ci */
136862306a36Sopenharmony_cistatic void camss_unregister_entities(struct camss *camss)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	unsigned int i;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++)
137362306a36Sopenharmony_ci		msm_csiphy_unregister_entity(&camss->csiphy[i]);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++)
137662306a36Sopenharmony_ci		msm_csid_unregister_entity(&camss->csid[i]);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	msm_ispif_unregister_entities(camss->ispif);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++)
138162306a36Sopenharmony_ci		msm_vfe_unregister_entities(&camss->vfe[i]);
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int camss_subdev_notifier_bound(struct v4l2_async_notifier *async,
138562306a36Sopenharmony_ci				       struct v4l2_subdev *subdev,
138662306a36Sopenharmony_ci				       struct v4l2_async_connection *asd)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	struct camss *camss = container_of(async, struct camss, notifier);
138962306a36Sopenharmony_ci	struct camss_async_subdev *csd =
139062306a36Sopenharmony_ci		container_of(asd, struct camss_async_subdev, asd);
139162306a36Sopenharmony_ci	u8 id = csd->interface.csiphy_id;
139262306a36Sopenharmony_ci	struct csiphy_device *csiphy = &camss->csiphy[id];
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	csiphy->cfg.csi2 = &csd->interface.csi2;
139562306a36Sopenharmony_ci	subdev->host_priv = csiphy;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct camss *camss = container_of(async, struct camss, notifier);
140362306a36Sopenharmony_ci	struct v4l2_device *v4l2_dev = &camss->v4l2_dev;
140462306a36Sopenharmony_ci	struct v4l2_subdev *sd;
140562306a36Sopenharmony_ci	int ret;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
140862306a36Sopenharmony_ci		if (sd->host_priv) {
140962306a36Sopenharmony_ci			struct media_entity *sensor = &sd->entity;
141062306a36Sopenharmony_ci			struct csiphy_device *csiphy =
141162306a36Sopenharmony_ci					(struct csiphy_device *) sd->host_priv;
141262306a36Sopenharmony_ci			struct media_entity *input = &csiphy->subdev.entity;
141362306a36Sopenharmony_ci			unsigned int i;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci			for (i = 0; i < sensor->num_pads; i++) {
141662306a36Sopenharmony_ci				if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
141762306a36Sopenharmony_ci					break;
141862306a36Sopenharmony_ci			}
141962306a36Sopenharmony_ci			if (i == sensor->num_pads) {
142062306a36Sopenharmony_ci				dev_err(camss->dev,
142162306a36Sopenharmony_ci					"No source pad in external entity\n");
142262306a36Sopenharmony_ci				return -EINVAL;
142362306a36Sopenharmony_ci			}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci			ret = media_create_pad_link(sensor, i,
142662306a36Sopenharmony_ci				input, MSM_CSIPHY_PAD_SINK,
142762306a36Sopenharmony_ci				MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
142862306a36Sopenharmony_ci			if (ret < 0) {
142962306a36Sopenharmony_ci				dev_err(camss->dev,
143062306a36Sopenharmony_ci					"Failed to link %s->%s entities: %d\n",
143162306a36Sopenharmony_ci					sensor->name, input->name, ret);
143262306a36Sopenharmony_ci				return ret;
143362306a36Sopenharmony_ci			}
143462306a36Sopenharmony_ci		}
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev);
143862306a36Sopenharmony_ci	if (ret < 0)
143962306a36Sopenharmony_ci		return ret;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	return media_device_register(&camss->media_dev);
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = {
144562306a36Sopenharmony_ci	.bound = camss_subdev_notifier_bound,
144662306a36Sopenharmony_ci	.complete = camss_subdev_notifier_complete,
144762306a36Sopenharmony_ci};
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic const struct media_device_ops camss_media_ops = {
145062306a36Sopenharmony_ci	.link_notify = v4l2_pipeline_link_notify,
145162306a36Sopenharmony_ci};
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cistatic int camss_configure_pd(struct camss *camss)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	struct device *dev = camss->dev;
145662306a36Sopenharmony_ci	int i;
145762306a36Sopenharmony_ci	int ret;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	camss->genpd_num = of_count_phandle_with_args(dev->of_node,
146062306a36Sopenharmony_ci						      "power-domains",
146162306a36Sopenharmony_ci						      "#power-domain-cells");
146262306a36Sopenharmony_ci	if (camss->genpd_num < 0) {
146362306a36Sopenharmony_ci		dev_err(dev, "Power domains are not defined for camss\n");
146462306a36Sopenharmony_ci		return camss->genpd_num;
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/*
146862306a36Sopenharmony_ci	 * If a platform device has just one power domain, then it is attached
146962306a36Sopenharmony_ci	 * at platform_probe() level, thus there shall be no need and even no
147062306a36Sopenharmony_ci	 * option to attach it again, this is the case for CAMSS on MSM8916.
147162306a36Sopenharmony_ci	 */
147262306a36Sopenharmony_ci	if (camss->genpd_num == 1)
147362306a36Sopenharmony_ci		return 0;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
147662306a36Sopenharmony_ci					  sizeof(*camss->genpd), GFP_KERNEL);
147762306a36Sopenharmony_ci	if (!camss->genpd)
147862306a36Sopenharmony_ci		return -ENOMEM;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num,
148162306a36Sopenharmony_ci					       sizeof(*camss->genpd_link),
148262306a36Sopenharmony_ci					       GFP_KERNEL);
148362306a36Sopenharmony_ci	if (!camss->genpd_link)
148462306a36Sopenharmony_ci		return -ENOMEM;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	/*
148762306a36Sopenharmony_ci	 * VFE power domains are in the beginning of the list, and while all
148862306a36Sopenharmony_ci	 * power domains should be attached, only if TITAN_TOP power domain is
148962306a36Sopenharmony_ci	 * found in the list, it should be linked over here.
149062306a36Sopenharmony_ci	 */
149162306a36Sopenharmony_ci	for (i = 0; i < camss->genpd_num; i++) {
149262306a36Sopenharmony_ci		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
149362306a36Sopenharmony_ci		if (IS_ERR(camss->genpd[i])) {
149462306a36Sopenharmony_ci			ret = PTR_ERR(camss->genpd[i]);
149562306a36Sopenharmony_ci			goto fail_pm;
149662306a36Sopenharmony_ci		}
149762306a36Sopenharmony_ci	}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	if (i > camss->vfe_num) {
150062306a36Sopenharmony_ci		camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1],
150162306a36Sopenharmony_ci							   DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
150262306a36Sopenharmony_ci							   DL_FLAG_RPM_ACTIVE);
150362306a36Sopenharmony_ci		if (!camss->genpd_link[i - 1]) {
150462306a36Sopenharmony_ci			ret = -EINVAL;
150562306a36Sopenharmony_ci			goto fail_pm;
150662306a36Sopenharmony_ci		}
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	return 0;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cifail_pm:
151262306a36Sopenharmony_ci	for (--i ; i >= 0; i--)
151362306a36Sopenharmony_ci		dev_pm_domain_detach(camss->genpd[i], true);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	return ret;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_cistatic int camss_icc_get(struct camss *camss)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	const struct resources_icc *icc_res;
152162306a36Sopenharmony_ci	int nbr_icc_paths = 0;
152262306a36Sopenharmony_ci	int i;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	if (camss->version == CAMSS_8250) {
152562306a36Sopenharmony_ci		icc_res = &icc_res_sm8250[0];
152662306a36Sopenharmony_ci		nbr_icc_paths =	ICC_SM8250_COUNT;
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	for (i = 0; i < nbr_icc_paths; i++) {
153062306a36Sopenharmony_ci		camss->icc_path[i] = devm_of_icc_get(camss->dev,
153162306a36Sopenharmony_ci						     icc_res[i].name);
153262306a36Sopenharmony_ci		if (IS_ERR(camss->icc_path[i]))
153362306a36Sopenharmony_ci			return PTR_ERR(camss->icc_path[i]);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		camss->icc_bw_tbl[i] = icc_res[i].icc_bw_tbl;
153662306a36Sopenharmony_ci	}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	return 0;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic void camss_genpd_cleanup(struct camss *camss)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	int i;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	if (camss->genpd_num == 1)
154662306a36Sopenharmony_ci		return;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	if (camss->genpd_num > camss->vfe_num)
154962306a36Sopenharmony_ci		device_link_del(camss->genpd_link[camss->genpd_num - 1]);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	for (i = 0; i < camss->genpd_num; i++)
155262306a36Sopenharmony_ci		dev_pm_domain_detach(camss->genpd[i], true);
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci/*
155662306a36Sopenharmony_ci * camss_probe - Probe CAMSS platform device
155762306a36Sopenharmony_ci * @pdev: Pointer to CAMSS platform device
155862306a36Sopenharmony_ci *
155962306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure
156062306a36Sopenharmony_ci */
156162306a36Sopenharmony_cistatic int camss_probe(struct platform_device *pdev)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
156462306a36Sopenharmony_ci	struct camss *camss;
156562306a36Sopenharmony_ci	int num_subdevs, ret;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL);
156862306a36Sopenharmony_ci	if (!camss)
156962306a36Sopenharmony_ci		return -ENOMEM;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	atomic_set(&camss->ref_count, 0);
157262306a36Sopenharmony_ci	camss->dev = dev;
157362306a36Sopenharmony_ci	platform_set_drvdata(pdev, camss);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) {
157662306a36Sopenharmony_ci		camss->version = CAMSS_8x16;
157762306a36Sopenharmony_ci		camss->csiphy_num = 2;
157862306a36Sopenharmony_ci		camss->csid_num = 2;
157962306a36Sopenharmony_ci		camss->vfe_num = 1;
158062306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
158162306a36Sopenharmony_ci					   "qcom,msm8996-camss")) {
158262306a36Sopenharmony_ci		camss->version = CAMSS_8x96;
158362306a36Sopenharmony_ci		camss->csiphy_num = 3;
158462306a36Sopenharmony_ci		camss->csid_num = 4;
158562306a36Sopenharmony_ci		camss->vfe_num = 2;
158662306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
158762306a36Sopenharmony_ci					   "qcom,sdm660-camss")) {
158862306a36Sopenharmony_ci		camss->version = CAMSS_660;
158962306a36Sopenharmony_ci		camss->csiphy_num = 3;
159062306a36Sopenharmony_ci		camss->csid_num = 4;
159162306a36Sopenharmony_ci		camss->vfe_num = 2;
159262306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
159362306a36Sopenharmony_ci					   "qcom,sdm845-camss")) {
159462306a36Sopenharmony_ci		camss->version = CAMSS_845;
159562306a36Sopenharmony_ci		camss->csiphy_num = 4;
159662306a36Sopenharmony_ci		camss->csid_num = 3;
159762306a36Sopenharmony_ci		camss->vfe_num = 2;
159862306a36Sopenharmony_ci		camss->vfe_lite_num = 1;
159962306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
160062306a36Sopenharmony_ci					   "qcom,sm8250-camss")) {
160162306a36Sopenharmony_ci		camss->version = CAMSS_8250;
160262306a36Sopenharmony_ci		camss->csiphy_num = 6;
160362306a36Sopenharmony_ci		camss->csid_num = 4;
160462306a36Sopenharmony_ci		camss->vfe_num = 2;
160562306a36Sopenharmony_ci		camss->vfe_lite_num = 2;
160662306a36Sopenharmony_ci	} else {
160762306a36Sopenharmony_ci		return -EINVAL;
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	camss->csiphy = devm_kcalloc(dev, camss->csiphy_num,
161162306a36Sopenharmony_ci				     sizeof(*camss->csiphy), GFP_KERNEL);
161262306a36Sopenharmony_ci	if (!camss->csiphy)
161362306a36Sopenharmony_ci		return -ENOMEM;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid),
161662306a36Sopenharmony_ci				   GFP_KERNEL);
161762306a36Sopenharmony_ci	if (!camss->csid)
161862306a36Sopenharmony_ci		return -ENOMEM;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (camss->version == CAMSS_8x16 ||
162162306a36Sopenharmony_ci	    camss->version == CAMSS_8x96) {
162262306a36Sopenharmony_ci		camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL);
162362306a36Sopenharmony_ci		if (!camss->ispif)
162462306a36Sopenharmony_ci			return -ENOMEM;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	camss->vfe = devm_kcalloc(dev, camss->vfe_num + camss->vfe_lite_num,
162862306a36Sopenharmony_ci				  sizeof(*camss->vfe), GFP_KERNEL);
162962306a36Sopenharmony_ci	if (!camss->vfe)
163062306a36Sopenharmony_ci		return -ENOMEM;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	ret = camss_icc_get(camss);
163362306a36Sopenharmony_ci	if (ret < 0)
163462306a36Sopenharmony_ci		return ret;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	ret = camss_configure_pd(camss);
163762306a36Sopenharmony_ci	if (ret < 0) {
163862306a36Sopenharmony_ci		dev_err(dev, "Failed to configure power domains: %d\n", ret);
163962306a36Sopenharmony_ci		return ret;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ret = camss_init_subdevices(camss);
164362306a36Sopenharmony_ci	if (ret < 0)
164462306a36Sopenharmony_ci		goto err_genpd_cleanup;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, 0xffffffff);
164762306a36Sopenharmony_ci	if (ret)
164862306a36Sopenharmony_ci		goto err_genpd_cleanup;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	camss->media_dev.dev = camss->dev;
165162306a36Sopenharmony_ci	strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem",
165262306a36Sopenharmony_ci		sizeof(camss->media_dev.model));
165362306a36Sopenharmony_ci	camss->media_dev.ops = &camss_media_ops;
165462306a36Sopenharmony_ci	media_device_init(&camss->media_dev);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	camss->v4l2_dev.mdev = &camss->media_dev;
165762306a36Sopenharmony_ci	ret = v4l2_device_register(camss->dev, &camss->v4l2_dev);
165862306a36Sopenharmony_ci	if (ret < 0) {
165962306a36Sopenharmony_ci		dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
166062306a36Sopenharmony_ci		goto err_genpd_cleanup;
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	v4l2_async_nf_init(&camss->notifier, &camss->v4l2_dev);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	num_subdevs = camss_of_parse_ports(camss);
166662306a36Sopenharmony_ci	if (num_subdevs < 0) {
166762306a36Sopenharmony_ci		ret = num_subdevs;
166862306a36Sopenharmony_ci		goto err_v4l2_device_unregister;
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	ret = camss_register_entities(camss);
167262306a36Sopenharmony_ci	if (ret < 0)
167362306a36Sopenharmony_ci		goto err_v4l2_device_unregister;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (num_subdevs) {
167662306a36Sopenharmony_ci		camss->notifier.ops = &camss_subdev_notifier_ops;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci		ret = v4l2_async_nf_register(&camss->notifier);
167962306a36Sopenharmony_ci		if (ret) {
168062306a36Sopenharmony_ci			dev_err(dev,
168162306a36Sopenharmony_ci				"Failed to register async subdev nodes: %d\n",
168262306a36Sopenharmony_ci				ret);
168362306a36Sopenharmony_ci			goto err_register_subdevs;
168462306a36Sopenharmony_ci		}
168562306a36Sopenharmony_ci	} else {
168662306a36Sopenharmony_ci		ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev);
168762306a36Sopenharmony_ci		if (ret < 0) {
168862306a36Sopenharmony_ci			dev_err(dev, "Failed to register subdev nodes: %d\n",
168962306a36Sopenharmony_ci				ret);
169062306a36Sopenharmony_ci			goto err_register_subdevs;
169162306a36Sopenharmony_ci		}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci		ret = media_device_register(&camss->media_dev);
169462306a36Sopenharmony_ci		if (ret < 0) {
169562306a36Sopenharmony_ci			dev_err(dev, "Failed to register media device: %d\n",
169662306a36Sopenharmony_ci				ret);
169762306a36Sopenharmony_ci			goto err_register_subdevs;
169862306a36Sopenharmony_ci		}
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	pm_runtime_enable(dev);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	return 0;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cierr_register_subdevs:
170662306a36Sopenharmony_ci	camss_unregister_entities(camss);
170762306a36Sopenharmony_cierr_v4l2_device_unregister:
170862306a36Sopenharmony_ci	v4l2_device_unregister(&camss->v4l2_dev);
170962306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&camss->notifier);
171062306a36Sopenharmony_cierr_genpd_cleanup:
171162306a36Sopenharmony_ci	camss_genpd_cleanup(camss);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return ret;
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_civoid camss_delete(struct camss *camss)
171762306a36Sopenharmony_ci{
171862306a36Sopenharmony_ci	v4l2_device_unregister(&camss->v4l2_dev);
171962306a36Sopenharmony_ci	media_device_unregister(&camss->media_dev);
172062306a36Sopenharmony_ci	media_device_cleanup(&camss->media_dev);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	pm_runtime_disable(camss->dev);
172362306a36Sopenharmony_ci}
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci/*
172662306a36Sopenharmony_ci * camss_remove - Remove CAMSS platform device
172762306a36Sopenharmony_ci * @pdev: Pointer to CAMSS platform device
172862306a36Sopenharmony_ci *
172962306a36Sopenharmony_ci * Always returns 0.
173062306a36Sopenharmony_ci */
173162306a36Sopenharmony_cistatic void camss_remove(struct platform_device *pdev)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	struct camss *camss = platform_get_drvdata(pdev);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	v4l2_async_nf_unregister(&camss->notifier);
173662306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&camss->notifier);
173762306a36Sopenharmony_ci	camss_unregister_entities(camss);
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	if (atomic_read(&camss->ref_count) == 0)
174062306a36Sopenharmony_ci		camss_delete(camss);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	camss_genpd_cleanup(camss);
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic const struct of_device_id camss_dt_match[] = {
174662306a36Sopenharmony_ci	{ .compatible = "qcom,msm8916-camss" },
174762306a36Sopenharmony_ci	{ .compatible = "qcom,msm8996-camss" },
174862306a36Sopenharmony_ci	{ .compatible = "qcom,sdm660-camss" },
174962306a36Sopenharmony_ci	{ .compatible = "qcom,sdm845-camss" },
175062306a36Sopenharmony_ci	{ .compatible = "qcom,sm8250-camss" },
175162306a36Sopenharmony_ci	{ }
175262306a36Sopenharmony_ci};
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, camss_dt_match);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic int __maybe_unused camss_runtime_suspend(struct device *dev)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	struct camss *camss = dev_get_drvdata(dev);
175962306a36Sopenharmony_ci	int nbr_icc_paths = 0;
176062306a36Sopenharmony_ci	int i;
176162306a36Sopenharmony_ci	int ret;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	if (camss->version == CAMSS_8250)
176462306a36Sopenharmony_ci		nbr_icc_paths =	ICC_SM8250_COUNT;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	for (i = 0; i < nbr_icc_paths; i++) {
176762306a36Sopenharmony_ci		ret = icc_set_bw(camss->icc_path[i], 0, 0);
176862306a36Sopenharmony_ci		if (ret)
176962306a36Sopenharmony_ci			return ret;
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	return 0;
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_cistatic int __maybe_unused camss_runtime_resume(struct device *dev)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	struct camss *camss = dev_get_drvdata(dev);
177862306a36Sopenharmony_ci	int nbr_icc_paths = 0;
177962306a36Sopenharmony_ci	int i;
178062306a36Sopenharmony_ci	int ret;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	if (camss->version == CAMSS_8250)
178362306a36Sopenharmony_ci		nbr_icc_paths =	ICC_SM8250_COUNT;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	for (i = 0; i < nbr_icc_paths; i++) {
178662306a36Sopenharmony_ci		ret = icc_set_bw(camss->icc_path[i],
178762306a36Sopenharmony_ci				 camss->icc_bw_tbl[i].avg,
178862306a36Sopenharmony_ci				 camss->icc_bw_tbl[i].peak);
178962306a36Sopenharmony_ci		if (ret)
179062306a36Sopenharmony_ci			return ret;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	return 0;
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_cistatic const struct dev_pm_ops camss_pm_ops = {
179762306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
179862306a36Sopenharmony_ci				pm_runtime_force_resume)
179962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(camss_runtime_suspend, camss_runtime_resume, NULL)
180062306a36Sopenharmony_ci};
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic struct platform_driver qcom_camss_driver = {
180362306a36Sopenharmony_ci	.probe = camss_probe,
180462306a36Sopenharmony_ci	.remove_new = camss_remove,
180562306a36Sopenharmony_ci	.driver = {
180662306a36Sopenharmony_ci		.name = "qcom-camss",
180762306a36Sopenharmony_ci		.of_match_table = camss_dt_match,
180862306a36Sopenharmony_ci		.pm = &camss_pm_ops,
180962306a36Sopenharmony_ci	},
181062306a36Sopenharmony_ci};
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cimodule_platform_driver(qcom_camss_driver);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ciMODULE_ALIAS("platform:qcom-camss");
181562306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Camera Subsystem driver");
181662306a36Sopenharmony_ciMODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>");
181762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1818