1b873663bSTodor Tomov // SPDX-License-Identifier: GPL-2.0 2ec6859b2STodor Tomov /* 3ec6859b2STodor Tomov * camss.c 4ec6859b2STodor Tomov * 5ec6859b2STodor Tomov * Qualcomm MSM Camera Subsystem - Core 6ec6859b2STodor Tomov * 7ec6859b2STodor Tomov * Copyright (c) 2015, The Linux Foundation. All rights reserved. 8ec6859b2STodor Tomov * Copyright (C) 2015-2018 Linaro Ltd. 9ec6859b2STodor Tomov */ 10ec6859b2STodor Tomov #include <linux/clk.h> 115ba38efbSBryan O'Donoghue #include <linux/interconnect.h> 12ec6859b2STodor Tomov #include <linux/media-bus-format.h> 13ec6859b2STodor Tomov #include <linux/media.h> 14ec6859b2STodor Tomov #include <linux/module.h> 15ec6859b2STodor Tomov #include <linux/platform_device.h> 16ec6859b2STodor Tomov #include <linux/of.h> 17ec6859b2STodor Tomov #include <linux/of_graph.h> 1802afa816STodor Tomov #include <linux/pm_runtime.h> 1902afa816STodor Tomov #include <linux/pm_domain.h> 20ec6859b2STodor Tomov #include <linux/slab.h> 21ec6859b2STodor Tomov #include <linux/videodev2.h> 22ec6859b2STodor Tomov 23ec6859b2STodor Tomov #include <media/media-device.h> 24ec6859b2STodor Tomov #include <media/v4l2-async.h> 25ec6859b2STodor Tomov #include <media/v4l2-device.h> 26ec6859b2STodor Tomov #include <media/v4l2-mc.h> 27ec6859b2STodor Tomov #include <media/v4l2-fwnode.h> 28ec6859b2STodor Tomov 29ec6859b2STodor Tomov #include "camss.h" 30ec6859b2STodor Tomov 31ec6859b2STodor Tomov #define CAMSS_CLOCK_MARGIN_NUMERATOR 105 32ec6859b2STodor Tomov #define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 33ec6859b2STodor Tomov 349c3e59deSTodor Tomov static const struct resources csiphy_res_8x16[] = { 35ec6859b2STodor Tomov /* CSIPHY0 */ 36ec6859b2STodor Tomov { 3781bdfa4fSBryan O'Donoghue .regulators = {}, 3809a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, 39ec6859b2STodor Tomov .clock_rate = { { 0 }, 40ec6859b2STodor Tomov { 0 }, 41ec6859b2STodor Tomov { 0 }, 42ec6859b2STodor Tomov { 100000000, 200000000 } }, 43ec6859b2STodor Tomov .reg = { "csiphy0", "csiphy0_clk_mux" }, 44ec6859b2STodor Tomov .interrupt = { "csiphy0" } 45ec6859b2STodor Tomov }, 46ec6859b2STodor Tomov 47ec6859b2STodor Tomov /* CSIPHY1 */ 48ec6859b2STodor Tomov { 4981bdfa4fSBryan O'Donoghue .regulators = {}, 5009a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, 51ec6859b2STodor Tomov .clock_rate = { { 0 }, 52ec6859b2STodor Tomov { 0 }, 53ec6859b2STodor Tomov { 0 }, 54ec6859b2STodor Tomov { 100000000, 200000000 } }, 55ec6859b2STodor Tomov .reg = { "csiphy1", "csiphy1_clk_mux" }, 56ec6859b2STodor Tomov .interrupt = { "csiphy1" } 57ec6859b2STodor Tomov } 58ec6859b2STodor Tomov }; 59ec6859b2STodor Tomov 609c3e59deSTodor Tomov static const struct resources csid_res_8x16[] = { 61ec6859b2STodor Tomov /* CSID0 */ 62ec6859b2STodor Tomov { 630d814017SBryan O'Donoghue .regulators = { "vdda" }, 6409a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 65ec6859b2STodor Tomov "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, 66ec6859b2STodor Tomov .clock_rate = { { 0 }, 67ec6859b2STodor Tomov { 0 }, 68ec6859b2STodor Tomov { 0 }, 69ec6859b2STodor Tomov { 0 }, 70ec6859b2STodor Tomov { 100000000, 200000000 }, 71ec6859b2STodor Tomov { 0 }, 72ec6859b2STodor Tomov { 0 }, 73ec6859b2STodor Tomov { 0 } }, 74ec6859b2STodor Tomov .reg = { "csid0" }, 75ec6859b2STodor Tomov .interrupt = { "csid0" } 76ec6859b2STodor Tomov }, 77ec6859b2STodor Tomov 78ec6859b2STodor Tomov /* CSID1 */ 79ec6859b2STodor Tomov { 800d814017SBryan O'Donoghue .regulators = { "vdda" }, 8109a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 82ec6859b2STodor Tomov "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, 83ec6859b2STodor Tomov .clock_rate = { { 0 }, 84ec6859b2STodor Tomov { 0 }, 85ec6859b2STodor Tomov { 0 }, 86ec6859b2STodor Tomov { 0 }, 87ec6859b2STodor Tomov { 100000000, 200000000 }, 88ec6859b2STodor Tomov { 0 }, 89ec6859b2STodor Tomov { 0 }, 90ec6859b2STodor Tomov { 0 } }, 91ec6859b2STodor Tomov .reg = { "csid1" }, 92ec6859b2STodor Tomov .interrupt = { "csid1" } 93ec6859b2STodor Tomov }, 94ec6859b2STodor Tomov }; 95ec6859b2STodor Tomov 969c3e59deSTodor Tomov static const struct resources_ispif ispif_res_8x16 = { 97ec6859b2STodor Tomov /* ISPIF */ 9809a94865STodor Tomov .clock = { "top_ahb", "ahb", "ispif_ahb", 99ec6859b2STodor Tomov "csi0", "csi0_pix", "csi0_rdi", 100ec6859b2STodor Tomov "csi1", "csi1_pix", "csi1_rdi" }, 10109a94865STodor Tomov .clock_for_reset = { "vfe0", "csi_vfe0" }, 102ec6859b2STodor Tomov .reg = { "ispif", "csi_clk_mux" }, 103ec6859b2STodor Tomov .interrupt = "ispif" 104ec6859b2STodor Tomov 105ec6859b2STodor Tomov }; 106ec6859b2STodor Tomov 1079c3e59deSTodor Tomov static const struct resources vfe_res_8x16[] = { 108ec6859b2STodor Tomov /* VFE0 */ 1099c3e59deSTodor Tomov { 11081bdfa4fSBryan O'Donoghue .regulators = {}, 11109a94865STodor Tomov .clock = { "top_ahb", "vfe0", "csi_vfe0", 11209a94865STodor Tomov "vfe_ahb", "vfe_axi", "ahb" }, 113ec6859b2STodor Tomov .clock_rate = { { 0 }, 114ec6859b2STodor Tomov { 50000000, 80000000, 100000000, 160000000, 115ec6859b2STodor Tomov 177780000, 200000000, 266670000, 320000000, 116ec6859b2STodor Tomov 400000000, 465000000 }, 117ec6859b2STodor Tomov { 0 }, 118ec6859b2STodor Tomov { 0 }, 119ec6859b2STodor Tomov { 0 }, 120ec6859b2STodor Tomov { 0 }, 121ec6859b2STodor Tomov { 0 }, 122ec6859b2STodor Tomov { 0 }, 123ec6859b2STodor Tomov { 0 } }, 124ec6859b2STodor Tomov .reg = { "vfe0" }, 125ec6859b2STodor Tomov .interrupt = { "vfe0" } 1269c3e59deSTodor Tomov } 1279c3e59deSTodor Tomov }; 1289c3e59deSTodor Tomov 1299c3e59deSTodor Tomov static const struct resources csiphy_res_8x96[] = { 1309c3e59deSTodor Tomov /* CSIPHY0 */ 1319c3e59deSTodor Tomov { 13281bdfa4fSBryan O'Donoghue .regulators = {}, 1339c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, 1349c3e59deSTodor Tomov .clock_rate = { { 0 }, 1359c3e59deSTodor Tomov { 0 }, 1369c3e59deSTodor Tomov { 0 }, 1379c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1389c3e59deSTodor Tomov .reg = { "csiphy0", "csiphy0_clk_mux" }, 1399c3e59deSTodor Tomov .interrupt = { "csiphy0" } 1409c3e59deSTodor Tomov }, 1419c3e59deSTodor Tomov 1429c3e59deSTodor Tomov /* CSIPHY1 */ 1439c3e59deSTodor Tomov { 14481bdfa4fSBryan O'Donoghue .regulators = {}, 1459c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, 1469c3e59deSTodor Tomov .clock_rate = { { 0 }, 1479c3e59deSTodor Tomov { 0 }, 1489c3e59deSTodor Tomov { 0 }, 1499c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1509c3e59deSTodor Tomov .reg = { "csiphy1", "csiphy1_clk_mux" }, 1519c3e59deSTodor Tomov .interrupt = { "csiphy1" } 1529c3e59deSTodor Tomov }, 1539c3e59deSTodor Tomov 1549c3e59deSTodor Tomov /* CSIPHY2 */ 1559c3e59deSTodor Tomov { 15681bdfa4fSBryan O'Donoghue .regulators = {}, 1579c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer" }, 1589c3e59deSTodor Tomov .clock_rate = { { 0 }, 1599c3e59deSTodor Tomov { 0 }, 1609c3e59deSTodor Tomov { 0 }, 1619c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1629c3e59deSTodor Tomov .reg = { "csiphy2", "csiphy2_clk_mux" }, 1639c3e59deSTodor Tomov .interrupt = { "csiphy2" } 1649c3e59deSTodor Tomov } 1659c3e59deSTodor Tomov }; 1669c3e59deSTodor Tomov 1679c3e59deSTodor Tomov static const struct resources csid_res_8x96[] = { 1689c3e59deSTodor Tomov /* CSID0 */ 1699c3e59deSTodor Tomov { 1700d814017SBryan O'Donoghue .regulators = { "vdda" }, 1719c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 1729c3e59deSTodor Tomov "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, 1739c3e59deSTodor Tomov .clock_rate = { { 0 }, 1749c3e59deSTodor Tomov { 0 }, 1759c3e59deSTodor Tomov { 0 }, 1769c3e59deSTodor Tomov { 0 }, 1779c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 1789c3e59deSTodor Tomov { 0 }, 1799c3e59deSTodor Tomov { 0 }, 1809c3e59deSTodor Tomov { 0 } }, 1819c3e59deSTodor Tomov .reg = { "csid0" }, 1829c3e59deSTodor Tomov .interrupt = { "csid0" } 1839c3e59deSTodor Tomov }, 1849c3e59deSTodor Tomov 1859c3e59deSTodor Tomov /* CSID1 */ 1869c3e59deSTodor Tomov { 1870d814017SBryan O'Donoghue .regulators = { "vdda" }, 1889c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 1899c3e59deSTodor Tomov "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, 1909c3e59deSTodor Tomov .clock_rate = { { 0 }, 1919c3e59deSTodor Tomov { 0 }, 1929c3e59deSTodor Tomov { 0 }, 1939c3e59deSTodor Tomov { 0 }, 1949c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 1959c3e59deSTodor Tomov { 0 }, 1969c3e59deSTodor Tomov { 0 }, 1979c3e59deSTodor Tomov { 0 } }, 1989c3e59deSTodor Tomov .reg = { "csid1" }, 1999c3e59deSTodor Tomov .interrupt = { "csid1" } 2009c3e59deSTodor Tomov }, 2019c3e59deSTodor Tomov 2029c3e59deSTodor Tomov /* CSID2 */ 2039c3e59deSTodor Tomov { 2040d814017SBryan O'Donoghue .regulators = { "vdda" }, 2059c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", 2069c3e59deSTodor Tomov "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, 2079c3e59deSTodor Tomov .clock_rate = { { 0 }, 2089c3e59deSTodor Tomov { 0 }, 2099c3e59deSTodor Tomov { 0 }, 2109c3e59deSTodor Tomov { 0 }, 2119c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 2129c3e59deSTodor Tomov { 0 }, 2139c3e59deSTodor Tomov { 0 }, 2149c3e59deSTodor Tomov { 0 } }, 2159c3e59deSTodor Tomov .reg = { "csid2" }, 2169c3e59deSTodor Tomov .interrupt = { "csid2" } 2179c3e59deSTodor Tomov }, 2189c3e59deSTodor Tomov 2199c3e59deSTodor Tomov /* CSID3 */ 2209c3e59deSTodor Tomov { 2210d814017SBryan O'Donoghue .regulators = { "vdda" }, 2229c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", 2239c3e59deSTodor Tomov "csi3", "csi3_phy", "csi3_pix", "csi3_rdi" }, 2249c3e59deSTodor Tomov .clock_rate = { { 0 }, 2259c3e59deSTodor Tomov { 0 }, 2269c3e59deSTodor Tomov { 0 }, 2279c3e59deSTodor Tomov { 0 }, 2289c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 2299c3e59deSTodor Tomov { 0 }, 2309c3e59deSTodor Tomov { 0 }, 2319c3e59deSTodor Tomov { 0 } }, 2329c3e59deSTodor Tomov .reg = { "csid3" }, 2339c3e59deSTodor Tomov .interrupt = { "csid3" } 2349c3e59deSTodor Tomov } 2359c3e59deSTodor Tomov }; 2369c3e59deSTodor Tomov 2379c3e59deSTodor Tomov static const struct resources_ispif ispif_res_8x96 = { 2389c3e59deSTodor Tomov /* ISPIF */ 2399c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "ispif_ahb", 2409c3e59deSTodor Tomov "csi0", "csi0_pix", "csi0_rdi", 2419c3e59deSTodor Tomov "csi1", "csi1_pix", "csi1_rdi", 2429c3e59deSTodor Tomov "csi2", "csi2_pix", "csi2_rdi", 2439c3e59deSTodor Tomov "csi3", "csi3_pix", "csi3_rdi" }, 2449c3e59deSTodor Tomov .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, 2459c3e59deSTodor Tomov .reg = { "ispif", "csi_clk_mux" }, 2469c3e59deSTodor Tomov .interrupt = "ispif" 2479c3e59deSTodor Tomov }; 2489c3e59deSTodor Tomov 2499c3e59deSTodor Tomov static const struct resources vfe_res_8x96[] = { 2509c3e59deSTodor Tomov /* VFE0 */ 2519c3e59deSTodor Tomov { 25281bdfa4fSBryan O'Donoghue .regulators = {}, 2539c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "vfe0", "csi_vfe0", "vfe_ahb", 2549c3e59deSTodor Tomov "vfe0_ahb", "vfe_axi", "vfe0_stream"}, 2559c3e59deSTodor Tomov .clock_rate = { { 0 }, 2569c3e59deSTodor Tomov { 0 }, 2579c3e59deSTodor Tomov { 75000000, 100000000, 300000000, 2589c3e59deSTodor Tomov 320000000, 480000000, 600000000 }, 2599c3e59deSTodor Tomov { 0 }, 2609c3e59deSTodor Tomov { 0 }, 2619c3e59deSTodor Tomov { 0 }, 2629c3e59deSTodor Tomov { 0 }, 2639c3e59deSTodor Tomov { 0 } }, 2649c3e59deSTodor Tomov .reg = { "vfe0" }, 2659c3e59deSTodor Tomov .interrupt = { "vfe0" } 2669c3e59deSTodor Tomov }, 2679c3e59deSTodor Tomov 2689c3e59deSTodor Tomov /* VFE1 */ 2699c3e59deSTodor Tomov { 27081bdfa4fSBryan O'Donoghue .regulators = {}, 2719c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "vfe1", "csi_vfe1", "vfe_ahb", 2729c3e59deSTodor Tomov "vfe1_ahb", "vfe_axi", "vfe1_stream"}, 2739c3e59deSTodor Tomov .clock_rate = { { 0 }, 2749c3e59deSTodor Tomov { 0 }, 2759c3e59deSTodor Tomov { 75000000, 100000000, 300000000, 2769c3e59deSTodor Tomov 320000000, 480000000, 600000000 }, 2779c3e59deSTodor Tomov { 0 }, 2789c3e59deSTodor Tomov { 0 }, 2799c3e59deSTodor Tomov { 0 }, 2809c3e59deSTodor Tomov { 0 }, 2819c3e59deSTodor Tomov { 0 } }, 2829c3e59deSTodor Tomov .reg = { "vfe1" }, 2839c3e59deSTodor Tomov .interrupt = { "vfe1" } 2849c3e59deSTodor Tomov } 285ec6859b2STodor Tomov }; 286ec6859b2STodor Tomov 2879e5d1581SAngeloGioacchino Del Regno static const struct resources csiphy_res_660[] = { 2889e5d1581SAngeloGioacchino Del Regno /* CSIPHY0 */ 2899e5d1581SAngeloGioacchino Del Regno { 29081bdfa4fSBryan O'Donoghue .regulators = {}, 2919e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer", 2929e5d1581SAngeloGioacchino Del Regno "csi0_phy", "csiphy_ahb2crif" }, 2939e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 2949e5d1581SAngeloGioacchino Del Regno { 0 }, 2959e5d1581SAngeloGioacchino Del Regno { 0 }, 2969e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 2979e5d1581SAngeloGioacchino Del Regno { 0 } }, 2989e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy0", "csiphy0_clk_mux" }, 2999e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy0" } 3009e5d1581SAngeloGioacchino Del Regno }, 3019e5d1581SAngeloGioacchino Del Regno 3029e5d1581SAngeloGioacchino Del Regno /* CSIPHY1 */ 3039e5d1581SAngeloGioacchino Del Regno { 30481bdfa4fSBryan O'Donoghue .regulators = {}, 3059e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer", 3069e5d1581SAngeloGioacchino Del Regno "csi1_phy", "csiphy_ahb2crif" }, 3079e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3089e5d1581SAngeloGioacchino Del Regno { 0 }, 3099e5d1581SAngeloGioacchino Del Regno { 0 }, 3109e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 3119e5d1581SAngeloGioacchino Del Regno { 0 } }, 3129e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy1", "csiphy1_clk_mux" }, 3139e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy1" } 3149e5d1581SAngeloGioacchino Del Regno }, 3159e5d1581SAngeloGioacchino Del Regno 3169e5d1581SAngeloGioacchino Del Regno /* CSIPHY2 */ 3179e5d1581SAngeloGioacchino Del Regno { 31881bdfa4fSBryan O'Donoghue .regulators = {}, 3199e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer", 3209e5d1581SAngeloGioacchino Del Regno "csi2_phy", "csiphy_ahb2crif" }, 3219e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3229e5d1581SAngeloGioacchino Del Regno { 0 }, 3239e5d1581SAngeloGioacchino Del Regno { 0 }, 3249e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 3259e5d1581SAngeloGioacchino Del Regno { 0 } }, 3269e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy2", "csiphy2_clk_mux" }, 3279e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy2" } 3289e5d1581SAngeloGioacchino Del Regno } 3299e5d1581SAngeloGioacchino Del Regno }; 3309e5d1581SAngeloGioacchino Del Regno 3319e5d1581SAngeloGioacchino Del Regno static const struct resources csid_res_660[] = { 3329e5d1581SAngeloGioacchino Del Regno /* CSID0 */ 3339e5d1581SAngeloGioacchino Del Regno { 3340d814017SBryan O'Donoghue .regulators = { "vdda", "vdd_sec" }, 3359e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 3369e5d1581SAngeloGioacchino Del Regno "csi0", "csi0_phy", "csi0_pix", "csi0_rdi", 3379e5d1581SAngeloGioacchino Del Regno "cphy_csid0" }, 3389e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3399e5d1581SAngeloGioacchino Del Regno { 0 }, 3409e5d1581SAngeloGioacchino Del Regno { 0 }, 3419e5d1581SAngeloGioacchino Del Regno { 0 }, 3429e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3439e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3449e5d1581SAngeloGioacchino Del Regno { 0 }, 3459e5d1581SAngeloGioacchino Del Regno { 0 }, 3469e5d1581SAngeloGioacchino Del Regno { 0 }, 3479e5d1581SAngeloGioacchino Del Regno { 0 } }, 3489e5d1581SAngeloGioacchino Del Regno .reg = { "csid0" }, 3499e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid0" } 3509e5d1581SAngeloGioacchino Del Regno }, 3519e5d1581SAngeloGioacchino Del Regno 3529e5d1581SAngeloGioacchino Del Regno /* CSID1 */ 3539e5d1581SAngeloGioacchino Del Regno { 3540d814017SBryan O'Donoghue .regulators = { "vdda", "vdd_sec" }, 3559e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 3569e5d1581SAngeloGioacchino Del Regno "csi1", "csi1_phy", "csi1_pix", "csi1_rdi", 3579e5d1581SAngeloGioacchino Del Regno "cphy_csid1" }, 3589e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3599e5d1581SAngeloGioacchino Del Regno { 0 }, 3609e5d1581SAngeloGioacchino Del Regno { 0 }, 3619e5d1581SAngeloGioacchino Del Regno { 0 }, 3629e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3639e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3649e5d1581SAngeloGioacchino Del Regno { 0 }, 3659e5d1581SAngeloGioacchino Del Regno { 0 }, 3669e5d1581SAngeloGioacchino Del Regno { 0 }, 3679e5d1581SAngeloGioacchino Del Regno { 0 } }, 3689e5d1581SAngeloGioacchino Del Regno .reg = { "csid1" }, 3699e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid1" } 3709e5d1581SAngeloGioacchino Del Regno }, 3719e5d1581SAngeloGioacchino Del Regno 3729e5d1581SAngeloGioacchino Del Regno /* CSID2 */ 3739e5d1581SAngeloGioacchino Del Regno { 3740d814017SBryan O'Donoghue .regulators = { "vdda", "vdd_sec" }, 3759e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", 3769e5d1581SAngeloGioacchino Del Regno "csi2", "csi2_phy", "csi2_pix", "csi2_rdi", 3779e5d1581SAngeloGioacchino Del Regno "cphy_csid2" }, 3789e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3799e5d1581SAngeloGioacchino Del Regno { 0 }, 3809e5d1581SAngeloGioacchino Del Regno { 0 }, 3819e5d1581SAngeloGioacchino Del Regno { 0 }, 3829e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3839e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3849e5d1581SAngeloGioacchino Del Regno { 0 }, 3859e5d1581SAngeloGioacchino Del Regno { 0 }, 3869e5d1581SAngeloGioacchino Del Regno { 0 }, 3879e5d1581SAngeloGioacchino Del Regno { 0 } }, 3889e5d1581SAngeloGioacchino Del Regno .reg = { "csid2" }, 3899e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid2" } 3909e5d1581SAngeloGioacchino Del Regno }, 3919e5d1581SAngeloGioacchino Del Regno 3929e5d1581SAngeloGioacchino Del Regno /* CSID3 */ 3939e5d1581SAngeloGioacchino Del Regno { 3940d814017SBryan O'Donoghue .regulators = { "vdda", "vdd_sec" }, 3959e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", 3969e5d1581SAngeloGioacchino Del Regno "csi3", "csi3_phy", "csi3_pix", "csi3_rdi", 3979e5d1581SAngeloGioacchino Del Regno "cphy_csid3" }, 3989e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3999e5d1581SAngeloGioacchino Del Regno { 0 }, 4009e5d1581SAngeloGioacchino Del Regno { 0 }, 4019e5d1581SAngeloGioacchino Del Regno { 0 }, 4029e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 4039e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 4049e5d1581SAngeloGioacchino Del Regno { 0 }, 4059e5d1581SAngeloGioacchino Del Regno { 0 }, 4069e5d1581SAngeloGioacchino Del Regno { 0 }, 4079e5d1581SAngeloGioacchino Del Regno { 0 } }, 4089e5d1581SAngeloGioacchino Del Regno .reg = { "csid3" }, 4099e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid3" } 4109e5d1581SAngeloGioacchino Del Regno } 4119e5d1581SAngeloGioacchino Del Regno }; 4129e5d1581SAngeloGioacchino Del Regno 4139e5d1581SAngeloGioacchino Del Regno static const struct resources_ispif ispif_res_660 = { 4149e5d1581SAngeloGioacchino Del Regno /* ISPIF */ 4159e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ahb", "ispif_ahb", 4169e5d1581SAngeloGioacchino Del Regno "csi0", "csi0_pix", "csi0_rdi", 4179e5d1581SAngeloGioacchino Del Regno "csi1", "csi1_pix", "csi1_rdi", 4189e5d1581SAngeloGioacchino Del Regno "csi2", "csi2_pix", "csi2_rdi", 4199e5d1581SAngeloGioacchino Del Regno "csi3", "csi3_pix", "csi3_rdi" }, 4209e5d1581SAngeloGioacchino Del Regno .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, 4219e5d1581SAngeloGioacchino Del Regno .reg = { "ispif", "csi_clk_mux" }, 4229e5d1581SAngeloGioacchino Del Regno .interrupt = "ispif" 4239e5d1581SAngeloGioacchino Del Regno }; 4249e5d1581SAngeloGioacchino Del Regno 4259e5d1581SAngeloGioacchino Del Regno static const struct resources vfe_res_660[] = { 4269e5d1581SAngeloGioacchino Del Regno /* VFE0 */ 4279e5d1581SAngeloGioacchino Del Regno { 42881bdfa4fSBryan O'Donoghue .regulators = {}, 4299e5d1581SAngeloGioacchino Del Regno .clock = { "throttle_axi", "top_ahb", "ahb", "vfe0", 4309e5d1581SAngeloGioacchino Del Regno "csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi", 4319e5d1581SAngeloGioacchino Del Regno "vfe0_stream"}, 4329e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 4339e5d1581SAngeloGioacchino Del Regno { 0 }, 4349e5d1581SAngeloGioacchino Del Regno { 0 }, 4359e5d1581SAngeloGioacchino Del Regno { 120000000, 200000000, 256000000, 4369e5d1581SAngeloGioacchino Del Regno 300000000, 404000000, 480000000, 4379e5d1581SAngeloGioacchino Del Regno 540000000, 576000000 }, 4389e5d1581SAngeloGioacchino Del Regno { 0 }, 4399e5d1581SAngeloGioacchino Del Regno { 0 }, 4409e5d1581SAngeloGioacchino Del Regno { 0 }, 4419e5d1581SAngeloGioacchino Del Regno { 0 }, 4429e5d1581SAngeloGioacchino Del Regno { 0 } }, 4439e5d1581SAngeloGioacchino Del Regno .reg = { "vfe0" }, 4449e5d1581SAngeloGioacchino Del Regno .interrupt = { "vfe0" } 4459e5d1581SAngeloGioacchino Del Regno }, 4469e5d1581SAngeloGioacchino Del Regno 4479e5d1581SAngeloGioacchino Del Regno /* VFE1 */ 4489e5d1581SAngeloGioacchino Del Regno { 44981bdfa4fSBryan O'Donoghue .regulators = {}, 4509e5d1581SAngeloGioacchino Del Regno .clock = { "throttle_axi", "top_ahb", "ahb", "vfe1", 4519e5d1581SAngeloGioacchino Del Regno "csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi", 4529e5d1581SAngeloGioacchino Del Regno "vfe1_stream"}, 4539e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 4549e5d1581SAngeloGioacchino Del Regno { 0 }, 4559e5d1581SAngeloGioacchino Del Regno { 0 }, 4569e5d1581SAngeloGioacchino Del Regno { 120000000, 200000000, 256000000, 4579e5d1581SAngeloGioacchino Del Regno 300000000, 404000000, 480000000, 4589e5d1581SAngeloGioacchino Del Regno 540000000, 576000000 }, 4599e5d1581SAngeloGioacchino Del Regno { 0 }, 4609e5d1581SAngeloGioacchino Del Regno { 0 }, 4619e5d1581SAngeloGioacchino Del Regno { 0 }, 4629e5d1581SAngeloGioacchino Del Regno { 0 }, 4639e5d1581SAngeloGioacchino Del Regno { 0 } }, 4649e5d1581SAngeloGioacchino Del Regno .reg = { "vfe1" }, 4659e5d1581SAngeloGioacchino Del Regno .interrupt = { "vfe1" } 4669e5d1581SAngeloGioacchino Del Regno } 4679e5d1581SAngeloGioacchino Del Regno }; 4689e5d1581SAngeloGioacchino Del Regno 4692f8b6719SRobert Foss static const struct resources csiphy_res_845[] = { 4702f8b6719SRobert Foss /* CSIPHY0 */ 4712f8b6719SRobert Foss { 47281bdfa4fSBryan O'Donoghue .regulators = {}, 4732f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 4742f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy0", 4752f8b6719SRobert Foss "csiphy0_timer_src", "csiphy0_timer" }, 4762f8b6719SRobert Foss .clock_rate = { { 0 }, 4772f8b6719SRobert Foss { 0 }, 4782f8b6719SRobert Foss { 0 }, 4792f8b6719SRobert Foss { 0 }, 4802f8b6719SRobert Foss { 0 }, 4812f8b6719SRobert Foss { 0 }, 4822f8b6719SRobert Foss { 0 }, 4832f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 4842f8b6719SRobert Foss .reg = { "csiphy0" }, 4852f8b6719SRobert Foss .interrupt = { "csiphy0" } 4862f8b6719SRobert Foss }, 4872f8b6719SRobert Foss 4882f8b6719SRobert Foss /* CSIPHY1 */ 4892f8b6719SRobert Foss { 49081bdfa4fSBryan O'Donoghue .regulators = {}, 4912f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 4922f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy1", 4932f8b6719SRobert Foss "csiphy1_timer_src", "csiphy1_timer" }, 4942f8b6719SRobert Foss .clock_rate = { { 0 }, 4952f8b6719SRobert Foss { 0 }, 4962f8b6719SRobert Foss { 0 }, 4972f8b6719SRobert Foss { 0 }, 4982f8b6719SRobert Foss { 0 }, 4992f8b6719SRobert Foss { 0 }, 5002f8b6719SRobert Foss { 0 }, 5012f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5022f8b6719SRobert Foss .reg = { "csiphy1" }, 5032f8b6719SRobert Foss .interrupt = { "csiphy1" } 5042f8b6719SRobert Foss }, 5052f8b6719SRobert Foss 5062f8b6719SRobert Foss /* CSIPHY2 */ 5072f8b6719SRobert Foss { 50881bdfa4fSBryan O'Donoghue .regulators = {}, 5092f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 5102f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy2", 5112f8b6719SRobert Foss "csiphy2_timer_src", "csiphy2_timer" }, 5122f8b6719SRobert Foss .clock_rate = { { 0 }, 5132f8b6719SRobert Foss { 0 }, 5142f8b6719SRobert Foss { 0 }, 5152f8b6719SRobert Foss { 0 }, 5162f8b6719SRobert Foss { 0 }, 5172f8b6719SRobert Foss { 0 }, 5182f8b6719SRobert Foss { 0 }, 5192f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5202f8b6719SRobert Foss .reg = { "csiphy2" }, 5212f8b6719SRobert Foss .interrupt = { "csiphy2" } 5222f8b6719SRobert Foss }, 5232f8b6719SRobert Foss 5242f8b6719SRobert Foss /* CSIPHY3 */ 5252f8b6719SRobert Foss { 52681bdfa4fSBryan O'Donoghue .regulators = {}, 5272f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 5282f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy3", 5292f8b6719SRobert Foss "csiphy3_timer_src", "csiphy3_timer" }, 5302f8b6719SRobert Foss .clock_rate = { { 0 }, 5312f8b6719SRobert Foss { 0 }, 5322f8b6719SRobert Foss { 0 }, 5332f8b6719SRobert Foss { 0 }, 5342f8b6719SRobert Foss { 0 }, 5352f8b6719SRobert Foss { 0 }, 5362f8b6719SRobert Foss { 0 }, 5372f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5382f8b6719SRobert Foss .reg = { "csiphy3" }, 5392f8b6719SRobert Foss .interrupt = { "csiphy3" } 5402f8b6719SRobert Foss } 5412f8b6719SRobert Foss }; 5422f8b6719SRobert Foss 543eebe6d00SRobert Foss static const struct resources csid_res_845[] = { 544eebe6d00SRobert Foss /* CSID0 */ 545eebe6d00SRobert Foss { 5460c4d7fdaSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 547eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 548eebe6d00SRobert Foss "soc_ahb", "vfe0", "vfe0_src", 549eebe6d00SRobert Foss "vfe0_cphy_rx", "csi0", 550eebe6d00SRobert Foss "csi0_src" }, 551eebe6d00SRobert Foss .clock_rate = { { 0 }, 552eebe6d00SRobert Foss { 384000000 }, 553eebe6d00SRobert Foss { 80000000 }, 554eebe6d00SRobert Foss { 0 }, 555eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 556eebe6d00SRobert Foss { 320000000 }, 557eebe6d00SRobert Foss { 0 }, 558eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 559eebe6d00SRobert Foss { 384000000 } }, 560eebe6d00SRobert Foss .reg = { "csid0" }, 561eebe6d00SRobert Foss .interrupt = { "csid0" } 562eebe6d00SRobert Foss }, 563eebe6d00SRobert Foss 564eebe6d00SRobert Foss /* CSID1 */ 565eebe6d00SRobert Foss { 5660c4d7fdaSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 567eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 568eebe6d00SRobert Foss "soc_ahb", "vfe1", "vfe1_src", 569eebe6d00SRobert Foss "vfe1_cphy_rx", "csi1", 570eebe6d00SRobert Foss "csi1_src" }, 571eebe6d00SRobert Foss .clock_rate = { { 0 }, 572eebe6d00SRobert Foss { 384000000 }, 573eebe6d00SRobert Foss { 80000000 }, 574eebe6d00SRobert Foss { 0 }, 575eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 576eebe6d00SRobert Foss { 320000000 }, 577eebe6d00SRobert Foss { 0 }, 578eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 579eebe6d00SRobert Foss { 384000000 } }, 580eebe6d00SRobert Foss .reg = { "csid1" }, 581eebe6d00SRobert Foss .interrupt = { "csid1" } 582eebe6d00SRobert Foss }, 583eebe6d00SRobert Foss 584eebe6d00SRobert Foss /* CSID2 */ 585eebe6d00SRobert Foss { 5860c4d7fdaSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 587eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 588eebe6d00SRobert Foss "soc_ahb", "vfe_lite", "vfe_lite_src", 589eebe6d00SRobert Foss "vfe_lite_cphy_rx", "csi2", 590eebe6d00SRobert Foss "csi2_src" }, 591eebe6d00SRobert Foss .clock_rate = { { 0 }, 592eebe6d00SRobert Foss { 384000000 }, 593eebe6d00SRobert Foss { 80000000 }, 594eebe6d00SRobert Foss { 0 }, 595eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 596eebe6d00SRobert Foss { 320000000 }, 597eebe6d00SRobert Foss { 0 }, 598eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 599eebe6d00SRobert Foss { 384000000 } }, 600eebe6d00SRobert Foss .reg = { "csid2" }, 601eebe6d00SRobert Foss .interrupt = { "csid2" } 602eebe6d00SRobert Foss } 603eebe6d00SRobert Foss }; 604eebe6d00SRobert Foss 6057319cdf1SRobert Foss static const struct resources vfe_res_845[] = { 6067319cdf1SRobert Foss /* VFE0 */ 6077319cdf1SRobert Foss { 60881bdfa4fSBryan O'Donoghue .regulators = {}, 6097319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6107319cdf1SRobert Foss "soc_ahb", "vfe0", "vfe0_axi", 6117319cdf1SRobert Foss "vfe0_src", "csi0", 6127319cdf1SRobert Foss "csi0_src"}, 6137319cdf1SRobert Foss .clock_rate = { { 0 }, 6147319cdf1SRobert Foss { 0 }, 6157319cdf1SRobert Foss { 80000000 }, 6167319cdf1SRobert Foss { 0 }, 6177319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6187319cdf1SRobert Foss { 0 }, 6197319cdf1SRobert Foss { 320000000 }, 6207319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6217319cdf1SRobert Foss { 384000000 } }, 6227319cdf1SRobert Foss .reg = { "vfe0" }, 6237319cdf1SRobert Foss .interrupt = { "vfe0" } 6247319cdf1SRobert Foss }, 6257319cdf1SRobert Foss 6267319cdf1SRobert Foss /* VFE1 */ 6277319cdf1SRobert Foss { 62881bdfa4fSBryan O'Donoghue .regulators = {}, 6297319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6307319cdf1SRobert Foss "soc_ahb", "vfe1", "vfe1_axi", 6317319cdf1SRobert Foss "vfe1_src", "csi1", 6327319cdf1SRobert Foss "csi1_src"}, 6337319cdf1SRobert Foss .clock_rate = { { 0 }, 6347319cdf1SRobert Foss { 0 }, 6357319cdf1SRobert Foss { 80000000 }, 6367319cdf1SRobert Foss { 0 }, 6377319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6387319cdf1SRobert Foss { 0 }, 6397319cdf1SRobert Foss { 320000000 }, 6407319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6417319cdf1SRobert Foss { 384000000 } }, 6427319cdf1SRobert Foss .reg = { "vfe1" }, 6437319cdf1SRobert Foss .interrupt = { "vfe1" } 6447319cdf1SRobert Foss }, 6457319cdf1SRobert Foss 6467319cdf1SRobert Foss /* VFE-lite */ 6477319cdf1SRobert Foss { 64881bdfa4fSBryan O'Donoghue .regulators = {}, 6497319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6507319cdf1SRobert Foss "soc_ahb", "vfe_lite", 6517319cdf1SRobert Foss "vfe_lite_src", "csi2", 6527319cdf1SRobert Foss "csi2_src"}, 6537319cdf1SRobert Foss .clock_rate = { { 0 }, 6547319cdf1SRobert Foss { 0 }, 6557319cdf1SRobert Foss { 80000000 }, 6567319cdf1SRobert Foss { 0 }, 6577319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6587319cdf1SRobert Foss { 320000000 }, 6597319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6607319cdf1SRobert Foss { 384000000 } }, 6617319cdf1SRobert Foss .reg = { "vfe_lite" }, 6627319cdf1SRobert Foss .interrupt = { "vfe_lite" } 6637319cdf1SRobert Foss } 6647319cdf1SRobert Foss }; 6657319cdf1SRobert Foss 666b4436a18SJonathan Marek static const struct resources csiphy_res_8250[] = { 667b4436a18SJonathan Marek /* CSIPHY0 */ 668b4436a18SJonathan Marek { 66981bdfa4fSBryan O'Donoghue .regulators = {}, 670b4436a18SJonathan Marek .clock = { "csiphy0", "csiphy0_timer" }, 671b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 672b4436a18SJonathan Marek { 300000000 } }, 673b4436a18SJonathan Marek .reg = { "csiphy0" }, 674b4436a18SJonathan Marek .interrupt = { "csiphy0" } 675b4436a18SJonathan Marek }, 676b4436a18SJonathan Marek /* CSIPHY1 */ 677b4436a18SJonathan Marek { 67881bdfa4fSBryan O'Donoghue .regulators = {}, 679b4436a18SJonathan Marek .clock = { "csiphy1", "csiphy1_timer" }, 680b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 681b4436a18SJonathan Marek { 300000000 } }, 682b4436a18SJonathan Marek .reg = { "csiphy1" }, 683b4436a18SJonathan Marek .interrupt = { "csiphy1" } 684b4436a18SJonathan Marek }, 685b4436a18SJonathan Marek /* CSIPHY2 */ 686b4436a18SJonathan Marek { 68781bdfa4fSBryan O'Donoghue .regulators = {}, 688b4436a18SJonathan Marek .clock = { "csiphy2", "csiphy2_timer" }, 689b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 690b4436a18SJonathan Marek { 300000000 } }, 691b4436a18SJonathan Marek .reg = { "csiphy2" }, 692b4436a18SJonathan Marek .interrupt = { "csiphy2" } 693b4436a18SJonathan Marek }, 694b4436a18SJonathan Marek /* CSIPHY3 */ 695b4436a18SJonathan Marek { 69681bdfa4fSBryan O'Donoghue .regulators = {}, 697b4436a18SJonathan Marek .clock = { "csiphy3", "csiphy3_timer" }, 698b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 699b4436a18SJonathan Marek { 300000000 } }, 700b4436a18SJonathan Marek .reg = { "csiphy3" }, 701b4436a18SJonathan Marek .interrupt = { "csiphy3" } 702b4436a18SJonathan Marek }, 703b4436a18SJonathan Marek /* CSIPHY4 */ 704b4436a18SJonathan Marek { 70581bdfa4fSBryan O'Donoghue .regulators = {}, 706b4436a18SJonathan Marek .clock = { "csiphy4", "csiphy4_timer" }, 707b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 708b4436a18SJonathan Marek { 300000000 } }, 709b4436a18SJonathan Marek .reg = { "csiphy4" }, 710b4436a18SJonathan Marek .interrupt = { "csiphy4" } 711b4436a18SJonathan Marek }, 712b4436a18SJonathan Marek /* CSIPHY5 */ 713b4436a18SJonathan Marek { 71481bdfa4fSBryan O'Donoghue .regulators = {}, 715b4436a18SJonathan Marek .clock = { "csiphy5", "csiphy5_timer" }, 716b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 717b4436a18SJonathan Marek { 300000000 } }, 718b4436a18SJonathan Marek .reg = { "csiphy5" }, 719b4436a18SJonathan Marek .interrupt = { "csiphy5" } 720b4436a18SJonathan Marek } 721b4436a18SJonathan Marek }; 722b4436a18SJonathan Marek 723b4436a18SJonathan Marek static const struct resources csid_res_8250[] = { 724b4436a18SJonathan Marek /* CSID0 */ 725b4436a18SJonathan Marek { 726db95031dSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 727b4436a18SJonathan Marek .clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" }, 728b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 729b4436a18SJonathan Marek { 400000000 }, 730b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 731b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 732b4436a18SJonathan Marek { 0 } }, 733b4436a18SJonathan Marek .reg = { "csid0" }, 734b4436a18SJonathan Marek .interrupt = { "csid0" } 735b4436a18SJonathan Marek }, 736b4436a18SJonathan Marek /* CSID1 */ 737b4436a18SJonathan Marek { 738db95031dSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 739b4436a18SJonathan Marek .clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" }, 740b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 741b4436a18SJonathan Marek { 400000000 }, 742b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 743b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 744b4436a18SJonathan Marek { 0 } }, 745b4436a18SJonathan Marek .reg = { "csid1" }, 746b4436a18SJonathan Marek .interrupt = { "csid1" } 747b4436a18SJonathan Marek }, 748b4436a18SJonathan Marek /* CSID2 */ 749b4436a18SJonathan Marek { 750db95031dSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 751b4436a18SJonathan Marek .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, 752b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 753b4436a18SJonathan Marek { 400000000 }, 754b4436a18SJonathan Marek { 400000000, 480000000 }, 755b4436a18SJonathan Marek { 0 } }, 756b4436a18SJonathan Marek .reg = { "csid2" }, 757b4436a18SJonathan Marek .interrupt = { "csid2" } 758b4436a18SJonathan Marek }, 759b4436a18SJonathan Marek /* CSID3 */ 760b4436a18SJonathan Marek { 761db95031dSBryan O'Donoghue .regulators = { "vdda-phy", "vdda-pll" }, 762b4436a18SJonathan Marek .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, 763b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 764b4436a18SJonathan Marek { 400000000 }, 765b4436a18SJonathan Marek { 400000000, 480000000 }, 766b4436a18SJonathan Marek { 0 } }, 767b4436a18SJonathan Marek .reg = { "csid3" }, 768b4436a18SJonathan Marek .interrupt = { "csid3" } 769b4436a18SJonathan Marek } 770b4436a18SJonathan Marek }; 771b4436a18SJonathan Marek 772b4436a18SJonathan Marek static const struct resources vfe_res_8250[] = { 773b4436a18SJonathan Marek /* VFE0 */ 774b4436a18SJonathan Marek { 77581bdfa4fSBryan O'Donoghue .regulators = {}, 776b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 777b4436a18SJonathan Marek "camnoc_axi", "vfe0_ahb", "vfe0_areg", "vfe0", 778b4436a18SJonathan Marek "vfe0_axi", "cam_hf_axi" }, 779b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 780b4436a18SJonathan Marek { 19200000, 80000000 }, 781b4436a18SJonathan Marek { 19200000 }, 782b4436a18SJonathan Marek { 0 }, 783b4436a18SJonathan Marek { 0 }, 784b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 785b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 786b4436a18SJonathan Marek { 0 }, 787b4436a18SJonathan Marek { 0 } }, 788b4436a18SJonathan Marek .reg = { "vfe0" }, 789b4436a18SJonathan Marek .interrupt = { "vfe0" } 790b4436a18SJonathan Marek }, 791b4436a18SJonathan Marek /* VFE1 */ 792b4436a18SJonathan Marek { 79381bdfa4fSBryan O'Donoghue .regulators = {}, 794b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 795b4436a18SJonathan Marek "camnoc_axi", "vfe1_ahb", "vfe1_areg", "vfe1", 796b4436a18SJonathan Marek "vfe1_axi", "cam_hf_axi" }, 797b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 798b4436a18SJonathan Marek { 19200000, 80000000 }, 799b4436a18SJonathan Marek { 19200000 }, 800b4436a18SJonathan Marek { 0 }, 801b4436a18SJonathan Marek { 0 }, 802b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 803b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 804b4436a18SJonathan Marek { 0 }, 805b4436a18SJonathan Marek { 0 } }, 806b4436a18SJonathan Marek .reg = { "vfe1" }, 807b4436a18SJonathan Marek .interrupt = { "vfe1" } 808b4436a18SJonathan Marek }, 809b4436a18SJonathan Marek /* VFE2 (lite) */ 810b4436a18SJonathan Marek { 81181bdfa4fSBryan O'Donoghue .regulators = {}, 812b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 813b4436a18SJonathan Marek "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi", 814b4436a18SJonathan Marek "vfe_lite", "cam_hf_axi" }, 815b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 816b4436a18SJonathan Marek { 19200000, 80000000 }, 817b4436a18SJonathan Marek { 19200000 }, 818b4436a18SJonathan Marek { 0 }, 819b4436a18SJonathan Marek { 0 }, 820b4436a18SJonathan Marek { 0 }, 821b4436a18SJonathan Marek { 400000000, 480000000 }, 822b4436a18SJonathan Marek { 0 } }, 823b4436a18SJonathan Marek .reg = { "vfe_lite0" }, 824b4436a18SJonathan Marek .interrupt = { "vfe_lite0" } 825b4436a18SJonathan Marek }, 826b4436a18SJonathan Marek /* VFE3 (lite) */ 827b4436a18SJonathan Marek { 82881bdfa4fSBryan O'Donoghue .regulators = {}, 829b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 830b4436a18SJonathan Marek "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi", 831b4436a18SJonathan Marek "vfe_lite", "cam_hf_axi" }, 832b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 833b4436a18SJonathan Marek { 19200000, 80000000 }, 834b4436a18SJonathan Marek { 19200000 }, 835b4436a18SJonathan Marek { 0 }, 836b4436a18SJonathan Marek { 0 }, 837b4436a18SJonathan Marek { 0 }, 838b4436a18SJonathan Marek { 400000000, 480000000 }, 839b4436a18SJonathan Marek { 0 } }, 840b4436a18SJonathan Marek .reg = { "vfe_lite1" }, 841b4436a18SJonathan Marek .interrupt = { "vfe_lite1" } 842b4436a18SJonathan Marek }, 843b4436a18SJonathan Marek }; 844b4436a18SJonathan Marek 8455ba38efbSBryan O'Donoghue static const struct resources_icc icc_res_sm8250[] = { 8465ba38efbSBryan O'Donoghue { 8475ba38efbSBryan O'Donoghue .name = "cam_ahb", 8485ba38efbSBryan O'Donoghue .icc_bw_tbl.avg = 38400, 8495ba38efbSBryan O'Donoghue .icc_bw_tbl.peak = 76800, 8505ba38efbSBryan O'Donoghue }, 8515ba38efbSBryan O'Donoghue { 8525ba38efbSBryan O'Donoghue .name = "cam_hf_0_mnoc", 8535ba38efbSBryan O'Donoghue .icc_bw_tbl.avg = 2097152, 8545ba38efbSBryan O'Donoghue .icc_bw_tbl.peak = 2097152, 8555ba38efbSBryan O'Donoghue }, 8565ba38efbSBryan O'Donoghue { 8575ba38efbSBryan O'Donoghue .name = "cam_sf_0_mnoc", 8585ba38efbSBryan O'Donoghue .icc_bw_tbl.avg = 0, 8595ba38efbSBryan O'Donoghue .icc_bw_tbl.peak = 2097152, 8605ba38efbSBryan O'Donoghue }, 8615ba38efbSBryan O'Donoghue { 8625ba38efbSBryan O'Donoghue .name = "cam_sf_icp_mnoc", 8635ba38efbSBryan O'Donoghue .icc_bw_tbl.avg = 2097152, 8645ba38efbSBryan O'Donoghue .icc_bw_tbl.peak = 2097152, 8655ba38efbSBryan O'Donoghue }, 8665ba38efbSBryan O'Donoghue }; 8675ba38efbSBryan O'Donoghue 868ec6859b2STodor Tomov /* 869ec6859b2STodor Tomov * camss_add_clock_margin - Add margin to clock frequency rate 870ec6859b2STodor Tomov * @rate: Clock frequency rate 871ec6859b2STodor Tomov * 872ec6859b2STodor Tomov * When making calculations with physical clock frequency values 873ec6859b2STodor Tomov * some safety margin must be added. Add it. 874ec6859b2STodor Tomov */ 875ec6859b2STodor Tomov inline void camss_add_clock_margin(u64 *rate) 876ec6859b2STodor Tomov { 877ec6859b2STodor Tomov *rate *= CAMSS_CLOCK_MARGIN_NUMERATOR; 878ec6859b2STodor Tomov *rate = div_u64(*rate, CAMSS_CLOCK_MARGIN_DENOMINATOR); 879ec6859b2STodor Tomov } 880ec6859b2STodor Tomov 881ec6859b2STodor Tomov /* 882ec6859b2STodor Tomov * camss_enable_clocks - Enable multiple clocks 883ec6859b2STodor Tomov * @nclocks: Number of clocks in clock array 884ec6859b2STodor Tomov * @clock: Clock array 885ec6859b2STodor Tomov * @dev: Device 886ec6859b2STodor Tomov * 887ec6859b2STodor Tomov * Return 0 on success or a negative error code otherwise 888ec6859b2STodor Tomov */ 889ec6859b2STodor Tomov int camss_enable_clocks(int nclocks, struct camss_clock *clock, 890ec6859b2STodor Tomov struct device *dev) 891ec6859b2STodor Tomov { 892ec6859b2STodor Tomov int ret; 893ec6859b2STodor Tomov int i; 894ec6859b2STodor Tomov 895ec6859b2STodor Tomov for (i = 0; i < nclocks; i++) { 896ec6859b2STodor Tomov ret = clk_prepare_enable(clock[i].clk); 897ec6859b2STodor Tomov if (ret) { 898ec6859b2STodor Tomov dev_err(dev, "clock enable failed: %d\n", ret); 899ec6859b2STodor Tomov goto error; 900ec6859b2STodor Tomov } 901ec6859b2STodor Tomov } 902ec6859b2STodor Tomov 903ec6859b2STodor Tomov return 0; 904ec6859b2STodor Tomov 905ec6859b2STodor Tomov error: 906ec6859b2STodor Tomov for (i--; i >= 0; i--) 907ec6859b2STodor Tomov clk_disable_unprepare(clock[i].clk); 908ec6859b2STodor Tomov 909ec6859b2STodor Tomov return ret; 910ec6859b2STodor Tomov } 911ec6859b2STodor Tomov 912ec6859b2STodor Tomov /* 913ec6859b2STodor Tomov * camss_disable_clocks - Disable multiple clocks 914ec6859b2STodor Tomov * @nclocks: Number of clocks in clock array 915ec6859b2STodor Tomov * @clock: Clock array 916ec6859b2STodor Tomov */ 917ec6859b2STodor Tomov void camss_disable_clocks(int nclocks, struct camss_clock *clock) 918ec6859b2STodor Tomov { 919ec6859b2STodor Tomov int i; 920ec6859b2STodor Tomov 921ec6859b2STodor Tomov for (i = nclocks - 1; i >= 0; i--) 922ec6859b2STodor Tomov clk_disable_unprepare(clock[i].clk); 923ec6859b2STodor Tomov } 924ec6859b2STodor Tomov 925ec6859b2STodor Tomov /* 926ec6859b2STodor Tomov * camss_find_sensor - Find a linked media entity which represents a sensor 927ec6859b2STodor Tomov * @entity: Media entity to start searching from 928ec6859b2STodor Tomov * 929ec6859b2STodor Tomov * Return a pointer to sensor media entity or NULL if not found 930ec6859b2STodor Tomov */ 93125f5c34bSTodor Tomov struct media_entity *camss_find_sensor(struct media_entity *entity) 932ec6859b2STodor Tomov { 933ec6859b2STodor Tomov struct media_pad *pad; 934ec6859b2STodor Tomov 935ec6859b2STodor Tomov while (1) { 936ec6859b2STodor Tomov pad = &entity->pads[0]; 937ec6859b2STodor Tomov if (!(pad->flags & MEDIA_PAD_FL_SINK)) 938ec6859b2STodor Tomov return NULL; 939ec6859b2STodor Tomov 940b2e44430SLaurent Pinchart pad = media_pad_remote_pad_first(pad); 941ec6859b2STodor Tomov if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 942ec6859b2STodor Tomov return NULL; 943ec6859b2STodor Tomov 944ec6859b2STodor Tomov entity = pad->entity; 945ec6859b2STodor Tomov 946ec6859b2STodor Tomov if (entity->function == MEDIA_ENT_F_CAM_SENSOR) 947ec6859b2STodor Tomov return entity; 948ec6859b2STodor Tomov } 949ec6859b2STodor Tomov } 950ec6859b2STodor Tomov 95178c2cc28SAndrey Konovalov /** 95278c2cc28SAndrey Konovalov * camss_get_link_freq - Get link frequency from sensor 95378c2cc28SAndrey Konovalov * @entity: Media entity in the current pipeline 95478c2cc28SAndrey Konovalov * @bpp: Number of bits per pixel for the current format 95578c2cc28SAndrey Konovalov * @lanes: Number of lanes in the link to the sensor 95678c2cc28SAndrey Konovalov * 95778c2cc28SAndrey Konovalov * Return link frequency on success or a negative error code otherwise 95878c2cc28SAndrey Konovalov */ 95978c2cc28SAndrey Konovalov s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, 96078c2cc28SAndrey Konovalov unsigned int lanes) 96178c2cc28SAndrey Konovalov { 96278c2cc28SAndrey Konovalov struct media_entity *sensor; 96378c2cc28SAndrey Konovalov struct v4l2_subdev *subdev; 96478c2cc28SAndrey Konovalov 96578c2cc28SAndrey Konovalov sensor = camss_find_sensor(entity); 96678c2cc28SAndrey Konovalov if (!sensor) 96778c2cc28SAndrey Konovalov return -ENODEV; 96878c2cc28SAndrey Konovalov 96978c2cc28SAndrey Konovalov subdev = media_entity_to_v4l2_subdev(sensor); 97078c2cc28SAndrey Konovalov 97178c2cc28SAndrey Konovalov return v4l2_get_link_freq(subdev->ctrl_handler, bpp, 2 * lanes); 97278c2cc28SAndrey Konovalov } 97378c2cc28SAndrey Konovalov 974ec6859b2STodor Tomov /* 975ec6859b2STodor Tomov * camss_get_pixel_clock - Get pixel clock rate from sensor 976ec6859b2STodor Tomov * @entity: Media entity in the current pipeline 977ec6859b2STodor Tomov * @pixel_clock: Received pixel clock value 978ec6859b2STodor Tomov * 979ec6859b2STodor Tomov * Return 0 on success or a negative error code otherwise 980ec6859b2STodor Tomov */ 9812f908577SVladimir Lypak int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock) 982ec6859b2STodor Tomov { 983ec6859b2STodor Tomov struct media_entity *sensor; 984ec6859b2STodor Tomov struct v4l2_subdev *subdev; 985ec6859b2STodor Tomov struct v4l2_ctrl *ctrl; 986ec6859b2STodor Tomov 987ec6859b2STodor Tomov sensor = camss_find_sensor(entity); 988ec6859b2STodor Tomov if (!sensor) 989ec6859b2STodor Tomov return -ENODEV; 990ec6859b2STodor Tomov 991ec6859b2STodor Tomov subdev = media_entity_to_v4l2_subdev(sensor); 992ec6859b2STodor Tomov 993ec6859b2STodor Tomov ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); 994ec6859b2STodor Tomov 995ec6859b2STodor Tomov if (!ctrl) 996ec6859b2STodor Tomov return -EINVAL; 997ec6859b2STodor Tomov 998ec6859b2STodor Tomov *pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); 999ec6859b2STodor Tomov 1000ec6859b2STodor Tomov return 0; 1001ec6859b2STodor Tomov } 1002ec6859b2STodor Tomov 100302afa816STodor Tomov int camss_pm_domain_on(struct camss *camss, int id) 100402afa816STodor Tomov { 10052f6f8af6SRobert Foss int ret = 0; 100602afa816STodor Tomov 10072f6f8af6SRobert Foss if (id < camss->vfe_num) { 10082f6f8af6SRobert Foss struct vfe_device *vfe = &camss->vfe[id]; 10092f6f8af6SRobert Foss 10102f6f8af6SRobert Foss ret = vfe->ops->pm_domain_on(vfe); 101102afa816STodor Tomov } 101202afa816STodor Tomov 10132f6f8af6SRobert Foss return ret; 101402afa816STodor Tomov } 101502afa816STodor Tomov 101602afa816STodor Tomov void camss_pm_domain_off(struct camss *camss, int id) 101702afa816STodor Tomov { 10182f6f8af6SRobert Foss if (id < camss->vfe_num) { 10192f6f8af6SRobert Foss struct vfe_device *vfe = &camss->vfe[id]; 10202f6f8af6SRobert Foss 10212f6f8af6SRobert Foss vfe->ops->pm_domain_off(vfe); 10222f6f8af6SRobert Foss } 102302afa816STodor Tomov } 102402afa816STodor Tomov 1025ec6859b2STodor Tomov /* 1026ec6859b2STodor Tomov * camss_of_parse_endpoint_node - Parse port endpoint node 1027ec6859b2STodor Tomov * @dev: Device 1028ec6859b2STodor Tomov * @node: Device node to be parsed 1029ec6859b2STodor Tomov * @csd: Parsed data from port endpoint node 1030ec6859b2STodor Tomov * 1031ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1032ec6859b2STodor Tomov */ 1033ec6859b2STodor Tomov static int camss_of_parse_endpoint_node(struct device *dev, 1034ec6859b2STodor Tomov struct device_node *node, 1035ec6859b2STodor Tomov struct camss_async_subdev *csd) 1036ec6859b2STodor Tomov { 1037ec6859b2STodor Tomov struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; 103894d964e5SLaurent Pinchart struct v4l2_mbus_config_mipi_csi2 *mipi_csi2; 1039ec6859b2STodor Tomov struct v4l2_fwnode_endpoint vep = { { 0 } }; 1040ec6859b2STodor Tomov unsigned int i; 1041ec6859b2STodor Tomov 1042ec6859b2STodor Tomov v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); 1043ec6859b2STodor Tomov 1044ec6859b2STodor Tomov csd->interface.csiphy_id = vep.base.port; 1045ec6859b2STodor Tomov 1046ec6859b2STodor Tomov mipi_csi2 = &vep.bus.mipi_csi2; 1047ec6859b2STodor Tomov lncfg->clk.pos = mipi_csi2->clock_lane; 1048ec6859b2STodor Tomov lncfg->clk.pol = mipi_csi2->lane_polarities[0]; 1049ec6859b2STodor Tomov lncfg->num_data = mipi_csi2->num_data_lanes; 1050ec6859b2STodor Tomov 1051ec6859b2STodor Tomov lncfg->data = devm_kcalloc(dev, 1052ec6859b2STodor Tomov lncfg->num_data, sizeof(*lncfg->data), 1053ec6859b2STodor Tomov GFP_KERNEL); 1054ec6859b2STodor Tomov if (!lncfg->data) 1055ec6859b2STodor Tomov return -ENOMEM; 1056ec6859b2STodor Tomov 1057ec6859b2STodor Tomov for (i = 0; i < lncfg->num_data; i++) { 1058ec6859b2STodor Tomov lncfg->data[i].pos = mipi_csi2->data_lanes[i]; 1059ec6859b2STodor Tomov lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1]; 1060ec6859b2STodor Tomov } 1061ec6859b2STodor Tomov 1062ec6859b2STodor Tomov return 0; 1063ec6859b2STodor Tomov } 1064ec6859b2STodor Tomov 1065ec6859b2STodor Tomov /* 1066ec6859b2STodor Tomov * camss_of_parse_ports - Parse ports node 1067ec6859b2STodor Tomov * @dev: Device 1068ec6859b2STodor Tomov * @notifier: v4l2_device notifier data 1069ec6859b2STodor Tomov * 1070ec6859b2STodor Tomov * Return number of "port" nodes found in "ports" node 1071ec6859b2STodor Tomov */ 1072d079f94cSSteve Longerbeam static int camss_of_parse_ports(struct camss *camss) 1073ec6859b2STodor Tomov { 1074d079f94cSSteve Longerbeam struct device *dev = camss->dev; 1075ec6859b2STodor Tomov struct device_node *node = NULL; 1076ec6859b2STodor Tomov struct device_node *remote = NULL; 1077d079f94cSSteve Longerbeam int ret, num_subdevs = 0; 1078ec6859b2STodor Tomov 1079d079f94cSSteve Longerbeam for_each_endpoint_of_node(dev->of_node, node) { 1080ec6859b2STodor Tomov struct camss_async_subdev *csd; 1081ec6859b2STodor Tomov 1082ec6859b2STodor Tomov if (!of_device_is_available(node)) 1083ec6859b2STodor Tomov continue; 1084ec6859b2STodor Tomov 1085ec6859b2STodor Tomov remote = of_graph_get_remote_port_parent(node); 1086ec6859b2STodor Tomov if (!remote) { 1087ec6859b2STodor Tomov dev_err(dev, "Cannot get remote parent\n"); 1088d079f94cSSteve Longerbeam ret = -EINVAL; 1089d079f94cSSteve Longerbeam goto err_cleanup; 1090ec6859b2STodor Tomov } 1091ec6859b2STodor Tomov 10923c8c1539SSakari Ailus csd = v4l2_async_nf_add_fwnode(&camss->notifier, 10933c8c1539SSakari Ailus of_fwnode_handle(remote), 1094b01edcbdSLaurent Pinchart struct camss_async_subdev); 1095016413d9SSakari Ailus of_node_put(remote); 1096b01edcbdSLaurent Pinchart if (IS_ERR(csd)) { 1097b01edcbdSLaurent Pinchart ret = PTR_ERR(csd); 1098d079f94cSSteve Longerbeam goto err_cleanup; 1099ec6859b2STodor Tomov } 1100ec6859b2STodor Tomov 1101d079f94cSSteve Longerbeam ret = camss_of_parse_endpoint_node(dev, node, csd); 1102d079f94cSSteve Longerbeam if (ret < 0) 1103d079f94cSSteve Longerbeam goto err_cleanup; 1104d079f94cSSteve Longerbeam 1105d079f94cSSteve Longerbeam num_subdevs++; 1106d079f94cSSteve Longerbeam } 1107d079f94cSSteve Longerbeam 1108d079f94cSSteve Longerbeam return num_subdevs; 1109d079f94cSSteve Longerbeam 1110d079f94cSSteve Longerbeam err_cleanup: 1111d079f94cSSteve Longerbeam of_node_put(node); 1112d079f94cSSteve Longerbeam return ret; 1113ec6859b2STodor Tomov } 1114ec6859b2STodor Tomov 1115ec6859b2STodor Tomov /* 1116ec6859b2STodor Tomov * camss_init_subdevices - Initialize subdev structures and resources 1117ec6859b2STodor Tomov * @camss: CAMSS device 1118ec6859b2STodor Tomov * 1119ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1120ec6859b2STodor Tomov */ 1121ec6859b2STodor Tomov static int camss_init_subdevices(struct camss *camss) 1122ec6859b2STodor Tomov { 11239c3e59deSTodor Tomov const struct resources *csiphy_res; 11249c3e59deSTodor Tomov const struct resources *csid_res; 11259c3e59deSTodor Tomov const struct resources_ispif *ispif_res; 11269c3e59deSTodor Tomov const struct resources *vfe_res; 1127ec6859b2STodor Tomov unsigned int i; 1128ec6859b2STodor Tomov int ret; 1129ec6859b2STodor Tomov 11309c3e59deSTodor Tomov if (camss->version == CAMSS_8x16) { 11319c3e59deSTodor Tomov csiphy_res = csiphy_res_8x16; 11329c3e59deSTodor Tomov csid_res = csid_res_8x16; 11339c3e59deSTodor Tomov ispif_res = &ispif_res_8x16; 11349c3e59deSTodor Tomov vfe_res = vfe_res_8x16; 11359c3e59deSTodor Tomov } else if (camss->version == CAMSS_8x96) { 11369c3e59deSTodor Tomov csiphy_res = csiphy_res_8x96; 11379c3e59deSTodor Tomov csid_res = csid_res_8x96; 11389c3e59deSTodor Tomov ispif_res = &ispif_res_8x96; 11399c3e59deSTodor Tomov vfe_res = vfe_res_8x96; 11409e5d1581SAngeloGioacchino Del Regno } else if (camss->version == CAMSS_660) { 11419e5d1581SAngeloGioacchino Del Regno csiphy_res = csiphy_res_660; 11429e5d1581SAngeloGioacchino Del Regno csid_res = csid_res_660; 11439e5d1581SAngeloGioacchino Del Regno ispif_res = &ispif_res_660; 11449e5d1581SAngeloGioacchino Del Regno vfe_res = vfe_res_660; 114570524567SRobert Foss } else if (camss->version == CAMSS_845) { 114670524567SRobert Foss csiphy_res = csiphy_res_845; 114770524567SRobert Foss csid_res = csid_res_845; 114870524567SRobert Foss /* Titan VFEs don't have an ISPIF */ 114970524567SRobert Foss ispif_res = NULL; 115070524567SRobert Foss vfe_res = vfe_res_845; 1151b4436a18SJonathan Marek } else if (camss->version == CAMSS_8250) { 1152b4436a18SJonathan Marek csiphy_res = csiphy_res_8250; 1153b4436a18SJonathan Marek csid_res = csid_res_8250; 1154b4436a18SJonathan Marek /* Titan VFEs don't have an ISPIF */ 1155b4436a18SJonathan Marek ispif_res = NULL; 1156b4436a18SJonathan Marek vfe_res = vfe_res_8250; 11579c3e59deSTodor Tomov } else { 11589c3e59deSTodor Tomov return -EINVAL; 11599c3e59deSTodor Tomov } 11609c3e59deSTodor Tomov 11619c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 11629c3e59deSTodor Tomov ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], 1163ec6859b2STodor Tomov &csiphy_res[i], i); 1164ec6859b2STodor Tomov if (ret < 0) { 1165ec6859b2STodor Tomov dev_err(camss->dev, 1166ec6859b2STodor Tomov "Failed to init csiphy%d sub-device: %d\n", 1167ec6859b2STodor Tomov i, ret); 1168ec6859b2STodor Tomov return ret; 1169ec6859b2STodor Tomov } 1170ec6859b2STodor Tomov } 1171ec6859b2STodor Tomov 1172b4436a18SJonathan Marek /* note: SM8250 requires VFE to be initialized before CSID */ 1173be11096dSVladimir Zapolskiy for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { 1174b4436a18SJonathan Marek ret = msm_vfe_subdev_init(camss, &camss->vfe[i], 1175b4436a18SJonathan Marek &vfe_res[i], i); 1176b4436a18SJonathan Marek if (ret < 0) { 1177b4436a18SJonathan Marek dev_err(camss->dev, 1178b4436a18SJonathan Marek "Fail to init vfe%d sub-device: %d\n", i, ret); 1179b4436a18SJonathan Marek return ret; 1180b4436a18SJonathan Marek } 1181b4436a18SJonathan Marek } 1182b4436a18SJonathan Marek 11839c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 11849c3e59deSTodor Tomov ret = msm_csid_subdev_init(camss, &camss->csid[i], 1185ec6859b2STodor Tomov &csid_res[i], i); 1186ec6859b2STodor Tomov if (ret < 0) { 1187ec6859b2STodor Tomov dev_err(camss->dev, 1188ec6859b2STodor Tomov "Failed to init csid%d sub-device: %d\n", 1189ec6859b2STodor Tomov i, ret); 1190ec6859b2STodor Tomov return ret; 1191ec6859b2STodor Tomov } 1192ec6859b2STodor Tomov } 1193ec6859b2STodor Tomov 11949d95baf9SRobert Foss ret = msm_ispif_subdev_init(camss, ispif_res); 1195ec6859b2STodor Tomov if (ret < 0) { 1196ec6859b2STodor Tomov dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", 1197ec6859b2STodor Tomov ret); 1198ec6859b2STodor Tomov return ret; 1199ec6859b2STodor Tomov } 1200ec6859b2STodor Tomov 1201ec6859b2STodor Tomov return 0; 1202ec6859b2STodor Tomov } 1203ec6859b2STodor Tomov 1204ec6859b2STodor Tomov /* 1205ec6859b2STodor Tomov * camss_register_entities - Register subdev nodes and create links 1206ec6859b2STodor Tomov * @camss: CAMSS device 1207ec6859b2STodor Tomov * 1208ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1209ec6859b2STodor Tomov */ 1210ec6859b2STodor Tomov static int camss_register_entities(struct camss *camss) 1211ec6859b2STodor Tomov { 12129c3e59deSTodor Tomov int i, j, k; 1213ec6859b2STodor Tomov int ret; 1214ec6859b2STodor Tomov 12159c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 1216ec6859b2STodor Tomov ret = msm_csiphy_register_entity(&camss->csiphy[i], 1217ec6859b2STodor Tomov &camss->v4l2_dev); 1218ec6859b2STodor Tomov if (ret < 0) { 1219ec6859b2STodor Tomov dev_err(camss->dev, 1220ec6859b2STodor Tomov "Failed to register csiphy%d entity: %d\n", 1221ec6859b2STodor Tomov i, ret); 1222ec6859b2STodor Tomov goto err_reg_csiphy; 1223ec6859b2STodor Tomov } 1224ec6859b2STodor Tomov } 1225ec6859b2STodor Tomov 12269c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 1227ec6859b2STodor Tomov ret = msm_csid_register_entity(&camss->csid[i], 1228ec6859b2STodor Tomov &camss->v4l2_dev); 1229ec6859b2STodor Tomov if (ret < 0) { 1230ec6859b2STodor Tomov dev_err(camss->dev, 1231ec6859b2STodor Tomov "Failed to register csid%d entity: %d\n", 1232ec6859b2STodor Tomov i, ret); 1233ec6859b2STodor Tomov goto err_reg_csid; 1234ec6859b2STodor Tomov } 1235ec6859b2STodor Tomov } 1236ec6859b2STodor Tomov 12379d95baf9SRobert Foss ret = msm_ispif_register_entities(camss->ispif, 12389d95baf9SRobert Foss &camss->v4l2_dev); 1239ec6859b2STodor Tomov if (ret < 0) { 1240ec6859b2STodor Tomov dev_err(camss->dev, "Failed to register ispif entities: %d\n", 1241ec6859b2STodor Tomov ret); 1242ec6859b2STodor Tomov goto err_reg_ispif; 1243ec6859b2STodor Tomov } 1244ec6859b2STodor Tomov 1245be11096dSVladimir Zapolskiy for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { 12469c3e59deSTodor Tomov ret = msm_vfe_register_entities(&camss->vfe[i], 12479c3e59deSTodor Tomov &camss->v4l2_dev); 1248ec6859b2STodor Tomov if (ret < 0) { 12499c3e59deSTodor Tomov dev_err(camss->dev, 12509c3e59deSTodor Tomov "Failed to register vfe%d entities: %d\n", 12519c3e59deSTodor Tomov i, ret); 1252ec6859b2STodor Tomov goto err_reg_vfe; 1253ec6859b2STodor Tomov } 12549c3e59deSTodor Tomov } 1255ec6859b2STodor Tomov 12569c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 12579c3e59deSTodor Tomov for (j = 0; j < camss->csid_num; j++) { 1258ec6859b2STodor Tomov ret = media_create_pad_link( 1259ec6859b2STodor Tomov &camss->csiphy[i].subdev.entity, 1260ec6859b2STodor Tomov MSM_CSIPHY_PAD_SRC, 1261ec6859b2STodor Tomov &camss->csid[j].subdev.entity, 1262ec6859b2STodor Tomov MSM_CSID_PAD_SINK, 1263ec6859b2STodor Tomov 0); 1264ec6859b2STodor Tomov if (ret < 0) { 1265ec6859b2STodor Tomov dev_err(camss->dev, 1266ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1267ec6859b2STodor Tomov camss->csiphy[i].subdev.entity.name, 1268ec6859b2STodor Tomov camss->csid[j].subdev.entity.name, 1269ec6859b2STodor Tomov ret); 1270ec6859b2STodor Tomov goto err_link; 1271ec6859b2STodor Tomov } 1272ec6859b2STodor Tomov } 1273ec6859b2STodor Tomov } 1274ec6859b2STodor Tomov 12759d95baf9SRobert Foss if (camss->ispif) { 12769c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 12779d95baf9SRobert Foss for (j = 0; j < camss->ispif->line_num; j++) { 1278ec6859b2STodor Tomov ret = media_create_pad_link( 1279ec6859b2STodor Tomov &camss->csid[i].subdev.entity, 1280ec6859b2STodor Tomov MSM_CSID_PAD_SRC, 12819d95baf9SRobert Foss &camss->ispif->line[j].subdev.entity, 1282ec6859b2STodor Tomov MSM_ISPIF_PAD_SINK, 1283ec6859b2STodor Tomov 0); 1284ec6859b2STodor Tomov if (ret < 0) { 1285ec6859b2STodor Tomov dev_err(camss->dev, 1286ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1287ec6859b2STodor Tomov camss->csid[i].subdev.entity.name, 12889d95baf9SRobert Foss camss->ispif->line[j].subdev.entity.name, 1289ec6859b2STodor Tomov ret); 1290ec6859b2STodor Tomov goto err_link; 1291ec6859b2STodor Tomov } 1292ec6859b2STodor Tomov } 1293ec6859b2STodor Tomov } 1294ec6859b2STodor Tomov 12959d95baf9SRobert Foss for (i = 0; i < camss->ispif->line_num; i++) 12969c3e59deSTodor Tomov for (k = 0; k < camss->vfe_num; k++) 1297633b388fSRobert Foss for (j = 0; j < camss->vfe[k].line_num; j++) { 12989d95baf9SRobert Foss struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev; 12999d95baf9SRobert Foss struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; 13009d95baf9SRobert Foss 13019d95baf9SRobert Foss ret = media_create_pad_link(&ispif->entity, 1302ec6859b2STodor Tomov MSM_ISPIF_PAD_SRC, 13039d95baf9SRobert Foss &vfe->entity, 1304ec6859b2STodor Tomov MSM_VFE_PAD_SINK, 1305ec6859b2STodor Tomov 0); 1306ec6859b2STodor Tomov if (ret < 0) { 1307ec6859b2STodor Tomov dev_err(camss->dev, 1308ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 13099d95baf9SRobert Foss ispif->entity.name, 13109d95baf9SRobert Foss vfe->entity.name, 1311ec6859b2STodor Tomov ret); 1312ec6859b2STodor Tomov goto err_link; 1313ec6859b2STodor Tomov } 1314ec6859b2STodor Tomov } 13159d95baf9SRobert Foss } else { 13169d95baf9SRobert Foss for (i = 0; i < camss->csid_num; i++) 1317be11096dSVladimir Zapolskiy for (k = 0; k < camss->vfe_num + camss->vfe_lite_num; k++) 1318633b388fSRobert Foss for (j = 0; j < camss->vfe[k].line_num; j++) { 13199d95baf9SRobert Foss struct v4l2_subdev *csid = &camss->csid[i].subdev; 13209d95baf9SRobert Foss struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; 13219d95baf9SRobert Foss 13229d95baf9SRobert Foss ret = media_create_pad_link(&csid->entity, 13238ce158c1SMilen Mitkov MSM_CSID_PAD_FIRST_SRC + j, 13249d95baf9SRobert Foss &vfe->entity, 13259d95baf9SRobert Foss MSM_VFE_PAD_SINK, 13269d95baf9SRobert Foss 0); 13279d95baf9SRobert Foss if (ret < 0) { 13289d95baf9SRobert Foss dev_err(camss->dev, 13299d95baf9SRobert Foss "Failed to link %s->%s entities: %d\n", 13309d95baf9SRobert Foss csid->entity.name, 13319d95baf9SRobert Foss vfe->entity.name, 13329d95baf9SRobert Foss ret); 13339d95baf9SRobert Foss goto err_link; 13349d95baf9SRobert Foss } 13359d95baf9SRobert Foss } 13369d95baf9SRobert Foss } 1337ec6859b2STodor Tomov 1338ec6859b2STodor Tomov return 0; 1339ec6859b2STodor Tomov 1340ec6859b2STodor Tomov err_link: 1341be11096dSVladimir Zapolskiy i = camss->vfe_num + camss->vfe_lite_num; 1342ec6859b2STodor Tomov err_reg_vfe: 13439c3e59deSTodor Tomov for (i--; i >= 0; i--) 13449c3e59deSTodor Tomov msm_vfe_unregister_entities(&camss->vfe[i]); 13459c3e59deSTodor Tomov 1346ec6859b2STodor Tomov err_reg_ispif: 13479d95baf9SRobert Foss msm_ispif_unregister_entities(camss->ispif); 1348ec6859b2STodor Tomov 13499c3e59deSTodor Tomov i = camss->csid_num; 1350ec6859b2STodor Tomov err_reg_csid: 1351ec6859b2STodor Tomov for (i--; i >= 0; i--) 1352ec6859b2STodor Tomov msm_csid_unregister_entity(&camss->csid[i]); 1353ec6859b2STodor Tomov 13549c3e59deSTodor Tomov i = camss->csiphy_num; 1355ec6859b2STodor Tomov err_reg_csiphy: 1356ec6859b2STodor Tomov for (i--; i >= 0; i--) 1357ec6859b2STodor Tomov msm_csiphy_unregister_entity(&camss->csiphy[i]); 1358ec6859b2STodor Tomov 1359ec6859b2STodor Tomov return ret; 1360ec6859b2STodor Tomov } 1361ec6859b2STodor Tomov 1362ec6859b2STodor Tomov /* 1363ec6859b2STodor Tomov * camss_unregister_entities - Unregister subdev nodes 1364ec6859b2STodor Tomov * @camss: CAMSS device 1365ec6859b2STodor Tomov * 1366ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1367ec6859b2STodor Tomov */ 1368ec6859b2STodor Tomov static void camss_unregister_entities(struct camss *camss) 1369ec6859b2STodor Tomov { 1370ec6859b2STodor Tomov unsigned int i; 1371ec6859b2STodor Tomov 13729c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) 1373ec6859b2STodor Tomov msm_csiphy_unregister_entity(&camss->csiphy[i]); 1374ec6859b2STodor Tomov 13759c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) 1376ec6859b2STodor Tomov msm_csid_unregister_entity(&camss->csid[i]); 1377ec6859b2STodor Tomov 13789d95baf9SRobert Foss msm_ispif_unregister_entities(camss->ispif); 13799c3e59deSTodor Tomov 1380be11096dSVladimir Zapolskiy for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) 13819c3e59deSTodor Tomov msm_vfe_unregister_entities(&camss->vfe[i]); 1382ec6859b2STodor Tomov } 1383ec6859b2STodor Tomov 1384ec6859b2STodor Tomov static int camss_subdev_notifier_bound(struct v4l2_async_notifier *async, 1385ec6859b2STodor Tomov struct v4l2_subdev *subdev, 1386*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 1387ec6859b2STodor Tomov { 1388ec6859b2STodor Tomov struct camss *camss = container_of(async, struct camss, notifier); 1389ec6859b2STodor Tomov struct camss_async_subdev *csd = 1390ec6859b2STodor Tomov container_of(asd, struct camss_async_subdev, asd); 1391ec6859b2STodor Tomov u8 id = csd->interface.csiphy_id; 1392ec6859b2STodor Tomov struct csiphy_device *csiphy = &camss->csiphy[id]; 1393ec6859b2STodor Tomov 1394ec6859b2STodor Tomov csiphy->cfg.csi2 = &csd->interface.csi2; 1395ec6859b2STodor Tomov subdev->host_priv = csiphy; 1396ec6859b2STodor Tomov 1397ec6859b2STodor Tomov return 0; 1398ec6859b2STodor Tomov } 1399ec6859b2STodor Tomov 1400ec6859b2STodor Tomov static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) 1401ec6859b2STodor Tomov { 1402ec6859b2STodor Tomov struct camss *camss = container_of(async, struct camss, notifier); 1403ec6859b2STodor Tomov struct v4l2_device *v4l2_dev = &camss->v4l2_dev; 1404ec6859b2STodor Tomov struct v4l2_subdev *sd; 1405ec6859b2STodor Tomov int ret; 1406ec6859b2STodor Tomov 1407ec6859b2STodor Tomov list_for_each_entry(sd, &v4l2_dev->subdevs, list) { 1408ec6859b2STodor Tomov if (sd->host_priv) { 1409ec6859b2STodor Tomov struct media_entity *sensor = &sd->entity; 1410ec6859b2STodor Tomov struct csiphy_device *csiphy = 1411ec6859b2STodor Tomov (struct csiphy_device *) sd->host_priv; 1412ec6859b2STodor Tomov struct media_entity *input = &csiphy->subdev.entity; 1413ec6859b2STodor Tomov unsigned int i; 1414ec6859b2STodor Tomov 1415ec6859b2STodor Tomov for (i = 0; i < sensor->num_pads; i++) { 1416ec6859b2STodor Tomov if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) 1417ec6859b2STodor Tomov break; 1418ec6859b2STodor Tomov } 1419ec6859b2STodor Tomov if (i == sensor->num_pads) { 1420ec6859b2STodor Tomov dev_err(camss->dev, 1421ec6859b2STodor Tomov "No source pad in external entity\n"); 1422ec6859b2STodor Tomov return -EINVAL; 1423ec6859b2STodor Tomov } 1424ec6859b2STodor Tomov 1425ec6859b2STodor Tomov ret = media_create_pad_link(sensor, i, 1426ec6859b2STodor Tomov input, MSM_CSIPHY_PAD_SINK, 1427ec6859b2STodor Tomov MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 1428ec6859b2STodor Tomov if (ret < 0) { 1429ec6859b2STodor Tomov dev_err(camss->dev, 1430ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1431ec6859b2STodor Tomov sensor->name, input->name, ret); 1432ec6859b2STodor Tomov return ret; 1433ec6859b2STodor Tomov } 1434ec6859b2STodor Tomov } 1435ec6859b2STodor Tomov } 1436ec6859b2STodor Tomov 1437ec6859b2STodor Tomov ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); 1438ec6859b2STodor Tomov if (ret < 0) 1439ec6859b2STodor Tomov return ret; 1440ec6859b2STodor Tomov 1441ec6859b2STodor Tomov return media_device_register(&camss->media_dev); 1442ec6859b2STodor Tomov } 1443ec6859b2STodor Tomov 1444ec6859b2STodor Tomov static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { 1445ec6859b2STodor Tomov .bound = camss_subdev_notifier_bound, 1446ec6859b2STodor Tomov .complete = camss_subdev_notifier_complete, 1447ec6859b2STodor Tomov }; 1448ec6859b2STodor Tomov 1449ec6859b2STodor Tomov static const struct media_device_ops camss_media_ops = { 1450ec6859b2STodor Tomov .link_notify = v4l2_pipeline_link_notify, 1451ec6859b2STodor Tomov }; 1452ec6859b2STodor Tomov 14532f6f8af6SRobert Foss static int camss_configure_pd(struct camss *camss) 14542f6f8af6SRobert Foss { 14556b1814e2SVladimir Zapolskiy struct device *dev = camss->dev; 14562f6f8af6SRobert Foss int i; 14572f6f8af6SRobert Foss int ret; 14582f6f8af6SRobert Foss 14596b1814e2SVladimir Zapolskiy camss->genpd_num = of_count_phandle_with_args(dev->of_node, 14606b1814e2SVladimir Zapolskiy "power-domains", 14616b1814e2SVladimir Zapolskiy "#power-domain-cells"); 14626b1814e2SVladimir Zapolskiy if (camss->genpd_num < 0) { 14636b1814e2SVladimir Zapolskiy dev_err(dev, "Power domains are not defined for camss\n"); 14646b1814e2SVladimir Zapolskiy return camss->genpd_num; 14656b1814e2SVladimir Zapolskiy } 14662f6f8af6SRobert Foss 14673d658980SVladimir Zapolskiy /* 14683d658980SVladimir Zapolskiy * If a platform device has just one power domain, then it is attached 14693d658980SVladimir Zapolskiy * at platform_probe() level, thus there shall be no need and even no 14703d658980SVladimir Zapolskiy * option to attach it again, this is the case for CAMSS on MSM8916. 14713d658980SVladimir Zapolskiy */ 14723d658980SVladimir Zapolskiy if (camss->genpd_num == 1) 14733d658980SVladimir Zapolskiy return 0; 14743d658980SVladimir Zapolskiy 14756b1814e2SVladimir Zapolskiy camss->genpd = devm_kmalloc_array(dev, camss->genpd_num, 14766b1814e2SVladimir Zapolskiy sizeof(*camss->genpd), GFP_KERNEL); 14776b1814e2SVladimir Zapolskiy if (!camss->genpd) 14786b1814e2SVladimir Zapolskiy return -ENOMEM; 14796b1814e2SVladimir Zapolskiy 14806b1814e2SVladimir Zapolskiy camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num, 14816b1814e2SVladimir Zapolskiy sizeof(*camss->genpd_link), 14826b1814e2SVladimir Zapolskiy GFP_KERNEL); 14836b1814e2SVladimir Zapolskiy if (!camss->genpd_link) 14846b1814e2SVladimir Zapolskiy return -ENOMEM; 14856b1814e2SVladimir Zapolskiy 148646cc0317SVladimir Zapolskiy /* 148746cc0317SVladimir Zapolskiy * VFE power domains are in the beginning of the list, and while all 148846cc0317SVladimir Zapolskiy * power domains should be attached, only if TITAN_TOP power domain is 148946cc0317SVladimir Zapolskiy * found in the list, it should be linked over here. 149046cc0317SVladimir Zapolskiy */ 14916b1814e2SVladimir Zapolskiy for (i = 0; i < camss->genpd_num; i++) { 14922f6f8af6SRobert Foss camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); 14932f6f8af6SRobert Foss if (IS_ERR(camss->genpd[i])) { 14942f6f8af6SRobert Foss ret = PTR_ERR(camss->genpd[i]); 14952f6f8af6SRobert Foss goto fail_pm; 14962f6f8af6SRobert Foss } 149746cc0317SVladimir Zapolskiy } 14982f6f8af6SRobert Foss 149946cc0317SVladimir Zapolskiy if (i > camss->vfe_num) { 150046cc0317SVladimir Zapolskiy camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], 15012f6f8af6SRobert Foss DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | 15022f6f8af6SRobert Foss DL_FLAG_RPM_ACTIVE); 150346cc0317SVladimir Zapolskiy if (!camss->genpd_link[i - 1]) { 15042f6f8af6SRobert Foss ret = -EINVAL; 15052f6f8af6SRobert Foss goto fail_pm; 15062f6f8af6SRobert Foss } 15072f6f8af6SRobert Foss } 15082f6f8af6SRobert Foss 15092f6f8af6SRobert Foss return 0; 15102f6f8af6SRobert Foss 15112f6f8af6SRobert Foss fail_pm: 151246cc0317SVladimir Zapolskiy for (--i ; i >= 0; i--) 15132f6f8af6SRobert Foss dev_pm_domain_detach(camss->genpd[i], true); 15142f6f8af6SRobert Foss 15152f6f8af6SRobert Foss return ret; 15162f6f8af6SRobert Foss } 15172f6f8af6SRobert Foss 15185ba38efbSBryan O'Donoghue static int camss_icc_get(struct camss *camss) 15195ba38efbSBryan O'Donoghue { 15205ba38efbSBryan O'Donoghue const struct resources_icc *icc_res; 15215ba38efbSBryan O'Donoghue int nbr_icc_paths = 0; 15225ba38efbSBryan O'Donoghue int i; 15235ba38efbSBryan O'Donoghue 15245ba38efbSBryan O'Donoghue if (camss->version == CAMSS_8250) { 15255ba38efbSBryan O'Donoghue icc_res = &icc_res_sm8250[0]; 15265ba38efbSBryan O'Donoghue nbr_icc_paths = ICC_SM8250_COUNT; 15275ba38efbSBryan O'Donoghue } 15285ba38efbSBryan O'Donoghue 15295ba38efbSBryan O'Donoghue for (i = 0; i < nbr_icc_paths; i++) { 15305ba38efbSBryan O'Donoghue camss->icc_path[i] = devm_of_icc_get(camss->dev, 15315ba38efbSBryan O'Donoghue icc_res[i].name); 15325ba38efbSBryan O'Donoghue if (IS_ERR(camss->icc_path[i])) 15335ba38efbSBryan O'Donoghue return PTR_ERR(camss->icc_path[i]); 15345ba38efbSBryan O'Donoghue 15355ba38efbSBryan O'Donoghue camss->icc_bw_tbl[i] = icc_res[i].icc_bw_tbl; 15365ba38efbSBryan O'Donoghue } 15375ba38efbSBryan O'Donoghue 15385ba38efbSBryan O'Donoghue return 0; 15395ba38efbSBryan O'Donoghue } 15405ba38efbSBryan O'Donoghue 1541ec6859b2STodor Tomov /* 1542ec6859b2STodor Tomov * camss_probe - Probe CAMSS platform device 1543ec6859b2STodor Tomov * @pdev: Pointer to CAMSS platform device 1544ec6859b2STodor Tomov * 1545ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1546ec6859b2STodor Tomov */ 1547ec6859b2STodor Tomov static int camss_probe(struct platform_device *pdev) 1548ec6859b2STodor Tomov { 1549ec6859b2STodor Tomov struct device *dev = &pdev->dev; 1550ec6859b2STodor Tomov struct camss *camss; 1551d079f94cSSteve Longerbeam int num_subdevs, ret; 1552ec6859b2STodor Tomov 1553cf295629SVladimir Zapolskiy camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); 1554ec6859b2STodor Tomov if (!camss) 1555ec6859b2STodor Tomov return -ENOMEM; 1556ec6859b2STodor Tomov 1557ec6859b2STodor Tomov atomic_set(&camss->ref_count, 0); 1558ec6859b2STodor Tomov camss->dev = dev; 1559ec6859b2STodor Tomov platform_set_drvdata(pdev, camss); 1560ec6859b2STodor Tomov 15619c3e59deSTodor Tomov if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) { 15629c3e59deSTodor Tomov camss->version = CAMSS_8x16; 15639c3e59deSTodor Tomov camss->csiphy_num = 2; 15649c3e59deSTodor Tomov camss->csid_num = 2; 15659c3e59deSTodor Tomov camss->vfe_num = 1; 15669c3e59deSTodor Tomov } else if (of_device_is_compatible(dev->of_node, 15679c3e59deSTodor Tomov "qcom,msm8996-camss")) { 15689c3e59deSTodor Tomov camss->version = CAMSS_8x96; 15699c3e59deSTodor Tomov camss->csiphy_num = 3; 15709c3e59deSTodor Tomov camss->csid_num = 4; 15719c3e59deSTodor Tomov camss->vfe_num = 2; 15729e5d1581SAngeloGioacchino Del Regno } else if (of_device_is_compatible(dev->of_node, 15739e5d1581SAngeloGioacchino Del Regno "qcom,sdm660-camss")) { 15749e5d1581SAngeloGioacchino Del Regno camss->version = CAMSS_660; 15759e5d1581SAngeloGioacchino Del Regno camss->csiphy_num = 3; 15769e5d1581SAngeloGioacchino Del Regno camss->csid_num = 4; 15779e5d1581SAngeloGioacchino Del Regno camss->vfe_num = 2; 157870524567SRobert Foss } else if (of_device_is_compatible(dev->of_node, 157970524567SRobert Foss "qcom,sdm845-camss")) { 158070524567SRobert Foss camss->version = CAMSS_845; 158170524567SRobert Foss camss->csiphy_num = 4; 158270524567SRobert Foss camss->csid_num = 3; 1583be11096dSVladimir Zapolskiy camss->vfe_num = 2; 1584be11096dSVladimir Zapolskiy camss->vfe_lite_num = 1; 1585b4436a18SJonathan Marek } else if (of_device_is_compatible(dev->of_node, 1586b4436a18SJonathan Marek "qcom,sm8250-camss")) { 1587b4436a18SJonathan Marek camss->version = CAMSS_8250; 1588b4436a18SJonathan Marek camss->csiphy_num = 6; 1589b4436a18SJonathan Marek camss->csid_num = 4; 1590be11096dSVladimir Zapolskiy camss->vfe_num = 2; 1591be11096dSVladimir Zapolskiy camss->vfe_lite_num = 2; 15929c3e59deSTodor Tomov } else { 1593cf295629SVladimir Zapolskiy return -EINVAL; 15949c3e59deSTodor Tomov } 15959c3e59deSTodor Tomov 159655b51899STodor Tomov camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, 159755b51899STodor Tomov sizeof(*camss->csiphy), GFP_KERNEL); 1598cf295629SVladimir Zapolskiy if (!camss->csiphy) 1599cf295629SVladimir Zapolskiy return -ENOMEM; 16009c3e59deSTodor Tomov 160155b51899STodor Tomov camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), 16029c3e59deSTodor Tomov GFP_KERNEL); 1603cf295629SVladimir Zapolskiy if (!camss->csid) 1604cf295629SVladimir Zapolskiy return -ENOMEM; 16059c3e59deSTodor Tomov 16069d95baf9SRobert Foss if (camss->version == CAMSS_8x16 || 16079d95baf9SRobert Foss camss->version == CAMSS_8x96) { 16089d95baf9SRobert Foss camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); 1609cf295629SVladimir Zapolskiy if (!camss->ispif) 1610cf295629SVladimir Zapolskiy return -ENOMEM; 16119d95baf9SRobert Foss } 16129d95baf9SRobert Foss 1613be11096dSVladimir Zapolskiy camss->vfe = devm_kcalloc(dev, camss->vfe_num + camss->vfe_lite_num, 1614be11096dSVladimir Zapolskiy sizeof(*camss->vfe), GFP_KERNEL); 1615cf295629SVladimir Zapolskiy if (!camss->vfe) 1616cf295629SVladimir Zapolskiy return -ENOMEM; 16179c3e59deSTodor Tomov 16183c8c1539SSakari Ailus v4l2_async_nf_init(&camss->notifier); 1619d079f94cSSteve Longerbeam 1620d079f94cSSteve Longerbeam num_subdevs = camss_of_parse_ports(camss); 1621f45882cfSEvgeny Novikov if (num_subdevs < 0) { 1622f45882cfSEvgeny Novikov ret = num_subdevs; 1623f45882cfSEvgeny Novikov goto err_cleanup; 1624f45882cfSEvgeny Novikov } 1625ec6859b2STodor Tomov 16265ba38efbSBryan O'Donoghue ret = camss_icc_get(camss); 16275ba38efbSBryan O'Donoghue if (ret < 0) 16285ba38efbSBryan O'Donoghue goto err_cleanup; 16295ba38efbSBryan O'Donoghue 1630ec6859b2STodor Tomov ret = camss_init_subdevices(camss); 1631ec6859b2STodor Tomov if (ret < 0) 1632d079f94cSSteve Longerbeam goto err_cleanup; 1633ec6859b2STodor Tomov 1634ec6859b2STodor Tomov ret = dma_set_mask_and_coherent(dev, 0xffffffff); 1635ec6859b2STodor Tomov if (ret) 1636d079f94cSSteve Longerbeam goto err_cleanup; 1637ec6859b2STodor Tomov 1638ec6859b2STodor Tomov camss->media_dev.dev = camss->dev; 1639c0decac1SMauro Carvalho Chehab strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem", 1640ec6859b2STodor Tomov sizeof(camss->media_dev.model)); 1641ec6859b2STodor Tomov camss->media_dev.ops = &camss_media_ops; 1642ec6859b2STodor Tomov media_device_init(&camss->media_dev); 1643ec6859b2STodor Tomov 1644ec6859b2STodor Tomov camss->v4l2_dev.mdev = &camss->media_dev; 1645ec6859b2STodor Tomov ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); 1646ec6859b2STodor Tomov if (ret < 0) { 1647ec6859b2STodor Tomov dev_err(dev, "Failed to register V4L2 device: %d\n", ret); 1648d079f94cSSteve Longerbeam goto err_cleanup; 1649ec6859b2STodor Tomov } 1650ec6859b2STodor Tomov 1651ec6859b2STodor Tomov ret = camss_register_entities(camss); 1652ec6859b2STodor Tomov if (ret < 0) 1653ec6859b2STodor Tomov goto err_register_entities; 1654ec6859b2STodor Tomov 1655d079f94cSSteve Longerbeam if (num_subdevs) { 1656ec6859b2STodor Tomov camss->notifier.ops = &camss_subdev_notifier_ops; 1657ec6859b2STodor Tomov 16583c8c1539SSakari Ailus ret = v4l2_async_nf_register(&camss->v4l2_dev, 1659ec6859b2STodor Tomov &camss->notifier); 1660ec6859b2STodor Tomov if (ret) { 1661ec6859b2STodor Tomov dev_err(dev, 1662ec6859b2STodor Tomov "Failed to register async subdev nodes: %d\n", 1663ec6859b2STodor Tomov ret); 1664ec6859b2STodor Tomov goto err_register_subdevs; 1665ec6859b2STodor Tomov } 1666ec6859b2STodor Tomov } else { 1667ec6859b2STodor Tomov ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); 1668ec6859b2STodor Tomov if (ret < 0) { 1669ec6859b2STodor Tomov dev_err(dev, "Failed to register subdev nodes: %d\n", 1670ec6859b2STodor Tomov ret); 1671ec6859b2STodor Tomov goto err_register_subdevs; 1672ec6859b2STodor Tomov } 1673ec6859b2STodor Tomov 1674ec6859b2STodor Tomov ret = media_device_register(&camss->media_dev); 1675ec6859b2STodor Tomov if (ret < 0) { 1676ec6859b2STodor Tomov dev_err(dev, "Failed to register media device: %d\n", 1677ec6859b2STodor Tomov ret); 1678ec6859b2STodor Tomov goto err_register_subdevs; 1679ec6859b2STodor Tomov } 1680ec6859b2STodor Tomov } 1681ec6859b2STodor Tomov 16822f6f8af6SRobert Foss ret = camss_configure_pd(camss); 16832f6f8af6SRobert Foss if (ret < 0) { 16842f6f8af6SRobert Foss dev_err(dev, "Failed to configure power domains: %d\n", ret); 16852f6f8af6SRobert Foss return ret; 168602afa816STodor Tomov } 168702afa816STodor Tomov 168802afa816STodor Tomov pm_runtime_enable(dev); 168902afa816STodor Tomov 1690ec6859b2STodor Tomov return 0; 1691ec6859b2STodor Tomov 1692ec6859b2STodor Tomov err_register_subdevs: 1693ec6859b2STodor Tomov camss_unregister_entities(camss); 1694ec6859b2STodor Tomov err_register_entities: 1695ec6859b2STodor Tomov v4l2_device_unregister(&camss->v4l2_dev); 1696d079f94cSSteve Longerbeam err_cleanup: 16973c8c1539SSakari Ailus v4l2_async_nf_cleanup(&camss->notifier); 1698ec6859b2STodor Tomov 1699ec6859b2STodor Tomov return ret; 1700ec6859b2STodor Tomov } 1701ec6859b2STodor Tomov 1702ec6859b2STodor Tomov void camss_delete(struct camss *camss) 1703ec6859b2STodor Tomov { 17042f6f8af6SRobert Foss int i; 17052f6f8af6SRobert Foss 1706ec6859b2STodor Tomov v4l2_device_unregister(&camss->v4l2_dev); 1707ec6859b2STodor Tomov media_device_unregister(&camss->media_dev); 1708ec6859b2STodor Tomov media_device_cleanup(&camss->media_dev); 1709ec6859b2STodor Tomov 171002afa816STodor Tomov pm_runtime_disable(camss->dev); 171102afa816STodor Tomov 17123d658980SVladimir Zapolskiy if (camss->genpd_num == 1) 17133d658980SVladimir Zapolskiy return; 17143d658980SVladimir Zapolskiy 171546cc0317SVladimir Zapolskiy if (camss->genpd_num > camss->vfe_num) 171646cc0317SVladimir Zapolskiy device_link_del(camss->genpd_link[camss->genpd_num - 1]); 171746cc0317SVladimir Zapolskiy 171846cc0317SVladimir Zapolskiy for (i = 0; i < camss->genpd_num; i++) 17192f6f8af6SRobert Foss dev_pm_domain_detach(camss->genpd[i], true); 172002afa816STodor Tomov } 1721ec6859b2STodor Tomov 1722ec6859b2STodor Tomov /* 1723ec6859b2STodor Tomov * camss_remove - Remove CAMSS platform device 1724ec6859b2STodor Tomov * @pdev: Pointer to CAMSS platform device 1725ec6859b2STodor Tomov * 1726ec6859b2STodor Tomov * Always returns 0. 1727ec6859b2STodor Tomov */ 1728428bbf4bSUwe Kleine-König static void camss_remove(struct platform_device *pdev) 1729ec6859b2STodor Tomov { 1730ec6859b2STodor Tomov struct camss *camss = platform_get_drvdata(pdev); 1731ec6859b2STodor Tomov 17323c8c1539SSakari Ailus v4l2_async_nf_unregister(&camss->notifier); 17333c8c1539SSakari Ailus v4l2_async_nf_cleanup(&camss->notifier); 1734ec6859b2STodor Tomov camss_unregister_entities(camss); 1735ec6859b2STodor Tomov 1736ec6859b2STodor Tomov if (atomic_read(&camss->ref_count) == 0) 1737ec6859b2STodor Tomov camss_delete(camss); 1738ec6859b2STodor Tomov } 1739ec6859b2STodor Tomov 1740ec6859b2STodor Tomov static const struct of_device_id camss_dt_match[] = { 1741ec6859b2STodor Tomov { .compatible = "qcom,msm8916-camss" }, 17429c3e59deSTodor Tomov { .compatible = "qcom,msm8996-camss" }, 17439e5d1581SAngeloGioacchino Del Regno { .compatible = "qcom,sdm660-camss" }, 174470524567SRobert Foss { .compatible = "qcom,sdm845-camss" }, 1745b4436a18SJonathan Marek { .compatible = "qcom,sm8250-camss" }, 1746ec6859b2STodor Tomov { } 1747ec6859b2STodor Tomov }; 1748ec6859b2STodor Tomov 1749ec6859b2STodor Tomov MODULE_DEVICE_TABLE(of, camss_dt_match); 1750ec6859b2STodor Tomov 175144a9ffd4SArnd Bergmann static int __maybe_unused camss_runtime_suspend(struct device *dev) 175202afa816STodor Tomov { 17535ba38efbSBryan O'Donoghue struct camss *camss = dev_get_drvdata(dev); 17545ba38efbSBryan O'Donoghue int nbr_icc_paths = 0; 17555ba38efbSBryan O'Donoghue int i; 17565ba38efbSBryan O'Donoghue int ret; 17575ba38efbSBryan O'Donoghue 17585ba38efbSBryan O'Donoghue if (camss->version == CAMSS_8250) 17595ba38efbSBryan O'Donoghue nbr_icc_paths = ICC_SM8250_COUNT; 17605ba38efbSBryan O'Donoghue 17615ba38efbSBryan O'Donoghue for (i = 0; i < nbr_icc_paths; i++) { 17625ba38efbSBryan O'Donoghue ret = icc_set_bw(camss->icc_path[i], 0, 0); 17635ba38efbSBryan O'Donoghue if (ret) 17645ba38efbSBryan O'Donoghue return ret; 17655ba38efbSBryan O'Donoghue } 17665ba38efbSBryan O'Donoghue 176702afa816STodor Tomov return 0; 176802afa816STodor Tomov } 176902afa816STodor Tomov 177044a9ffd4SArnd Bergmann static int __maybe_unused camss_runtime_resume(struct device *dev) 177102afa816STodor Tomov { 17725ba38efbSBryan O'Donoghue struct camss *camss = dev_get_drvdata(dev); 17735ba38efbSBryan O'Donoghue int nbr_icc_paths = 0; 17745ba38efbSBryan O'Donoghue int i; 17755ba38efbSBryan O'Donoghue int ret; 17765ba38efbSBryan O'Donoghue 17775ba38efbSBryan O'Donoghue if (camss->version == CAMSS_8250) 17785ba38efbSBryan O'Donoghue nbr_icc_paths = ICC_SM8250_COUNT; 17795ba38efbSBryan O'Donoghue 17805ba38efbSBryan O'Donoghue for (i = 0; i < nbr_icc_paths; i++) { 17815ba38efbSBryan O'Donoghue ret = icc_set_bw(camss->icc_path[i], 17825ba38efbSBryan O'Donoghue camss->icc_bw_tbl[i].avg, 17835ba38efbSBryan O'Donoghue camss->icc_bw_tbl[i].peak); 17845ba38efbSBryan O'Donoghue if (ret) 17855ba38efbSBryan O'Donoghue return ret; 17865ba38efbSBryan O'Donoghue } 17875ba38efbSBryan O'Donoghue 178802afa816STodor Tomov return 0; 178902afa816STodor Tomov } 179002afa816STodor Tomov 179102afa816STodor Tomov static const struct dev_pm_ops camss_pm_ops = { 179202afa816STodor Tomov SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 179302afa816STodor Tomov pm_runtime_force_resume) 179402afa816STodor Tomov SET_RUNTIME_PM_OPS(camss_runtime_suspend, camss_runtime_resume, NULL) 179502afa816STodor Tomov }; 179602afa816STodor Tomov 1797ec6859b2STodor Tomov static struct platform_driver qcom_camss_driver = { 1798ec6859b2STodor Tomov .probe = camss_probe, 1799428bbf4bSUwe Kleine-König .remove_new = camss_remove, 1800ec6859b2STodor Tomov .driver = { 1801ec6859b2STodor Tomov .name = "qcom-camss", 1802ec6859b2STodor Tomov .of_match_table = camss_dt_match, 180302afa816STodor Tomov .pm = &camss_pm_ops, 1804ec6859b2STodor Tomov }, 1805ec6859b2STodor Tomov }; 1806ec6859b2STodor Tomov 1807ec6859b2STodor Tomov module_platform_driver(qcom_camss_driver); 1808ec6859b2STodor Tomov 1809ec6859b2STodor Tomov MODULE_ALIAS("platform:qcom-camss"); 1810ec6859b2STodor Tomov MODULE_DESCRIPTION("Qualcomm Camera Subsystem driver"); 1811ec6859b2STodor Tomov MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); 1812ec6859b2STodor Tomov MODULE_LICENSE("GPL v2"); 1813