18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * camss.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Qualcomm MSM Camera Subsystem - Core
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 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/media-bus-format.h>
128c2ecf20Sopenharmony_ci#include <linux/media.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_graph.h>
178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
188c2ecf20Sopenharmony_ci#include <linux/pm_domain.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <media/media-device.h>
238c2ecf20Sopenharmony_ci#include <media/v4l2-async.h>
248c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
258c2ecf20Sopenharmony_ci#include <media/v4l2-mc.h>
268c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "camss.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define CAMSS_CLOCK_MARGIN_NUMERATOR 105
318c2ecf20Sopenharmony_ci#define CAMSS_CLOCK_MARGIN_DENOMINATOR 100
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct resources csiphy_res_8x16[] = {
348c2ecf20Sopenharmony_ci	/* CSIPHY0 */
358c2ecf20Sopenharmony_ci	{
368c2ecf20Sopenharmony_ci		.regulator = { NULL },
378c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" },
388c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
398c2ecf20Sopenharmony_ci				{ 0 },
408c2ecf20Sopenharmony_ci				{ 0 },
418c2ecf20Sopenharmony_ci				{ 100000000, 200000000 } },
428c2ecf20Sopenharmony_ci		.reg = { "csiphy0", "csiphy0_clk_mux" },
438c2ecf20Sopenharmony_ci		.interrupt = { "csiphy0" }
448c2ecf20Sopenharmony_ci	},
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* CSIPHY1 */
478c2ecf20Sopenharmony_ci	{
488c2ecf20Sopenharmony_ci		.regulator = { NULL },
498c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" },
508c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
518c2ecf20Sopenharmony_ci				{ 0 },
528c2ecf20Sopenharmony_ci				{ 0 },
538c2ecf20Sopenharmony_ci				{ 100000000, 200000000 } },
548c2ecf20Sopenharmony_ci		.reg = { "csiphy1", "csiphy1_clk_mux" },
558c2ecf20Sopenharmony_ci		.interrupt = { "csiphy1" }
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic const struct resources csid_res_8x16[] = {
608c2ecf20Sopenharmony_ci	/* CSID0 */
618c2ecf20Sopenharmony_ci	{
628c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
638c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
648c2ecf20Sopenharmony_ci			   "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" },
658c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
668c2ecf20Sopenharmony_ci				{ 0 },
678c2ecf20Sopenharmony_ci				{ 0 },
688c2ecf20Sopenharmony_ci				{ 0 },
698c2ecf20Sopenharmony_ci				{ 100000000, 200000000 },
708c2ecf20Sopenharmony_ci				{ 0 },
718c2ecf20Sopenharmony_ci				{ 0 },
728c2ecf20Sopenharmony_ci				{ 0 } },
738c2ecf20Sopenharmony_ci		.reg = { "csid0" },
748c2ecf20Sopenharmony_ci		.interrupt = { "csid0" }
758c2ecf20Sopenharmony_ci	},
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* CSID1 */
788c2ecf20Sopenharmony_ci	{
798c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
808c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
818c2ecf20Sopenharmony_ci			   "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" },
828c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
838c2ecf20Sopenharmony_ci				{ 0 },
848c2ecf20Sopenharmony_ci				{ 0 },
858c2ecf20Sopenharmony_ci				{ 0 },
868c2ecf20Sopenharmony_ci				{ 100000000, 200000000 },
878c2ecf20Sopenharmony_ci				{ 0 },
888c2ecf20Sopenharmony_ci				{ 0 },
898c2ecf20Sopenharmony_ci				{ 0 } },
908c2ecf20Sopenharmony_ci		.reg = { "csid1" },
918c2ecf20Sopenharmony_ci		.interrupt = { "csid1" }
928c2ecf20Sopenharmony_ci	},
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic const struct resources_ispif ispif_res_8x16 = {
968c2ecf20Sopenharmony_ci	/* ISPIF */
978c2ecf20Sopenharmony_ci	.clock = { "top_ahb", "ahb", "ispif_ahb",
988c2ecf20Sopenharmony_ci		   "csi0", "csi0_pix", "csi0_rdi",
998c2ecf20Sopenharmony_ci		   "csi1", "csi1_pix", "csi1_rdi" },
1008c2ecf20Sopenharmony_ci	.clock_for_reset = { "vfe0", "csi_vfe0" },
1018c2ecf20Sopenharmony_ci	.reg = { "ispif", "csi_clk_mux" },
1028c2ecf20Sopenharmony_ci	.interrupt = "ispif"
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic const struct resources vfe_res_8x16[] = {
1078c2ecf20Sopenharmony_ci	/* VFE0 */
1088c2ecf20Sopenharmony_ci	{
1098c2ecf20Sopenharmony_ci		.regulator = { NULL },
1108c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "vfe0", "csi_vfe0",
1118c2ecf20Sopenharmony_ci			   "vfe_ahb", "vfe_axi", "ahb" },
1128c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1138c2ecf20Sopenharmony_ci				{ 50000000, 80000000, 100000000, 160000000,
1148c2ecf20Sopenharmony_ci				  177780000, 200000000, 266670000, 320000000,
1158c2ecf20Sopenharmony_ci				  400000000, 465000000 },
1168c2ecf20Sopenharmony_ci				{ 0 },
1178c2ecf20Sopenharmony_ci				{ 0 },
1188c2ecf20Sopenharmony_ci				{ 0 },
1198c2ecf20Sopenharmony_ci				{ 0 },
1208c2ecf20Sopenharmony_ci				{ 0 },
1218c2ecf20Sopenharmony_ci				{ 0 },
1228c2ecf20Sopenharmony_ci				{ 0 } },
1238c2ecf20Sopenharmony_ci		.reg = { "vfe0" },
1248c2ecf20Sopenharmony_ci		.interrupt = { "vfe0" }
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct resources csiphy_res_8x96[] = {
1298c2ecf20Sopenharmony_ci	/* CSIPHY0 */
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci		.regulator = { NULL },
1328c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" },
1338c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1348c2ecf20Sopenharmony_ci				{ 0 },
1358c2ecf20Sopenharmony_ci				{ 0 },
1368c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
1378c2ecf20Sopenharmony_ci		.reg = { "csiphy0", "csiphy0_clk_mux" },
1388c2ecf20Sopenharmony_ci		.interrupt = { "csiphy0" }
1398c2ecf20Sopenharmony_ci	},
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* CSIPHY1 */
1428c2ecf20Sopenharmony_ci	{
1438c2ecf20Sopenharmony_ci		.regulator = { NULL },
1448c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" },
1458c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1468c2ecf20Sopenharmony_ci				{ 0 },
1478c2ecf20Sopenharmony_ci				{ 0 },
1488c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
1498c2ecf20Sopenharmony_ci		.reg = { "csiphy1", "csiphy1_clk_mux" },
1508c2ecf20Sopenharmony_ci		.interrupt = { "csiphy1" }
1518c2ecf20Sopenharmony_ci	},
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* CSIPHY2 */
1548c2ecf20Sopenharmony_ci	{
1558c2ecf20Sopenharmony_ci		.regulator = { NULL },
1568c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer" },
1578c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1588c2ecf20Sopenharmony_ci				{ 0 },
1598c2ecf20Sopenharmony_ci				{ 0 },
1608c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 } },
1618c2ecf20Sopenharmony_ci		.reg = { "csiphy2", "csiphy2_clk_mux" },
1628c2ecf20Sopenharmony_ci		.interrupt = { "csiphy2" }
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic const struct resources csid_res_8x96[] = {
1678c2ecf20Sopenharmony_ci	/* CSID0 */
1688c2ecf20Sopenharmony_ci	{
1698c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
1708c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
1718c2ecf20Sopenharmony_ci			   "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" },
1728c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1738c2ecf20Sopenharmony_ci				{ 0 },
1748c2ecf20Sopenharmony_ci				{ 0 },
1758c2ecf20Sopenharmony_ci				{ 0 },
1768c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
1778c2ecf20Sopenharmony_ci				{ 0 },
1788c2ecf20Sopenharmony_ci				{ 0 },
1798c2ecf20Sopenharmony_ci				{ 0 } },
1808c2ecf20Sopenharmony_ci		.reg = { "csid0" },
1818c2ecf20Sopenharmony_ci		.interrupt = { "csid0" }
1828c2ecf20Sopenharmony_ci	},
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* CSID1 */
1858c2ecf20Sopenharmony_ci	{
1868c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
1878c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
1888c2ecf20Sopenharmony_ci			   "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" },
1898c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
1908c2ecf20Sopenharmony_ci				{ 0 },
1918c2ecf20Sopenharmony_ci				{ 0 },
1928c2ecf20Sopenharmony_ci				{ 0 },
1938c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
1948c2ecf20Sopenharmony_ci				{ 0 },
1958c2ecf20Sopenharmony_ci				{ 0 },
1968c2ecf20Sopenharmony_ci				{ 0 } },
1978c2ecf20Sopenharmony_ci		.reg = { "csid1" },
1988c2ecf20Sopenharmony_ci		.interrupt = { "csid1" }
1998c2ecf20Sopenharmony_ci	},
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* CSID2 */
2028c2ecf20Sopenharmony_ci	{
2038c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
2048c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
2058c2ecf20Sopenharmony_ci			   "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" },
2068c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
2078c2ecf20Sopenharmony_ci				{ 0 },
2088c2ecf20Sopenharmony_ci				{ 0 },
2098c2ecf20Sopenharmony_ci				{ 0 },
2108c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
2118c2ecf20Sopenharmony_ci				{ 0 },
2128c2ecf20Sopenharmony_ci				{ 0 },
2138c2ecf20Sopenharmony_ci				{ 0 } },
2148c2ecf20Sopenharmony_ci		.reg = { "csid2" },
2158c2ecf20Sopenharmony_ci		.interrupt = { "csid2" }
2168c2ecf20Sopenharmony_ci	},
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* CSID3 */
2198c2ecf20Sopenharmony_ci	{
2208c2ecf20Sopenharmony_ci		.regulator = { "vdda" },
2218c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb",
2228c2ecf20Sopenharmony_ci			   "csi3", "csi3_phy", "csi3_pix", "csi3_rdi" },
2238c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
2248c2ecf20Sopenharmony_ci				{ 0 },
2258c2ecf20Sopenharmony_ci				{ 0 },
2268c2ecf20Sopenharmony_ci				{ 0 },
2278c2ecf20Sopenharmony_ci				{ 100000000, 200000000, 266666667 },
2288c2ecf20Sopenharmony_ci				{ 0 },
2298c2ecf20Sopenharmony_ci				{ 0 },
2308c2ecf20Sopenharmony_ci				{ 0 } },
2318c2ecf20Sopenharmony_ci		.reg = { "csid3" },
2328c2ecf20Sopenharmony_ci		.interrupt = { "csid3" }
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic const struct resources_ispif ispif_res_8x96 = {
2378c2ecf20Sopenharmony_ci	/* ISPIF */
2388c2ecf20Sopenharmony_ci	.clock = { "top_ahb", "ahb", "ispif_ahb",
2398c2ecf20Sopenharmony_ci		   "csi0", "csi0_pix", "csi0_rdi",
2408c2ecf20Sopenharmony_ci		   "csi1", "csi1_pix", "csi1_rdi",
2418c2ecf20Sopenharmony_ci		   "csi2", "csi2_pix", "csi2_rdi",
2428c2ecf20Sopenharmony_ci		   "csi3", "csi3_pix", "csi3_rdi" },
2438c2ecf20Sopenharmony_ci	.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
2448c2ecf20Sopenharmony_ci	.reg = { "ispif", "csi_clk_mux" },
2458c2ecf20Sopenharmony_ci	.interrupt = "ispif"
2468c2ecf20Sopenharmony_ci};
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic const struct resources vfe_res_8x96[] = {
2498c2ecf20Sopenharmony_ci	/* VFE0 */
2508c2ecf20Sopenharmony_ci	{
2518c2ecf20Sopenharmony_ci		.regulator = { NULL },
2528c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ahb", "vfe0", "csi_vfe0", "vfe_ahb",
2538c2ecf20Sopenharmony_ci			   "vfe0_ahb", "vfe_axi", "vfe0_stream"},
2548c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
2558c2ecf20Sopenharmony_ci				{ 0 },
2568c2ecf20Sopenharmony_ci				{ 75000000, 100000000, 300000000,
2578c2ecf20Sopenharmony_ci				  320000000, 480000000, 600000000 },
2588c2ecf20Sopenharmony_ci				{ 0 },
2598c2ecf20Sopenharmony_ci				{ 0 },
2608c2ecf20Sopenharmony_ci				{ 0 },
2618c2ecf20Sopenharmony_ci				{ 0 },
2628c2ecf20Sopenharmony_ci				{ 0 } },
2638c2ecf20Sopenharmony_ci		.reg = { "vfe0" },
2648c2ecf20Sopenharmony_ci		.interrupt = { "vfe0" }
2658c2ecf20Sopenharmony_ci	},
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* VFE1 */
2688c2ecf20Sopenharmony_ci	{
2698c2ecf20Sopenharmony_ci		.regulator = { NULL },
2708c2ecf20Sopenharmony_ci		.clock = { "top_ahb", "ahb", "vfe1", "csi_vfe1", "vfe_ahb",
2718c2ecf20Sopenharmony_ci			   "vfe1_ahb", "vfe_axi", "vfe1_stream"},
2728c2ecf20Sopenharmony_ci		.clock_rate = { { 0 },
2738c2ecf20Sopenharmony_ci				{ 0 },
2748c2ecf20Sopenharmony_ci				{ 75000000, 100000000, 300000000,
2758c2ecf20Sopenharmony_ci				  320000000, 480000000, 600000000 },
2768c2ecf20Sopenharmony_ci				{ 0 },
2778c2ecf20Sopenharmony_ci				{ 0 },
2788c2ecf20Sopenharmony_ci				{ 0 },
2798c2ecf20Sopenharmony_ci				{ 0 },
2808c2ecf20Sopenharmony_ci				{ 0 } },
2818c2ecf20Sopenharmony_ci		.reg = { "vfe1" },
2828c2ecf20Sopenharmony_ci		.interrupt = { "vfe1" }
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/*
2878c2ecf20Sopenharmony_ci * camss_add_clock_margin - Add margin to clock frequency rate
2888c2ecf20Sopenharmony_ci * @rate: Clock frequency rate
2898c2ecf20Sopenharmony_ci *
2908c2ecf20Sopenharmony_ci * When making calculations with physical clock frequency values
2918c2ecf20Sopenharmony_ci * some safety margin must be added. Add it.
2928c2ecf20Sopenharmony_ci */
2938c2ecf20Sopenharmony_ciinline void camss_add_clock_margin(u64 *rate)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	*rate *= CAMSS_CLOCK_MARGIN_NUMERATOR;
2968c2ecf20Sopenharmony_ci	*rate = div_u64(*rate, CAMSS_CLOCK_MARGIN_DENOMINATOR);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/*
3008c2ecf20Sopenharmony_ci * camss_enable_clocks - Enable multiple clocks
3018c2ecf20Sopenharmony_ci * @nclocks: Number of clocks in clock array
3028c2ecf20Sopenharmony_ci * @clock: Clock array
3038c2ecf20Sopenharmony_ci * @dev: Device
3048c2ecf20Sopenharmony_ci *
3058c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
3068c2ecf20Sopenharmony_ci */
3078c2ecf20Sopenharmony_ciint camss_enable_clocks(int nclocks, struct camss_clock *clock,
3088c2ecf20Sopenharmony_ci			struct device *dev)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	int ret;
3118c2ecf20Sopenharmony_ci	int i;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	for (i = 0; i < nclocks; i++) {
3148c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(clock[i].clk);
3158c2ecf20Sopenharmony_ci		if (ret) {
3168c2ecf20Sopenharmony_ci			dev_err(dev, "clock enable failed: %d\n", ret);
3178c2ecf20Sopenharmony_ci			goto error;
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cierror:
3248c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
3258c2ecf20Sopenharmony_ci		clk_disable_unprepare(clock[i].clk);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return ret;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/*
3318c2ecf20Sopenharmony_ci * camss_disable_clocks - Disable multiple clocks
3328c2ecf20Sopenharmony_ci * @nclocks: Number of clocks in clock array
3338c2ecf20Sopenharmony_ci * @clock: Clock array
3348c2ecf20Sopenharmony_ci */
3358c2ecf20Sopenharmony_civoid camss_disable_clocks(int nclocks, struct camss_clock *clock)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int i;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	for (i = nclocks - 1; i >= 0; i--)
3408c2ecf20Sopenharmony_ci		clk_disable_unprepare(clock[i].clk);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/*
3448c2ecf20Sopenharmony_ci * camss_find_sensor - Find a linked media entity which represents a sensor
3458c2ecf20Sopenharmony_ci * @entity: Media entity to start searching from
3468c2ecf20Sopenharmony_ci *
3478c2ecf20Sopenharmony_ci * Return a pointer to sensor media entity or NULL if not found
3488c2ecf20Sopenharmony_ci */
3498c2ecf20Sopenharmony_cistruct media_entity *camss_find_sensor(struct media_entity *entity)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct media_pad *pad;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	while (1) {
3548c2ecf20Sopenharmony_ci		pad = &entity->pads[0];
3558c2ecf20Sopenharmony_ci		if (!(pad->flags & MEDIA_PAD_FL_SINK))
3568c2ecf20Sopenharmony_ci			return NULL;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		pad = media_entity_remote_pad(pad);
3598c2ecf20Sopenharmony_ci		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
3608c2ecf20Sopenharmony_ci			return NULL;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		entity = pad->entity;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
3658c2ecf20Sopenharmony_ci			return entity;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/*
3708c2ecf20Sopenharmony_ci * camss_get_pixel_clock - Get pixel clock rate from sensor
3718c2ecf20Sopenharmony_ci * @entity: Media entity in the current pipeline
3728c2ecf20Sopenharmony_ci * @pixel_clock: Received pixel clock value
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise
3758c2ecf20Sopenharmony_ci */
3768c2ecf20Sopenharmony_ciint camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct media_entity *sensor;
3798c2ecf20Sopenharmony_ci	struct v4l2_subdev *subdev;
3808c2ecf20Sopenharmony_ci	struct v4l2_ctrl *ctrl;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	sensor = camss_find_sensor(entity);
3838c2ecf20Sopenharmony_ci	if (!sensor)
3848c2ecf20Sopenharmony_ci		return -ENODEV;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	subdev = media_entity_to_v4l2_subdev(sensor);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (!ctrl)
3918c2ecf20Sopenharmony_ci		return -EINVAL;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	*pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	return 0;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ciint camss_pm_domain_on(struct camss *camss, int id)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x96) {
4018c2ecf20Sopenharmony_ci		camss->genpd_link[id] = device_link_add(camss->dev,
4028c2ecf20Sopenharmony_ci				camss->genpd[id], DL_FLAG_STATELESS |
4038c2ecf20Sopenharmony_ci				DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		if (!camss->genpd_link[id])
4068c2ecf20Sopenharmony_ci			return -EINVAL;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_civoid camss_pm_domain_off(struct camss *camss, int id)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x96)
4158c2ecf20Sopenharmony_ci		device_link_del(camss->genpd_link[id]);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci/*
4198c2ecf20Sopenharmony_ci * camss_of_parse_endpoint_node - Parse port endpoint node
4208c2ecf20Sopenharmony_ci * @dev: Device
4218c2ecf20Sopenharmony_ci * @node: Device node to be parsed
4228c2ecf20Sopenharmony_ci * @csd: Parsed data from port endpoint node
4238c2ecf20Sopenharmony_ci *
4248c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code on failure
4258c2ecf20Sopenharmony_ci */
4268c2ecf20Sopenharmony_cistatic int camss_of_parse_endpoint_node(struct device *dev,
4278c2ecf20Sopenharmony_ci					struct device_node *node,
4288c2ecf20Sopenharmony_ci					struct camss_async_subdev *csd)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg;
4318c2ecf20Sopenharmony_ci	struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2;
4328c2ecf20Sopenharmony_ci	struct v4l2_fwnode_endpoint vep = { { 0 } };
4338c2ecf20Sopenharmony_ci	unsigned int i;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	csd->interface.csiphy_id = vep.base.port;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	mipi_csi2 = &vep.bus.mipi_csi2;
4408c2ecf20Sopenharmony_ci	lncfg->clk.pos = mipi_csi2->clock_lane;
4418c2ecf20Sopenharmony_ci	lncfg->clk.pol = mipi_csi2->lane_polarities[0];
4428c2ecf20Sopenharmony_ci	lncfg->num_data = mipi_csi2->num_data_lanes;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	lncfg->data = devm_kcalloc(dev,
4458c2ecf20Sopenharmony_ci				   lncfg->num_data, sizeof(*lncfg->data),
4468c2ecf20Sopenharmony_ci				   GFP_KERNEL);
4478c2ecf20Sopenharmony_ci	if (!lncfg->data)
4488c2ecf20Sopenharmony_ci		return -ENOMEM;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for (i = 0; i < lncfg->num_data; i++) {
4518c2ecf20Sopenharmony_ci		lncfg->data[i].pos = mipi_csi2->data_lanes[i];
4528c2ecf20Sopenharmony_ci		lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1];
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/*
4598c2ecf20Sopenharmony_ci * camss_of_parse_ports - Parse ports node
4608c2ecf20Sopenharmony_ci * @dev: Device
4618c2ecf20Sopenharmony_ci * @notifier: v4l2_device notifier data
4628c2ecf20Sopenharmony_ci *
4638c2ecf20Sopenharmony_ci * Return number of "port" nodes found in "ports" node
4648c2ecf20Sopenharmony_ci */
4658c2ecf20Sopenharmony_cistatic int camss_of_parse_ports(struct camss *camss)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct device *dev = camss->dev;
4688c2ecf20Sopenharmony_ci	struct device_node *node = NULL;
4698c2ecf20Sopenharmony_ci	struct device_node *remote = NULL;
4708c2ecf20Sopenharmony_ci	int ret, num_subdevs = 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	for_each_endpoint_of_node(dev->of_node, node) {
4738c2ecf20Sopenharmony_ci		struct camss_async_subdev *csd;
4748c2ecf20Sopenharmony_ci		struct v4l2_async_subdev *asd;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		if (!of_device_is_available(node))
4778c2ecf20Sopenharmony_ci			continue;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		remote = of_graph_get_remote_port_parent(node);
4808c2ecf20Sopenharmony_ci		if (!remote) {
4818c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot get remote parent\n");
4828c2ecf20Sopenharmony_ci			ret = -EINVAL;
4838c2ecf20Sopenharmony_ci			goto err_cleanup;
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		asd = v4l2_async_notifier_add_fwnode_subdev(
4878c2ecf20Sopenharmony_ci			&camss->notifier, of_fwnode_handle(remote),
4888c2ecf20Sopenharmony_ci			sizeof(*csd));
4898c2ecf20Sopenharmony_ci		of_node_put(remote);
4908c2ecf20Sopenharmony_ci		if (IS_ERR(asd)) {
4918c2ecf20Sopenharmony_ci			ret = PTR_ERR(asd);
4928c2ecf20Sopenharmony_ci			goto err_cleanup;
4938c2ecf20Sopenharmony_ci		}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		csd = container_of(asd, struct camss_async_subdev, asd);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		ret = camss_of_parse_endpoint_node(dev, node, csd);
4988c2ecf20Sopenharmony_ci		if (ret < 0)
4998c2ecf20Sopenharmony_ci			goto err_cleanup;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		num_subdevs++;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return num_subdevs;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cierr_cleanup:
5078c2ecf20Sopenharmony_ci	of_node_put(node);
5088c2ecf20Sopenharmony_ci	return ret;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/*
5128c2ecf20Sopenharmony_ci * camss_init_subdevices - Initialize subdev structures and resources
5138c2ecf20Sopenharmony_ci * @camss: CAMSS device
5148c2ecf20Sopenharmony_ci *
5158c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code on failure
5168c2ecf20Sopenharmony_ci */
5178c2ecf20Sopenharmony_cistatic int camss_init_subdevices(struct camss *camss)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	const struct resources *csiphy_res;
5208c2ecf20Sopenharmony_ci	const struct resources *csid_res;
5218c2ecf20Sopenharmony_ci	const struct resources_ispif *ispif_res;
5228c2ecf20Sopenharmony_ci	const struct resources *vfe_res;
5238c2ecf20Sopenharmony_ci	unsigned int i;
5248c2ecf20Sopenharmony_ci	int ret;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x16) {
5278c2ecf20Sopenharmony_ci		csiphy_res = csiphy_res_8x16;
5288c2ecf20Sopenharmony_ci		csid_res = csid_res_8x16;
5298c2ecf20Sopenharmony_ci		ispif_res = &ispif_res_8x16;
5308c2ecf20Sopenharmony_ci		vfe_res = vfe_res_8x16;
5318c2ecf20Sopenharmony_ci	} else if (camss->version == CAMSS_8x96) {
5328c2ecf20Sopenharmony_ci		csiphy_res = csiphy_res_8x96;
5338c2ecf20Sopenharmony_ci		csid_res = csid_res_8x96;
5348c2ecf20Sopenharmony_ci		ispif_res = &ispif_res_8x96;
5358c2ecf20Sopenharmony_ci		vfe_res = vfe_res_8x96;
5368c2ecf20Sopenharmony_ci	} else {
5378c2ecf20Sopenharmony_ci		return -EINVAL;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
5418c2ecf20Sopenharmony_ci		ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i],
5428c2ecf20Sopenharmony_ci					     &csiphy_res[i], i);
5438c2ecf20Sopenharmony_ci		if (ret < 0) {
5448c2ecf20Sopenharmony_ci			dev_err(camss->dev,
5458c2ecf20Sopenharmony_ci				"Failed to init csiphy%d sub-device: %d\n",
5468c2ecf20Sopenharmony_ci				i, ret);
5478c2ecf20Sopenharmony_ci			return ret;
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++) {
5528c2ecf20Sopenharmony_ci		ret = msm_csid_subdev_init(camss, &camss->csid[i],
5538c2ecf20Sopenharmony_ci					   &csid_res[i], i);
5548c2ecf20Sopenharmony_ci		if (ret < 0) {
5558c2ecf20Sopenharmony_ci			dev_err(camss->dev,
5568c2ecf20Sopenharmony_ci				"Failed to init csid%d sub-device: %d\n",
5578c2ecf20Sopenharmony_ci				i, ret);
5588c2ecf20Sopenharmony_ci			return ret;
5598c2ecf20Sopenharmony_ci		}
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
5638c2ecf20Sopenharmony_ci	if (ret < 0) {
5648c2ecf20Sopenharmony_ci		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
5658c2ecf20Sopenharmony_ci			ret);
5668c2ecf20Sopenharmony_ci		return ret;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	for (i = 0; i < camss->vfe_num; i++) {
5708c2ecf20Sopenharmony_ci		ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
5718c2ecf20Sopenharmony_ci					  &vfe_res[i], i);
5728c2ecf20Sopenharmony_ci		if (ret < 0) {
5738c2ecf20Sopenharmony_ci			dev_err(camss->dev,
5748c2ecf20Sopenharmony_ci				"Fail to init vfe%d sub-device: %d\n", i, ret);
5758c2ecf20Sopenharmony_ci			return ret;
5768c2ecf20Sopenharmony_ci		}
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci/*
5838c2ecf20Sopenharmony_ci * camss_register_entities - Register subdev nodes and create links
5848c2ecf20Sopenharmony_ci * @camss: CAMSS device
5858c2ecf20Sopenharmony_ci *
5868c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code on failure
5878c2ecf20Sopenharmony_ci */
5888c2ecf20Sopenharmony_cistatic int camss_register_entities(struct camss *camss)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	int i, j, k;
5918c2ecf20Sopenharmony_ci	int ret;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
5948c2ecf20Sopenharmony_ci		ret = msm_csiphy_register_entity(&camss->csiphy[i],
5958c2ecf20Sopenharmony_ci						 &camss->v4l2_dev);
5968c2ecf20Sopenharmony_ci		if (ret < 0) {
5978c2ecf20Sopenharmony_ci			dev_err(camss->dev,
5988c2ecf20Sopenharmony_ci				"Failed to register csiphy%d entity: %d\n",
5998c2ecf20Sopenharmony_ci				i, ret);
6008c2ecf20Sopenharmony_ci			goto err_reg_csiphy;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++) {
6058c2ecf20Sopenharmony_ci		ret = msm_csid_register_entity(&camss->csid[i],
6068c2ecf20Sopenharmony_ci					       &camss->v4l2_dev);
6078c2ecf20Sopenharmony_ci		if (ret < 0) {
6088c2ecf20Sopenharmony_ci			dev_err(camss->dev,
6098c2ecf20Sopenharmony_ci				"Failed to register csid%d entity: %d\n",
6108c2ecf20Sopenharmony_ci				i, ret);
6118c2ecf20Sopenharmony_ci			goto err_reg_csid;
6128c2ecf20Sopenharmony_ci		}
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
6168c2ecf20Sopenharmony_ci	if (ret < 0) {
6178c2ecf20Sopenharmony_ci		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
6188c2ecf20Sopenharmony_ci			ret);
6198c2ecf20Sopenharmony_ci		goto err_reg_ispif;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	for (i = 0; i < camss->vfe_num; i++) {
6238c2ecf20Sopenharmony_ci		ret = msm_vfe_register_entities(&camss->vfe[i],
6248c2ecf20Sopenharmony_ci						&camss->v4l2_dev);
6258c2ecf20Sopenharmony_ci		if (ret < 0) {
6268c2ecf20Sopenharmony_ci			dev_err(camss->dev,
6278c2ecf20Sopenharmony_ci				"Failed to register vfe%d entities: %d\n",
6288c2ecf20Sopenharmony_ci				i, ret);
6298c2ecf20Sopenharmony_ci			goto err_reg_vfe;
6308c2ecf20Sopenharmony_ci		}
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++) {
6348c2ecf20Sopenharmony_ci		for (j = 0; j < camss->csid_num; j++) {
6358c2ecf20Sopenharmony_ci			ret = media_create_pad_link(
6368c2ecf20Sopenharmony_ci				&camss->csiphy[i].subdev.entity,
6378c2ecf20Sopenharmony_ci				MSM_CSIPHY_PAD_SRC,
6388c2ecf20Sopenharmony_ci				&camss->csid[j].subdev.entity,
6398c2ecf20Sopenharmony_ci				MSM_CSID_PAD_SINK,
6408c2ecf20Sopenharmony_ci				0);
6418c2ecf20Sopenharmony_ci			if (ret < 0) {
6428c2ecf20Sopenharmony_ci				dev_err(camss->dev,
6438c2ecf20Sopenharmony_ci					"Failed to link %s->%s entities: %d\n",
6448c2ecf20Sopenharmony_ci					camss->csiphy[i].subdev.entity.name,
6458c2ecf20Sopenharmony_ci					camss->csid[j].subdev.entity.name,
6468c2ecf20Sopenharmony_ci					ret);
6478c2ecf20Sopenharmony_ci				goto err_link;
6488c2ecf20Sopenharmony_ci			}
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++) {
6538c2ecf20Sopenharmony_ci		for (j = 0; j < camss->ispif.line_num; j++) {
6548c2ecf20Sopenharmony_ci			ret = media_create_pad_link(
6558c2ecf20Sopenharmony_ci				&camss->csid[i].subdev.entity,
6568c2ecf20Sopenharmony_ci				MSM_CSID_PAD_SRC,
6578c2ecf20Sopenharmony_ci				&camss->ispif.line[j].subdev.entity,
6588c2ecf20Sopenharmony_ci				MSM_ISPIF_PAD_SINK,
6598c2ecf20Sopenharmony_ci				0);
6608c2ecf20Sopenharmony_ci			if (ret < 0) {
6618c2ecf20Sopenharmony_ci				dev_err(camss->dev,
6628c2ecf20Sopenharmony_ci					"Failed to link %s->%s entities: %d\n",
6638c2ecf20Sopenharmony_ci					camss->csid[i].subdev.entity.name,
6648c2ecf20Sopenharmony_ci					camss->ispif.line[j].subdev.entity.name,
6658c2ecf20Sopenharmony_ci					ret);
6668c2ecf20Sopenharmony_ci				goto err_link;
6678c2ecf20Sopenharmony_ci			}
6688c2ecf20Sopenharmony_ci		}
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	for (i = 0; i < camss->ispif.line_num; i++)
6728c2ecf20Sopenharmony_ci		for (k = 0; k < camss->vfe_num; k++)
6738c2ecf20Sopenharmony_ci			for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
6748c2ecf20Sopenharmony_ci				ret = media_create_pad_link(
6758c2ecf20Sopenharmony_ci					&camss->ispif.line[i].subdev.entity,
6768c2ecf20Sopenharmony_ci					MSM_ISPIF_PAD_SRC,
6778c2ecf20Sopenharmony_ci					&camss->vfe[k].line[j].subdev.entity,
6788c2ecf20Sopenharmony_ci					MSM_VFE_PAD_SINK,
6798c2ecf20Sopenharmony_ci					0);
6808c2ecf20Sopenharmony_ci				if (ret < 0) {
6818c2ecf20Sopenharmony_ci					dev_err(camss->dev,
6828c2ecf20Sopenharmony_ci						"Failed to link %s->%s entities: %d\n",
6838c2ecf20Sopenharmony_ci						camss->ispif.line[i].subdev.entity.name,
6848c2ecf20Sopenharmony_ci						camss->vfe[k].line[j].subdev.entity.name,
6858c2ecf20Sopenharmony_ci						ret);
6868c2ecf20Sopenharmony_ci					goto err_link;
6878c2ecf20Sopenharmony_ci				}
6888c2ecf20Sopenharmony_ci			}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	return 0;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cierr_link:
6938c2ecf20Sopenharmony_ci	i = camss->vfe_num;
6948c2ecf20Sopenharmony_cierr_reg_vfe:
6958c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
6968c2ecf20Sopenharmony_ci		msm_vfe_unregister_entities(&camss->vfe[i]);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	msm_ispif_unregister_entities(&camss->ispif);
6998c2ecf20Sopenharmony_cierr_reg_ispif:
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	i = camss->csid_num;
7028c2ecf20Sopenharmony_cierr_reg_csid:
7038c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
7048c2ecf20Sopenharmony_ci		msm_csid_unregister_entity(&camss->csid[i]);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	i = camss->csiphy_num;
7078c2ecf20Sopenharmony_cierr_reg_csiphy:
7088c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
7098c2ecf20Sopenharmony_ci		msm_csiphy_unregister_entity(&camss->csiphy[i]);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return ret;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/*
7158c2ecf20Sopenharmony_ci * camss_unregister_entities - Unregister subdev nodes
7168c2ecf20Sopenharmony_ci * @camss: CAMSS device
7178c2ecf20Sopenharmony_ci *
7188c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code on failure
7198c2ecf20Sopenharmony_ci */
7208c2ecf20Sopenharmony_cistatic void camss_unregister_entities(struct camss *camss)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	unsigned int i;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csiphy_num; i++)
7258c2ecf20Sopenharmony_ci		msm_csiphy_unregister_entity(&camss->csiphy[i]);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	for (i = 0; i < camss->csid_num; i++)
7288c2ecf20Sopenharmony_ci		msm_csid_unregister_entity(&camss->csid[i]);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	msm_ispif_unregister_entities(&camss->ispif);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	for (i = 0; i < camss->vfe_num; i++)
7338c2ecf20Sopenharmony_ci		msm_vfe_unregister_entities(&camss->vfe[i]);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic int camss_subdev_notifier_bound(struct v4l2_async_notifier *async,
7378c2ecf20Sopenharmony_ci				       struct v4l2_subdev *subdev,
7388c2ecf20Sopenharmony_ci				       struct v4l2_async_subdev *asd)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct camss *camss = container_of(async, struct camss, notifier);
7418c2ecf20Sopenharmony_ci	struct camss_async_subdev *csd =
7428c2ecf20Sopenharmony_ci		container_of(asd, struct camss_async_subdev, asd);
7438c2ecf20Sopenharmony_ci	u8 id = csd->interface.csiphy_id;
7448c2ecf20Sopenharmony_ci	struct csiphy_device *csiphy = &camss->csiphy[id];
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	csiphy->cfg.csi2 = &csd->interface.csi2;
7478c2ecf20Sopenharmony_ci	subdev->host_priv = csiphy;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return 0;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct camss *camss = container_of(async, struct camss, notifier);
7558c2ecf20Sopenharmony_ci	struct v4l2_device *v4l2_dev = &camss->v4l2_dev;
7568c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd;
7578c2ecf20Sopenharmony_ci	int ret;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
7608c2ecf20Sopenharmony_ci		if (sd->host_priv) {
7618c2ecf20Sopenharmony_ci			struct media_entity *sensor = &sd->entity;
7628c2ecf20Sopenharmony_ci			struct csiphy_device *csiphy =
7638c2ecf20Sopenharmony_ci					(struct csiphy_device *) sd->host_priv;
7648c2ecf20Sopenharmony_ci			struct media_entity *input = &csiphy->subdev.entity;
7658c2ecf20Sopenharmony_ci			unsigned int i;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci			for (i = 0; i < sensor->num_pads; i++) {
7688c2ecf20Sopenharmony_ci				if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
7698c2ecf20Sopenharmony_ci					break;
7708c2ecf20Sopenharmony_ci			}
7718c2ecf20Sopenharmony_ci			if (i == sensor->num_pads) {
7728c2ecf20Sopenharmony_ci				dev_err(camss->dev,
7738c2ecf20Sopenharmony_ci					"No source pad in external entity\n");
7748c2ecf20Sopenharmony_ci				return -EINVAL;
7758c2ecf20Sopenharmony_ci			}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci			ret = media_create_pad_link(sensor, i,
7788c2ecf20Sopenharmony_ci				input, MSM_CSIPHY_PAD_SINK,
7798c2ecf20Sopenharmony_ci				MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
7808c2ecf20Sopenharmony_ci			if (ret < 0) {
7818c2ecf20Sopenharmony_ci				dev_err(camss->dev,
7828c2ecf20Sopenharmony_ci					"Failed to link %s->%s entities: %d\n",
7838c2ecf20Sopenharmony_ci					sensor->name, input->name, ret);
7848c2ecf20Sopenharmony_ci				return ret;
7858c2ecf20Sopenharmony_ci			}
7868c2ecf20Sopenharmony_ci		}
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev);
7908c2ecf20Sopenharmony_ci	if (ret < 0)
7918c2ecf20Sopenharmony_ci		return ret;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return media_device_register(&camss->media_dev);
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = {
7978c2ecf20Sopenharmony_ci	.bound = camss_subdev_notifier_bound,
7988c2ecf20Sopenharmony_ci	.complete = camss_subdev_notifier_complete,
7998c2ecf20Sopenharmony_ci};
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic const struct media_device_ops camss_media_ops = {
8028c2ecf20Sopenharmony_ci	.link_notify = v4l2_pipeline_link_notify,
8038c2ecf20Sopenharmony_ci};
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci/*
8068c2ecf20Sopenharmony_ci * camss_probe - Probe CAMSS platform device
8078c2ecf20Sopenharmony_ci * @pdev: Pointer to CAMSS platform device
8088c2ecf20Sopenharmony_ci *
8098c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code on failure
8108c2ecf20Sopenharmony_ci */
8118c2ecf20Sopenharmony_cistatic int camss_probe(struct platform_device *pdev)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
8148c2ecf20Sopenharmony_ci	struct camss *camss;
8158c2ecf20Sopenharmony_ci	int num_subdevs, ret;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	camss = kzalloc(sizeof(*camss), GFP_KERNEL);
8188c2ecf20Sopenharmony_ci	if (!camss)
8198c2ecf20Sopenharmony_ci		return -ENOMEM;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	atomic_set(&camss->ref_count, 0);
8228c2ecf20Sopenharmony_ci	camss->dev = dev;
8238c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, camss);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) {
8268c2ecf20Sopenharmony_ci		camss->version = CAMSS_8x16;
8278c2ecf20Sopenharmony_ci		camss->csiphy_num = 2;
8288c2ecf20Sopenharmony_ci		camss->csid_num = 2;
8298c2ecf20Sopenharmony_ci		camss->vfe_num = 1;
8308c2ecf20Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
8318c2ecf20Sopenharmony_ci					   "qcom,msm8996-camss")) {
8328c2ecf20Sopenharmony_ci		camss->version = CAMSS_8x96;
8338c2ecf20Sopenharmony_ci		camss->csiphy_num = 3;
8348c2ecf20Sopenharmony_ci		camss->csid_num = 4;
8358c2ecf20Sopenharmony_ci		camss->vfe_num = 2;
8368c2ecf20Sopenharmony_ci	} else {
8378c2ecf20Sopenharmony_ci		ret = -EINVAL;
8388c2ecf20Sopenharmony_ci		goto err_free;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	camss->csiphy = devm_kcalloc(dev, camss->csiphy_num,
8428c2ecf20Sopenharmony_ci				     sizeof(*camss->csiphy), GFP_KERNEL);
8438c2ecf20Sopenharmony_ci	if (!camss->csiphy) {
8448c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8458c2ecf20Sopenharmony_ci		goto err_free;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid),
8498c2ecf20Sopenharmony_ci				   GFP_KERNEL);
8508c2ecf20Sopenharmony_ci	if (!camss->csid) {
8518c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8528c2ecf20Sopenharmony_ci		goto err_free;
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
8568c2ecf20Sopenharmony_ci				  GFP_KERNEL);
8578c2ecf20Sopenharmony_ci	if (!camss->vfe) {
8588c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8598c2ecf20Sopenharmony_ci		goto err_free;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	v4l2_async_notifier_init(&camss->notifier);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	num_subdevs = camss_of_parse_ports(camss);
8658c2ecf20Sopenharmony_ci	if (num_subdevs < 0) {
8668c2ecf20Sopenharmony_ci		ret = num_subdevs;
8678c2ecf20Sopenharmony_ci		goto err_cleanup;
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	ret = camss_init_subdevices(camss);
8718c2ecf20Sopenharmony_ci	if (ret < 0)
8728c2ecf20Sopenharmony_ci		goto err_cleanup;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, 0xffffffff);
8758c2ecf20Sopenharmony_ci	if (ret)
8768c2ecf20Sopenharmony_ci		goto err_cleanup;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	camss->media_dev.dev = camss->dev;
8798c2ecf20Sopenharmony_ci	strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem",
8808c2ecf20Sopenharmony_ci		sizeof(camss->media_dev.model));
8818c2ecf20Sopenharmony_ci	camss->media_dev.ops = &camss_media_ops;
8828c2ecf20Sopenharmony_ci	media_device_init(&camss->media_dev);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	camss->v4l2_dev.mdev = &camss->media_dev;
8858c2ecf20Sopenharmony_ci	ret = v4l2_device_register(camss->dev, &camss->v4l2_dev);
8868c2ecf20Sopenharmony_ci	if (ret < 0) {
8878c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
8888c2ecf20Sopenharmony_ci		goto err_cleanup;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	ret = camss_register_entities(camss);
8928c2ecf20Sopenharmony_ci	if (ret < 0)
8938c2ecf20Sopenharmony_ci		goto err_register_entities;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (num_subdevs) {
8968c2ecf20Sopenharmony_ci		camss->notifier.ops = &camss_subdev_notifier_ops;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		ret = v4l2_async_notifier_register(&camss->v4l2_dev,
8998c2ecf20Sopenharmony_ci						   &camss->notifier);
9008c2ecf20Sopenharmony_ci		if (ret) {
9018c2ecf20Sopenharmony_ci			dev_err(dev,
9028c2ecf20Sopenharmony_ci				"Failed to register async subdev nodes: %d\n",
9038c2ecf20Sopenharmony_ci				ret);
9048c2ecf20Sopenharmony_ci			goto err_register_subdevs;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci	} else {
9078c2ecf20Sopenharmony_ci		ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev);
9088c2ecf20Sopenharmony_ci		if (ret < 0) {
9098c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to register subdev nodes: %d\n",
9108c2ecf20Sopenharmony_ci				ret);
9118c2ecf20Sopenharmony_ci			goto err_register_subdevs;
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		ret = media_device_register(&camss->media_dev);
9158c2ecf20Sopenharmony_ci		if (ret < 0) {
9168c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to register media device: %d\n",
9178c2ecf20Sopenharmony_ci				ret);
9188c2ecf20Sopenharmony_ci			goto err_register_subdevs;
9198c2ecf20Sopenharmony_ci		}
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x96) {
9238c2ecf20Sopenharmony_ci		camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
9248c2ecf20Sopenharmony_ci						camss->dev, PM_DOMAIN_VFE0);
9258c2ecf20Sopenharmony_ci		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
9268c2ecf20Sopenharmony_ci			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id(
9298c2ecf20Sopenharmony_ci						camss->dev, PM_DOMAIN_VFE1);
9308c2ecf20Sopenharmony_ci		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) {
9318c2ecf20Sopenharmony_ci			dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0],
9328c2ecf20Sopenharmony_ci					     true);
9338c2ecf20Sopenharmony_ci			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]);
9348c2ecf20Sopenharmony_ci		}
9358c2ecf20Sopenharmony_ci	}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	return 0;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cierr_register_subdevs:
9428c2ecf20Sopenharmony_ci	camss_unregister_entities(camss);
9438c2ecf20Sopenharmony_cierr_register_entities:
9448c2ecf20Sopenharmony_ci	v4l2_device_unregister(&camss->v4l2_dev);
9458c2ecf20Sopenharmony_cierr_cleanup:
9468c2ecf20Sopenharmony_ci	v4l2_async_notifier_cleanup(&camss->notifier);
9478c2ecf20Sopenharmony_cierr_free:
9488c2ecf20Sopenharmony_ci	kfree(camss);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	return ret;
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_civoid camss_delete(struct camss *camss)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	v4l2_device_unregister(&camss->v4l2_dev);
9568c2ecf20Sopenharmony_ci	media_device_unregister(&camss->media_dev);
9578c2ecf20Sopenharmony_ci	media_device_cleanup(&camss->media_dev);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	pm_runtime_disable(camss->dev);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (camss->version == CAMSS_8x96) {
9628c2ecf20Sopenharmony_ci		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
9638c2ecf20Sopenharmony_ci		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	kfree(camss);
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci/*
9708c2ecf20Sopenharmony_ci * camss_remove - Remove CAMSS platform device
9718c2ecf20Sopenharmony_ci * @pdev: Pointer to CAMSS platform device
9728c2ecf20Sopenharmony_ci *
9738c2ecf20Sopenharmony_ci * Always returns 0.
9748c2ecf20Sopenharmony_ci */
9758c2ecf20Sopenharmony_cistatic int camss_remove(struct platform_device *pdev)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	struct camss *camss = platform_get_drvdata(pdev);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	v4l2_async_notifier_unregister(&camss->notifier);
9808c2ecf20Sopenharmony_ci	v4l2_async_notifier_cleanup(&camss->notifier);
9818c2ecf20Sopenharmony_ci	camss_unregister_entities(camss);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	if (atomic_read(&camss->ref_count) == 0)
9848c2ecf20Sopenharmony_ci		camss_delete(camss);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	return 0;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cistatic const struct of_device_id camss_dt_match[] = {
9908c2ecf20Sopenharmony_ci	{ .compatible = "qcom,msm8916-camss" },
9918c2ecf20Sopenharmony_ci	{ .compatible = "qcom,msm8996-camss" },
9928c2ecf20Sopenharmony_ci	{ }
9938c2ecf20Sopenharmony_ci};
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, camss_dt_match);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic int __maybe_unused camss_runtime_suspend(struct device *dev)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	return 0;
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic int __maybe_unused camss_runtime_resume(struct device *dev)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	return 0;
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic const struct dev_pm_ops camss_pm_ops = {
10088c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
10098c2ecf20Sopenharmony_ci				pm_runtime_force_resume)
10108c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(camss_runtime_suspend, camss_runtime_resume, NULL)
10118c2ecf20Sopenharmony_ci};
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_cistatic struct platform_driver qcom_camss_driver = {
10148c2ecf20Sopenharmony_ci	.probe = camss_probe,
10158c2ecf20Sopenharmony_ci	.remove = camss_remove,
10168c2ecf20Sopenharmony_ci	.driver = {
10178c2ecf20Sopenharmony_ci		.name = "qcom-camss",
10188c2ecf20Sopenharmony_ci		.of_match_table = camss_dt_match,
10198c2ecf20Sopenharmony_ci		.pm = &camss_pm_ops,
10208c2ecf20Sopenharmony_ci	},
10218c2ecf20Sopenharmony_ci};
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cimodule_platform_driver(qcom_camss_driver);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:qcom-camss");
10268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Camera Subsystem driver");
10278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>");
10288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1029