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> 11ec6859b2STodor Tomov #include <linux/media-bus-format.h> 12ec6859b2STodor Tomov #include <linux/media.h> 13ec6859b2STodor Tomov #include <linux/module.h> 14ec6859b2STodor Tomov #include <linux/platform_device.h> 15ec6859b2STodor Tomov #include <linux/of.h> 16ec6859b2STodor Tomov #include <linux/of_graph.h> 1702afa816STodor Tomov #include <linux/pm_runtime.h> 1802afa816STodor Tomov #include <linux/pm_domain.h> 19ec6859b2STodor Tomov #include <linux/slab.h> 20ec6859b2STodor Tomov #include <linux/videodev2.h> 21ec6859b2STodor Tomov 22ec6859b2STodor Tomov #include <media/media-device.h> 23ec6859b2STodor Tomov #include <media/v4l2-async.h> 24ec6859b2STodor Tomov #include <media/v4l2-device.h> 25ec6859b2STodor Tomov #include <media/v4l2-mc.h> 26ec6859b2STodor Tomov #include <media/v4l2-fwnode.h> 27ec6859b2STodor Tomov 28ec6859b2STodor Tomov #include "camss.h" 29ec6859b2STodor Tomov 30ec6859b2STodor Tomov #define CAMSS_CLOCK_MARGIN_NUMERATOR 105 31ec6859b2STodor Tomov #define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 32ec6859b2STodor Tomov 339c3e59deSTodor Tomov static const struct resources csiphy_res_8x16[] = { 34ec6859b2STodor Tomov /* CSIPHY0 */ 35ec6859b2STodor Tomov { 36ec6859b2STodor Tomov .regulator = { NULL }, 3709a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, 38ec6859b2STodor Tomov .clock_rate = { { 0 }, 39ec6859b2STodor Tomov { 0 }, 40ec6859b2STodor Tomov { 0 }, 41ec6859b2STodor Tomov { 100000000, 200000000 } }, 42ec6859b2STodor Tomov .reg = { "csiphy0", "csiphy0_clk_mux" }, 43ec6859b2STodor Tomov .interrupt = { "csiphy0" } 44ec6859b2STodor Tomov }, 45ec6859b2STodor Tomov 46ec6859b2STodor Tomov /* CSIPHY1 */ 47ec6859b2STodor Tomov { 48ec6859b2STodor Tomov .regulator = { NULL }, 4909a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, 50ec6859b2STodor Tomov .clock_rate = { { 0 }, 51ec6859b2STodor Tomov { 0 }, 52ec6859b2STodor Tomov { 0 }, 53ec6859b2STodor Tomov { 100000000, 200000000 } }, 54ec6859b2STodor Tomov .reg = { "csiphy1", "csiphy1_clk_mux" }, 55ec6859b2STodor Tomov .interrupt = { "csiphy1" } 56ec6859b2STodor Tomov } 57ec6859b2STodor Tomov }; 58ec6859b2STodor Tomov 599c3e59deSTodor Tomov static const struct resources csid_res_8x16[] = { 60ec6859b2STodor Tomov /* CSID0 */ 61ec6859b2STodor Tomov { 62ec6859b2STodor Tomov .regulator = { "vdda" }, 6309a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 64ec6859b2STodor Tomov "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, 65ec6859b2STodor Tomov .clock_rate = { { 0 }, 66ec6859b2STodor Tomov { 0 }, 67ec6859b2STodor Tomov { 0 }, 68ec6859b2STodor Tomov { 0 }, 69ec6859b2STodor Tomov { 100000000, 200000000 }, 70ec6859b2STodor Tomov { 0 }, 71ec6859b2STodor Tomov { 0 }, 72ec6859b2STodor Tomov { 0 } }, 73ec6859b2STodor Tomov .reg = { "csid0" }, 74ec6859b2STodor Tomov .interrupt = { "csid0" } 75ec6859b2STodor Tomov }, 76ec6859b2STodor Tomov 77ec6859b2STodor Tomov /* CSID1 */ 78ec6859b2STodor Tomov { 79ec6859b2STodor Tomov .regulator = { "vdda" }, 8009a94865STodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 81ec6859b2STodor Tomov "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, 82ec6859b2STodor Tomov .clock_rate = { { 0 }, 83ec6859b2STodor Tomov { 0 }, 84ec6859b2STodor Tomov { 0 }, 85ec6859b2STodor Tomov { 0 }, 86ec6859b2STodor Tomov { 100000000, 200000000 }, 87ec6859b2STodor Tomov { 0 }, 88ec6859b2STodor Tomov { 0 }, 89ec6859b2STodor Tomov { 0 } }, 90ec6859b2STodor Tomov .reg = { "csid1" }, 91ec6859b2STodor Tomov .interrupt = { "csid1" } 92ec6859b2STodor Tomov }, 93ec6859b2STodor Tomov }; 94ec6859b2STodor Tomov 959c3e59deSTodor Tomov static const struct resources_ispif ispif_res_8x16 = { 96ec6859b2STodor Tomov /* ISPIF */ 9709a94865STodor Tomov .clock = { "top_ahb", "ahb", "ispif_ahb", 98ec6859b2STodor Tomov "csi0", "csi0_pix", "csi0_rdi", 99ec6859b2STodor Tomov "csi1", "csi1_pix", "csi1_rdi" }, 10009a94865STodor Tomov .clock_for_reset = { "vfe0", "csi_vfe0" }, 101ec6859b2STodor Tomov .reg = { "ispif", "csi_clk_mux" }, 102ec6859b2STodor Tomov .interrupt = "ispif" 103ec6859b2STodor Tomov 104ec6859b2STodor Tomov }; 105ec6859b2STodor Tomov 1069c3e59deSTodor Tomov static const struct resources vfe_res_8x16[] = { 107ec6859b2STodor Tomov /* VFE0 */ 1089c3e59deSTodor Tomov { 109ec6859b2STodor Tomov .regulator = { NULL }, 11009a94865STodor Tomov .clock = { "top_ahb", "vfe0", "csi_vfe0", 11109a94865STodor Tomov "vfe_ahb", "vfe_axi", "ahb" }, 112ec6859b2STodor Tomov .clock_rate = { { 0 }, 113ec6859b2STodor Tomov { 50000000, 80000000, 100000000, 160000000, 114ec6859b2STodor Tomov 177780000, 200000000, 266670000, 320000000, 115ec6859b2STodor Tomov 400000000, 465000000 }, 116ec6859b2STodor Tomov { 0 }, 117ec6859b2STodor Tomov { 0 }, 118ec6859b2STodor Tomov { 0 }, 119ec6859b2STodor Tomov { 0 }, 120ec6859b2STodor Tomov { 0 }, 121ec6859b2STodor Tomov { 0 }, 122ec6859b2STodor Tomov { 0 } }, 123ec6859b2STodor Tomov .reg = { "vfe0" }, 124ec6859b2STodor Tomov .interrupt = { "vfe0" } 1259c3e59deSTodor Tomov } 1269c3e59deSTodor Tomov }; 1279c3e59deSTodor Tomov 1289c3e59deSTodor Tomov static const struct resources csiphy_res_8x96[] = { 1299c3e59deSTodor Tomov /* CSIPHY0 */ 1309c3e59deSTodor Tomov { 1319c3e59deSTodor Tomov .regulator = { NULL }, 1329c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, 1339c3e59deSTodor Tomov .clock_rate = { { 0 }, 1349c3e59deSTodor Tomov { 0 }, 1359c3e59deSTodor Tomov { 0 }, 1369c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1379c3e59deSTodor Tomov .reg = { "csiphy0", "csiphy0_clk_mux" }, 1389c3e59deSTodor Tomov .interrupt = { "csiphy0" } 1399c3e59deSTodor Tomov }, 1409c3e59deSTodor Tomov 1419c3e59deSTodor Tomov /* CSIPHY1 */ 1429c3e59deSTodor Tomov { 1439c3e59deSTodor Tomov .regulator = { NULL }, 1449c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, 1459c3e59deSTodor Tomov .clock_rate = { { 0 }, 1469c3e59deSTodor Tomov { 0 }, 1479c3e59deSTodor Tomov { 0 }, 1489c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1499c3e59deSTodor Tomov .reg = { "csiphy1", "csiphy1_clk_mux" }, 1509c3e59deSTodor Tomov .interrupt = { "csiphy1" } 1519c3e59deSTodor Tomov }, 1529c3e59deSTodor Tomov 1539c3e59deSTodor Tomov /* CSIPHY2 */ 1549c3e59deSTodor Tomov { 1559c3e59deSTodor Tomov .regulator = { NULL }, 1569c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer" }, 1579c3e59deSTodor Tomov .clock_rate = { { 0 }, 1589c3e59deSTodor Tomov { 0 }, 1599c3e59deSTodor Tomov { 0 }, 1609c3e59deSTodor Tomov { 100000000, 200000000, 266666667 } }, 1619c3e59deSTodor Tomov .reg = { "csiphy2", "csiphy2_clk_mux" }, 1629c3e59deSTodor Tomov .interrupt = { "csiphy2" } 1639c3e59deSTodor Tomov } 1649c3e59deSTodor Tomov }; 1659c3e59deSTodor Tomov 1669c3e59deSTodor Tomov static const struct resources csid_res_8x96[] = { 1679c3e59deSTodor Tomov /* CSID0 */ 1689c3e59deSTodor Tomov { 1699c3e59deSTodor Tomov .regulator = { "vdda" }, 1709c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 1719c3e59deSTodor Tomov "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, 1729c3e59deSTodor Tomov .clock_rate = { { 0 }, 1739c3e59deSTodor Tomov { 0 }, 1749c3e59deSTodor Tomov { 0 }, 1759c3e59deSTodor Tomov { 0 }, 1769c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 1779c3e59deSTodor Tomov { 0 }, 1789c3e59deSTodor Tomov { 0 }, 1799c3e59deSTodor Tomov { 0 } }, 1809c3e59deSTodor Tomov .reg = { "csid0" }, 1819c3e59deSTodor Tomov .interrupt = { "csid0" } 1829c3e59deSTodor Tomov }, 1839c3e59deSTodor Tomov 1849c3e59deSTodor Tomov /* CSID1 */ 1859c3e59deSTodor Tomov { 1869c3e59deSTodor Tomov .regulator = { "vdda" }, 1879c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 1889c3e59deSTodor Tomov "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, 1899c3e59deSTodor Tomov .clock_rate = { { 0 }, 1909c3e59deSTodor Tomov { 0 }, 1919c3e59deSTodor Tomov { 0 }, 1929c3e59deSTodor Tomov { 0 }, 1939c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 1949c3e59deSTodor Tomov { 0 }, 1959c3e59deSTodor Tomov { 0 }, 1969c3e59deSTodor Tomov { 0 } }, 1979c3e59deSTodor Tomov .reg = { "csid1" }, 1989c3e59deSTodor Tomov .interrupt = { "csid1" } 1999c3e59deSTodor Tomov }, 2009c3e59deSTodor Tomov 2019c3e59deSTodor Tomov /* CSID2 */ 2029c3e59deSTodor Tomov { 2039c3e59deSTodor Tomov .regulator = { "vdda" }, 2049c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", 2059c3e59deSTodor Tomov "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, 2069c3e59deSTodor Tomov .clock_rate = { { 0 }, 2079c3e59deSTodor Tomov { 0 }, 2089c3e59deSTodor Tomov { 0 }, 2099c3e59deSTodor Tomov { 0 }, 2109c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 2119c3e59deSTodor Tomov { 0 }, 2129c3e59deSTodor Tomov { 0 }, 2139c3e59deSTodor Tomov { 0 } }, 2149c3e59deSTodor Tomov .reg = { "csid2" }, 2159c3e59deSTodor Tomov .interrupt = { "csid2" } 2169c3e59deSTodor Tomov }, 2179c3e59deSTodor Tomov 2189c3e59deSTodor Tomov /* CSID3 */ 2199c3e59deSTodor Tomov { 2209c3e59deSTodor Tomov .regulator = { "vdda" }, 2219c3e59deSTodor Tomov .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", 2229c3e59deSTodor Tomov "csi3", "csi3_phy", "csi3_pix", "csi3_rdi" }, 2239c3e59deSTodor Tomov .clock_rate = { { 0 }, 2249c3e59deSTodor Tomov { 0 }, 2259c3e59deSTodor Tomov { 0 }, 2269c3e59deSTodor Tomov { 0 }, 2279c3e59deSTodor Tomov { 100000000, 200000000, 266666667 }, 2289c3e59deSTodor Tomov { 0 }, 2299c3e59deSTodor Tomov { 0 }, 2309c3e59deSTodor Tomov { 0 } }, 2319c3e59deSTodor Tomov .reg = { "csid3" }, 2329c3e59deSTodor Tomov .interrupt = { "csid3" } 2339c3e59deSTodor Tomov } 2349c3e59deSTodor Tomov }; 2359c3e59deSTodor Tomov 2369c3e59deSTodor Tomov static const struct resources_ispif ispif_res_8x96 = { 2379c3e59deSTodor Tomov /* ISPIF */ 2389c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "ispif_ahb", 2399c3e59deSTodor Tomov "csi0", "csi0_pix", "csi0_rdi", 2409c3e59deSTodor Tomov "csi1", "csi1_pix", "csi1_rdi", 2419c3e59deSTodor Tomov "csi2", "csi2_pix", "csi2_rdi", 2429c3e59deSTodor Tomov "csi3", "csi3_pix", "csi3_rdi" }, 2439c3e59deSTodor Tomov .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, 2449c3e59deSTodor Tomov .reg = { "ispif", "csi_clk_mux" }, 2459c3e59deSTodor Tomov .interrupt = "ispif" 2469c3e59deSTodor Tomov }; 2479c3e59deSTodor Tomov 2489c3e59deSTodor Tomov static const struct resources vfe_res_8x96[] = { 2499c3e59deSTodor Tomov /* VFE0 */ 2509c3e59deSTodor Tomov { 2519c3e59deSTodor Tomov .regulator = { NULL }, 2529c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "vfe0", "csi_vfe0", "vfe_ahb", 2539c3e59deSTodor Tomov "vfe0_ahb", "vfe_axi", "vfe0_stream"}, 2549c3e59deSTodor Tomov .clock_rate = { { 0 }, 2559c3e59deSTodor Tomov { 0 }, 2569c3e59deSTodor Tomov { 75000000, 100000000, 300000000, 2579c3e59deSTodor Tomov 320000000, 480000000, 600000000 }, 2589c3e59deSTodor Tomov { 0 }, 2599c3e59deSTodor Tomov { 0 }, 2609c3e59deSTodor Tomov { 0 }, 2619c3e59deSTodor Tomov { 0 }, 2629c3e59deSTodor Tomov { 0 } }, 2639c3e59deSTodor Tomov .reg = { "vfe0" }, 2649c3e59deSTodor Tomov .interrupt = { "vfe0" } 2659c3e59deSTodor Tomov }, 2669c3e59deSTodor Tomov 2679c3e59deSTodor Tomov /* VFE1 */ 2689c3e59deSTodor Tomov { 2699c3e59deSTodor Tomov .regulator = { NULL }, 2709c3e59deSTodor Tomov .clock = { "top_ahb", "ahb", "vfe1", "csi_vfe1", "vfe_ahb", 2719c3e59deSTodor Tomov "vfe1_ahb", "vfe_axi", "vfe1_stream"}, 2729c3e59deSTodor Tomov .clock_rate = { { 0 }, 2739c3e59deSTodor Tomov { 0 }, 2749c3e59deSTodor Tomov { 75000000, 100000000, 300000000, 2759c3e59deSTodor Tomov 320000000, 480000000, 600000000 }, 2769c3e59deSTodor Tomov { 0 }, 2779c3e59deSTodor Tomov { 0 }, 2789c3e59deSTodor Tomov { 0 }, 2799c3e59deSTodor Tomov { 0 }, 2809c3e59deSTodor Tomov { 0 } }, 2819c3e59deSTodor Tomov .reg = { "vfe1" }, 2829c3e59deSTodor Tomov .interrupt = { "vfe1" } 2839c3e59deSTodor Tomov } 284ec6859b2STodor Tomov }; 285ec6859b2STodor Tomov 2869e5d1581SAngeloGioacchino Del Regno static const struct resources csiphy_res_660[] = { 2879e5d1581SAngeloGioacchino Del Regno /* CSIPHY0 */ 2889e5d1581SAngeloGioacchino Del Regno { 2899e5d1581SAngeloGioacchino Del Regno .regulator = { NULL }, 2909e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer", 2919e5d1581SAngeloGioacchino Del Regno "csi0_phy", "csiphy_ahb2crif" }, 2929e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 2939e5d1581SAngeloGioacchino Del Regno { 0 }, 2949e5d1581SAngeloGioacchino Del Regno { 0 }, 2959e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 2969e5d1581SAngeloGioacchino Del Regno { 0 } }, 2979e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy0", "csiphy0_clk_mux" }, 2989e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy0" } 2999e5d1581SAngeloGioacchino Del Regno }, 3009e5d1581SAngeloGioacchino Del Regno 3019e5d1581SAngeloGioacchino Del Regno /* CSIPHY1 */ 3029e5d1581SAngeloGioacchino Del Regno { 3039e5d1581SAngeloGioacchino Del Regno .regulator = { NULL }, 3049e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer", 3059e5d1581SAngeloGioacchino Del Regno "csi1_phy", "csiphy_ahb2crif" }, 3069e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3079e5d1581SAngeloGioacchino Del Regno { 0 }, 3089e5d1581SAngeloGioacchino Del Regno { 0 }, 3099e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 3109e5d1581SAngeloGioacchino Del Regno { 0 } }, 3119e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy1", "csiphy1_clk_mux" }, 3129e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy1" } 3139e5d1581SAngeloGioacchino Del Regno }, 3149e5d1581SAngeloGioacchino Del Regno 3159e5d1581SAngeloGioacchino Del Regno /* CSIPHY2 */ 3169e5d1581SAngeloGioacchino Del Regno { 3179e5d1581SAngeloGioacchino Del Regno .regulator = { NULL }, 3189e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer", 3199e5d1581SAngeloGioacchino Del Regno "csi2_phy", "csiphy_ahb2crif" }, 3209e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3219e5d1581SAngeloGioacchino Del Regno { 0 }, 3229e5d1581SAngeloGioacchino Del Regno { 0 }, 3239e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 269333333 }, 3249e5d1581SAngeloGioacchino Del Regno { 0 } }, 3259e5d1581SAngeloGioacchino Del Regno .reg = { "csiphy2", "csiphy2_clk_mux" }, 3269e5d1581SAngeloGioacchino Del Regno .interrupt = { "csiphy2" } 3279e5d1581SAngeloGioacchino Del Regno } 3289e5d1581SAngeloGioacchino Del Regno }; 3299e5d1581SAngeloGioacchino Del Regno 3309e5d1581SAngeloGioacchino Del Regno static const struct resources csid_res_660[] = { 3319e5d1581SAngeloGioacchino Del Regno /* CSID0 */ 3329e5d1581SAngeloGioacchino Del Regno { 3339e5d1581SAngeloGioacchino Del Regno .regulator = { "vdda", "vdd_sec" }, 3349e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", 3359e5d1581SAngeloGioacchino Del Regno "csi0", "csi0_phy", "csi0_pix", "csi0_rdi", 3369e5d1581SAngeloGioacchino Del Regno "cphy_csid0" }, 3379e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3389e5d1581SAngeloGioacchino Del Regno { 0 }, 3399e5d1581SAngeloGioacchino Del Regno { 0 }, 3409e5d1581SAngeloGioacchino Del Regno { 0 }, 3419e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3429e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3439e5d1581SAngeloGioacchino Del Regno { 0 }, 3449e5d1581SAngeloGioacchino Del Regno { 0 }, 3459e5d1581SAngeloGioacchino Del Regno { 0 }, 3469e5d1581SAngeloGioacchino Del Regno { 0 } }, 3479e5d1581SAngeloGioacchino Del Regno .reg = { "csid0" }, 3489e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid0" } 3499e5d1581SAngeloGioacchino Del Regno }, 3509e5d1581SAngeloGioacchino Del Regno 3519e5d1581SAngeloGioacchino Del Regno /* CSID1 */ 3529e5d1581SAngeloGioacchino Del Regno { 3539e5d1581SAngeloGioacchino Del Regno .regulator = { "vdda", "vdd_sec" }, 3549e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", 3559e5d1581SAngeloGioacchino Del Regno "csi1", "csi1_phy", "csi1_pix", "csi1_rdi", 3569e5d1581SAngeloGioacchino Del Regno "cphy_csid1" }, 3579e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3589e5d1581SAngeloGioacchino Del Regno { 0 }, 3599e5d1581SAngeloGioacchino Del Regno { 0 }, 3609e5d1581SAngeloGioacchino Del Regno { 0 }, 3619e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3629e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3639e5d1581SAngeloGioacchino Del Regno { 0 }, 3649e5d1581SAngeloGioacchino Del Regno { 0 }, 3659e5d1581SAngeloGioacchino Del Regno { 0 }, 3669e5d1581SAngeloGioacchino Del Regno { 0 } }, 3679e5d1581SAngeloGioacchino Del Regno .reg = { "csid1" }, 3689e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid1" } 3699e5d1581SAngeloGioacchino Del Regno }, 3709e5d1581SAngeloGioacchino Del Regno 3719e5d1581SAngeloGioacchino Del Regno /* CSID2 */ 3729e5d1581SAngeloGioacchino Del Regno { 3739e5d1581SAngeloGioacchino Del Regno .regulator = { "vdda", "vdd_sec" }, 3749e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", 3759e5d1581SAngeloGioacchino Del Regno "csi2", "csi2_phy", "csi2_pix", "csi2_rdi", 3769e5d1581SAngeloGioacchino Del Regno "cphy_csid2" }, 3779e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3789e5d1581SAngeloGioacchino Del Regno { 0 }, 3799e5d1581SAngeloGioacchino Del Regno { 0 }, 3809e5d1581SAngeloGioacchino Del Regno { 0 }, 3819e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 3829e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 3839e5d1581SAngeloGioacchino Del Regno { 0 }, 3849e5d1581SAngeloGioacchino Del Regno { 0 }, 3859e5d1581SAngeloGioacchino Del Regno { 0 }, 3869e5d1581SAngeloGioacchino Del Regno { 0 } }, 3879e5d1581SAngeloGioacchino Del Regno .reg = { "csid2" }, 3889e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid2" } 3899e5d1581SAngeloGioacchino Del Regno }, 3909e5d1581SAngeloGioacchino Del Regno 3919e5d1581SAngeloGioacchino Del Regno /* CSID3 */ 3929e5d1581SAngeloGioacchino Del Regno { 3939e5d1581SAngeloGioacchino Del Regno .regulator = { "vdda", "vdd_sec" }, 3949e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", 3959e5d1581SAngeloGioacchino Del Regno "csi3", "csi3_phy", "csi3_pix", "csi3_rdi", 3969e5d1581SAngeloGioacchino Del Regno "cphy_csid3" }, 3979e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 3989e5d1581SAngeloGioacchino Del Regno { 0 }, 3999e5d1581SAngeloGioacchino Del Regno { 0 }, 4009e5d1581SAngeloGioacchino Del Regno { 0 }, 4019e5d1581SAngeloGioacchino Del Regno { 100000000, 200000000, 310000000, 4029e5d1581SAngeloGioacchino Del Regno 404000000, 465000000 }, 4039e5d1581SAngeloGioacchino Del Regno { 0 }, 4049e5d1581SAngeloGioacchino Del Regno { 0 }, 4059e5d1581SAngeloGioacchino Del Regno { 0 }, 4069e5d1581SAngeloGioacchino Del Regno { 0 } }, 4079e5d1581SAngeloGioacchino Del Regno .reg = { "csid3" }, 4089e5d1581SAngeloGioacchino Del Regno .interrupt = { "csid3" } 4099e5d1581SAngeloGioacchino Del Regno } 4109e5d1581SAngeloGioacchino Del Regno }; 4119e5d1581SAngeloGioacchino Del Regno 4129e5d1581SAngeloGioacchino Del Regno static const struct resources_ispif ispif_res_660 = { 4139e5d1581SAngeloGioacchino Del Regno /* ISPIF */ 4149e5d1581SAngeloGioacchino Del Regno .clock = { "top_ahb", "ahb", "ispif_ahb", 4159e5d1581SAngeloGioacchino Del Regno "csi0", "csi0_pix", "csi0_rdi", 4169e5d1581SAngeloGioacchino Del Regno "csi1", "csi1_pix", "csi1_rdi", 4179e5d1581SAngeloGioacchino Del Regno "csi2", "csi2_pix", "csi2_rdi", 4189e5d1581SAngeloGioacchino Del Regno "csi3", "csi3_pix", "csi3_rdi" }, 4199e5d1581SAngeloGioacchino Del Regno .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, 4209e5d1581SAngeloGioacchino Del Regno .reg = { "ispif", "csi_clk_mux" }, 4219e5d1581SAngeloGioacchino Del Regno .interrupt = "ispif" 4229e5d1581SAngeloGioacchino Del Regno }; 4239e5d1581SAngeloGioacchino Del Regno 4249e5d1581SAngeloGioacchino Del Regno static const struct resources vfe_res_660[] = { 4259e5d1581SAngeloGioacchino Del Regno /* VFE0 */ 4269e5d1581SAngeloGioacchino Del Regno { 4279e5d1581SAngeloGioacchino Del Regno .regulator = { NULL }, 4289e5d1581SAngeloGioacchino Del Regno .clock = { "throttle_axi", "top_ahb", "ahb", "vfe0", 4299e5d1581SAngeloGioacchino Del Regno "csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi", 4309e5d1581SAngeloGioacchino Del Regno "vfe0_stream"}, 4319e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 4329e5d1581SAngeloGioacchino Del Regno { 0 }, 4339e5d1581SAngeloGioacchino Del Regno { 0 }, 4349e5d1581SAngeloGioacchino Del Regno { 120000000, 200000000, 256000000, 4359e5d1581SAngeloGioacchino Del Regno 300000000, 404000000, 480000000, 4369e5d1581SAngeloGioacchino Del Regno 540000000, 576000000 }, 4379e5d1581SAngeloGioacchino Del Regno { 0 }, 4389e5d1581SAngeloGioacchino Del Regno { 0 }, 4399e5d1581SAngeloGioacchino Del Regno { 0 }, 4409e5d1581SAngeloGioacchino Del Regno { 0 }, 4419e5d1581SAngeloGioacchino Del Regno { 0 } }, 4429e5d1581SAngeloGioacchino Del Regno .reg = { "vfe0" }, 4439e5d1581SAngeloGioacchino Del Regno .interrupt = { "vfe0" } 4449e5d1581SAngeloGioacchino Del Regno }, 4459e5d1581SAngeloGioacchino Del Regno 4469e5d1581SAngeloGioacchino Del Regno /* VFE1 */ 4479e5d1581SAngeloGioacchino Del Regno { 4489e5d1581SAngeloGioacchino Del Regno .regulator = { NULL }, 4499e5d1581SAngeloGioacchino Del Regno .clock = { "throttle_axi", "top_ahb", "ahb", "vfe1", 4509e5d1581SAngeloGioacchino Del Regno "csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi", 4519e5d1581SAngeloGioacchino Del Regno "vfe1_stream"}, 4529e5d1581SAngeloGioacchino Del Regno .clock_rate = { { 0 }, 4539e5d1581SAngeloGioacchino Del Regno { 0 }, 4549e5d1581SAngeloGioacchino Del Regno { 0 }, 4559e5d1581SAngeloGioacchino Del Regno { 120000000, 200000000, 256000000, 4569e5d1581SAngeloGioacchino Del Regno 300000000, 404000000, 480000000, 4579e5d1581SAngeloGioacchino Del Regno 540000000, 576000000 }, 4589e5d1581SAngeloGioacchino Del Regno { 0 }, 4599e5d1581SAngeloGioacchino Del Regno { 0 }, 4609e5d1581SAngeloGioacchino Del Regno { 0 }, 4619e5d1581SAngeloGioacchino Del Regno { 0 }, 4629e5d1581SAngeloGioacchino Del Regno { 0 } }, 4639e5d1581SAngeloGioacchino Del Regno .reg = { "vfe1" }, 4649e5d1581SAngeloGioacchino Del Regno .interrupt = { "vfe1" } 4659e5d1581SAngeloGioacchino Del Regno } 4669e5d1581SAngeloGioacchino Del Regno }; 4679e5d1581SAngeloGioacchino Del Regno 4682f8b6719SRobert Foss static const struct resources csiphy_res_845[] = { 4692f8b6719SRobert Foss /* CSIPHY0 */ 4702f8b6719SRobert Foss { 4712f8b6719SRobert Foss .regulator = { NULL }, 4722f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 4732f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy0", 4742f8b6719SRobert Foss "csiphy0_timer_src", "csiphy0_timer" }, 4752f8b6719SRobert Foss .clock_rate = { { 0 }, 4762f8b6719SRobert Foss { 0 }, 4772f8b6719SRobert Foss { 0 }, 4782f8b6719SRobert Foss { 0 }, 4792f8b6719SRobert Foss { 0 }, 4802f8b6719SRobert Foss { 0 }, 4812f8b6719SRobert Foss { 0 }, 4822f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 4832f8b6719SRobert Foss .reg = { "csiphy0" }, 4842f8b6719SRobert Foss .interrupt = { "csiphy0" } 4852f8b6719SRobert Foss }, 4862f8b6719SRobert Foss 4872f8b6719SRobert Foss /* CSIPHY1 */ 4882f8b6719SRobert Foss { 4892f8b6719SRobert Foss .regulator = { NULL }, 4902f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 4912f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy1", 4922f8b6719SRobert Foss "csiphy1_timer_src", "csiphy1_timer" }, 4932f8b6719SRobert Foss .clock_rate = { { 0 }, 4942f8b6719SRobert Foss { 0 }, 4952f8b6719SRobert Foss { 0 }, 4962f8b6719SRobert Foss { 0 }, 4972f8b6719SRobert Foss { 0 }, 4982f8b6719SRobert Foss { 0 }, 4992f8b6719SRobert Foss { 0 }, 5002f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5012f8b6719SRobert Foss .reg = { "csiphy1" }, 5022f8b6719SRobert Foss .interrupt = { "csiphy1" } 5032f8b6719SRobert Foss }, 5042f8b6719SRobert Foss 5052f8b6719SRobert Foss /* CSIPHY2 */ 5062f8b6719SRobert Foss { 5072f8b6719SRobert Foss .regulator = { NULL }, 5082f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 5092f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy2", 5102f8b6719SRobert Foss "csiphy2_timer_src", "csiphy2_timer" }, 5112f8b6719SRobert Foss .clock_rate = { { 0 }, 5122f8b6719SRobert Foss { 0 }, 5132f8b6719SRobert Foss { 0 }, 5142f8b6719SRobert Foss { 0 }, 5152f8b6719SRobert Foss { 0 }, 5162f8b6719SRobert Foss { 0 }, 5172f8b6719SRobert Foss { 0 }, 5182f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5192f8b6719SRobert Foss .reg = { "csiphy2" }, 5202f8b6719SRobert Foss .interrupt = { "csiphy2" } 5212f8b6719SRobert Foss }, 5222f8b6719SRobert Foss 5232f8b6719SRobert Foss /* CSIPHY3 */ 5242f8b6719SRobert Foss { 5252f8b6719SRobert Foss .regulator = { NULL }, 5262f8b6719SRobert Foss .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", 5272f8b6719SRobert Foss "cpas_ahb", "cphy_rx_src", "csiphy3", 5282f8b6719SRobert Foss "csiphy3_timer_src", "csiphy3_timer" }, 5292f8b6719SRobert Foss .clock_rate = { { 0 }, 5302f8b6719SRobert Foss { 0 }, 5312f8b6719SRobert Foss { 0 }, 5322f8b6719SRobert Foss { 0 }, 5332f8b6719SRobert Foss { 0 }, 5342f8b6719SRobert Foss { 0 }, 5352f8b6719SRobert Foss { 0 }, 5362f8b6719SRobert Foss { 19200000, 240000000, 269333333 } }, 5372f8b6719SRobert Foss .reg = { "csiphy3" }, 5382f8b6719SRobert Foss .interrupt = { "csiphy3" } 5392f8b6719SRobert Foss } 5402f8b6719SRobert Foss }; 5412f8b6719SRobert Foss 542eebe6d00SRobert Foss static const struct resources csid_res_845[] = { 543eebe6d00SRobert Foss /* CSID0 */ 544eebe6d00SRobert Foss { 545661a1021SJonathan Marek .regulator = { NULL }, 546eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 547eebe6d00SRobert Foss "soc_ahb", "vfe0", "vfe0_src", 548eebe6d00SRobert Foss "vfe0_cphy_rx", "csi0", 549eebe6d00SRobert Foss "csi0_src" }, 550eebe6d00SRobert Foss .clock_rate = { { 0 }, 551eebe6d00SRobert Foss { 384000000 }, 552eebe6d00SRobert Foss { 80000000 }, 553eebe6d00SRobert Foss { 0 }, 554eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 555eebe6d00SRobert Foss { 320000000 }, 556eebe6d00SRobert Foss { 0 }, 557eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 558eebe6d00SRobert Foss { 384000000 } }, 559eebe6d00SRobert Foss .reg = { "csid0" }, 560eebe6d00SRobert Foss .interrupt = { "csid0" } 561eebe6d00SRobert Foss }, 562eebe6d00SRobert Foss 563eebe6d00SRobert Foss /* CSID1 */ 564eebe6d00SRobert Foss { 565661a1021SJonathan Marek .regulator = { NULL }, 566eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 567eebe6d00SRobert Foss "soc_ahb", "vfe1", "vfe1_src", 568eebe6d00SRobert Foss "vfe1_cphy_rx", "csi1", 569eebe6d00SRobert Foss "csi1_src" }, 570eebe6d00SRobert Foss .clock_rate = { { 0 }, 571eebe6d00SRobert Foss { 384000000 }, 572eebe6d00SRobert Foss { 80000000 }, 573eebe6d00SRobert Foss { 0 }, 574eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 575eebe6d00SRobert Foss { 320000000 }, 576eebe6d00SRobert Foss { 0 }, 577eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 578eebe6d00SRobert Foss { 384000000 } }, 579eebe6d00SRobert Foss .reg = { "csid1" }, 580eebe6d00SRobert Foss .interrupt = { "csid1" } 581eebe6d00SRobert Foss }, 582eebe6d00SRobert Foss 583eebe6d00SRobert Foss /* CSID2 */ 584eebe6d00SRobert Foss { 585661a1021SJonathan Marek .regulator = { NULL }, 586eebe6d00SRobert Foss .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", 587eebe6d00SRobert Foss "soc_ahb", "vfe_lite", "vfe_lite_src", 588eebe6d00SRobert Foss "vfe_lite_cphy_rx", "csi2", 589eebe6d00SRobert Foss "csi2_src" }, 590eebe6d00SRobert Foss .clock_rate = { { 0 }, 591eebe6d00SRobert Foss { 384000000 }, 592eebe6d00SRobert Foss { 80000000 }, 593eebe6d00SRobert Foss { 0 }, 594eebe6d00SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 595eebe6d00SRobert Foss { 320000000 }, 596eebe6d00SRobert Foss { 0 }, 597eebe6d00SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 598eebe6d00SRobert Foss { 384000000 } }, 599eebe6d00SRobert Foss .reg = { "csid2" }, 600eebe6d00SRobert Foss .interrupt = { "csid2" } 601eebe6d00SRobert Foss } 602eebe6d00SRobert Foss }; 603eebe6d00SRobert Foss 6047319cdf1SRobert Foss static const struct resources vfe_res_845[] = { 6057319cdf1SRobert Foss /* VFE0 */ 6067319cdf1SRobert Foss { 6077319cdf1SRobert Foss .regulator = { NULL }, 6087319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6097319cdf1SRobert Foss "soc_ahb", "vfe0", "vfe0_axi", 6107319cdf1SRobert Foss "vfe0_src", "csi0", 6117319cdf1SRobert Foss "csi0_src"}, 6127319cdf1SRobert Foss .clock_rate = { { 0 }, 6137319cdf1SRobert Foss { 0 }, 6147319cdf1SRobert Foss { 80000000 }, 6157319cdf1SRobert Foss { 0 }, 6167319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6177319cdf1SRobert Foss { 0 }, 6187319cdf1SRobert Foss { 320000000 }, 6197319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6207319cdf1SRobert Foss { 384000000 } }, 6217319cdf1SRobert Foss .reg = { "vfe0" }, 6227319cdf1SRobert Foss .interrupt = { "vfe0" } 6237319cdf1SRobert Foss }, 6247319cdf1SRobert Foss 6257319cdf1SRobert Foss /* VFE1 */ 6267319cdf1SRobert Foss { 6277319cdf1SRobert Foss .regulator = { NULL }, 6287319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6297319cdf1SRobert Foss "soc_ahb", "vfe1", "vfe1_axi", 6307319cdf1SRobert Foss "vfe1_src", "csi1", 6317319cdf1SRobert Foss "csi1_src"}, 6327319cdf1SRobert Foss .clock_rate = { { 0 }, 6337319cdf1SRobert Foss { 0 }, 6347319cdf1SRobert Foss { 80000000 }, 6357319cdf1SRobert Foss { 0 }, 6367319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6377319cdf1SRobert Foss { 0 }, 6387319cdf1SRobert Foss { 320000000 }, 6397319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6407319cdf1SRobert Foss { 384000000 } }, 6417319cdf1SRobert Foss .reg = { "vfe1" }, 6427319cdf1SRobert Foss .interrupt = { "vfe1" } 6437319cdf1SRobert Foss }, 6447319cdf1SRobert Foss 6457319cdf1SRobert Foss /* VFE-lite */ 6467319cdf1SRobert Foss { 6477319cdf1SRobert Foss .regulator = { NULL }, 6487319cdf1SRobert Foss .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", 6497319cdf1SRobert Foss "soc_ahb", "vfe_lite", 6507319cdf1SRobert Foss "vfe_lite_src", "csi2", 6517319cdf1SRobert Foss "csi2_src"}, 6527319cdf1SRobert Foss .clock_rate = { { 0 }, 6537319cdf1SRobert Foss { 0 }, 6547319cdf1SRobert Foss { 80000000 }, 6557319cdf1SRobert Foss { 0 }, 6567319cdf1SRobert Foss { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, 6577319cdf1SRobert Foss { 320000000 }, 6587319cdf1SRobert Foss { 19200000, 75000000, 384000000, 538666667 }, 6597319cdf1SRobert Foss { 384000000 } }, 6607319cdf1SRobert Foss .reg = { "vfe_lite" }, 6617319cdf1SRobert Foss .interrupt = { "vfe_lite" } 6627319cdf1SRobert Foss } 6637319cdf1SRobert Foss }; 6647319cdf1SRobert Foss 665*b4436a18SJonathan Marek static const struct resources csiphy_res_8250[] = { 666*b4436a18SJonathan Marek /* CSIPHY0 */ 667*b4436a18SJonathan Marek { 668*b4436a18SJonathan Marek .regulator = { NULL }, 669*b4436a18SJonathan Marek .clock = { "csiphy0", "csiphy0_timer" }, 670*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 671*b4436a18SJonathan Marek { 300000000 } }, 672*b4436a18SJonathan Marek .reg = { "csiphy0" }, 673*b4436a18SJonathan Marek .interrupt = { "csiphy0" } 674*b4436a18SJonathan Marek }, 675*b4436a18SJonathan Marek /* CSIPHY1 */ 676*b4436a18SJonathan Marek { 677*b4436a18SJonathan Marek .regulator = { NULL }, 678*b4436a18SJonathan Marek .clock = { "csiphy1", "csiphy1_timer" }, 679*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 680*b4436a18SJonathan Marek { 300000000 } }, 681*b4436a18SJonathan Marek .reg = { "csiphy1" }, 682*b4436a18SJonathan Marek .interrupt = { "csiphy1" } 683*b4436a18SJonathan Marek }, 684*b4436a18SJonathan Marek /* CSIPHY2 */ 685*b4436a18SJonathan Marek { 686*b4436a18SJonathan Marek .regulator = { NULL }, 687*b4436a18SJonathan Marek .clock = { "csiphy2", "csiphy2_timer" }, 688*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 689*b4436a18SJonathan Marek { 300000000 } }, 690*b4436a18SJonathan Marek .reg = { "csiphy2" }, 691*b4436a18SJonathan Marek .interrupt = { "csiphy2" } 692*b4436a18SJonathan Marek }, 693*b4436a18SJonathan Marek /* CSIPHY3 */ 694*b4436a18SJonathan Marek { 695*b4436a18SJonathan Marek .regulator = { NULL }, 696*b4436a18SJonathan Marek .clock = { "csiphy3", "csiphy3_timer" }, 697*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 698*b4436a18SJonathan Marek { 300000000 } }, 699*b4436a18SJonathan Marek .reg = { "csiphy3" }, 700*b4436a18SJonathan Marek .interrupt = { "csiphy3" } 701*b4436a18SJonathan Marek }, 702*b4436a18SJonathan Marek /* CSIPHY4 */ 703*b4436a18SJonathan Marek { 704*b4436a18SJonathan Marek .regulator = { NULL }, 705*b4436a18SJonathan Marek .clock = { "csiphy4", "csiphy4_timer" }, 706*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 707*b4436a18SJonathan Marek { 300000000 } }, 708*b4436a18SJonathan Marek .reg = { "csiphy4" }, 709*b4436a18SJonathan Marek .interrupt = { "csiphy4" } 710*b4436a18SJonathan Marek }, 711*b4436a18SJonathan Marek /* CSIPHY5 */ 712*b4436a18SJonathan Marek { 713*b4436a18SJonathan Marek .regulator = { NULL }, 714*b4436a18SJonathan Marek .clock = { "csiphy5", "csiphy5_timer" }, 715*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 716*b4436a18SJonathan Marek { 300000000 } }, 717*b4436a18SJonathan Marek .reg = { "csiphy5" }, 718*b4436a18SJonathan Marek .interrupt = { "csiphy5" } 719*b4436a18SJonathan Marek } 720*b4436a18SJonathan Marek }; 721*b4436a18SJonathan Marek 722*b4436a18SJonathan Marek static const struct resources csid_res_8250[] = { 723*b4436a18SJonathan Marek /* CSID0 */ 724*b4436a18SJonathan Marek { 725*b4436a18SJonathan Marek .regulator = { NULL }, 726*b4436a18SJonathan Marek .clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" }, 727*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 728*b4436a18SJonathan Marek { 400000000 }, 729*b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 730*b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 731*b4436a18SJonathan Marek { 0 } }, 732*b4436a18SJonathan Marek .reg = { "csid0" }, 733*b4436a18SJonathan Marek .interrupt = { "csid0" } 734*b4436a18SJonathan Marek }, 735*b4436a18SJonathan Marek /* CSID1 */ 736*b4436a18SJonathan Marek { 737*b4436a18SJonathan Marek .regulator = { NULL }, 738*b4436a18SJonathan Marek .clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" }, 739*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 740*b4436a18SJonathan Marek { 400000000 }, 741*b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 742*b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 743*b4436a18SJonathan Marek { 0 } }, 744*b4436a18SJonathan Marek .reg = { "csid1" }, 745*b4436a18SJonathan Marek .interrupt = { "csid1" } 746*b4436a18SJonathan Marek }, 747*b4436a18SJonathan Marek /* CSID2 */ 748*b4436a18SJonathan Marek { 749*b4436a18SJonathan Marek .regulator = { NULL }, 750*b4436a18SJonathan Marek .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, 751*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 752*b4436a18SJonathan Marek { 400000000 }, 753*b4436a18SJonathan Marek { 400000000, 480000000 }, 754*b4436a18SJonathan Marek { 0 } }, 755*b4436a18SJonathan Marek .reg = { "csid2" }, 756*b4436a18SJonathan Marek .interrupt = { "csid2" } 757*b4436a18SJonathan Marek }, 758*b4436a18SJonathan Marek /* CSID3 */ 759*b4436a18SJonathan Marek { 760*b4436a18SJonathan Marek .regulator = { NULL }, 761*b4436a18SJonathan Marek .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, 762*b4436a18SJonathan Marek .clock_rate = { { 400000000 }, 763*b4436a18SJonathan Marek { 400000000 }, 764*b4436a18SJonathan Marek { 400000000, 480000000 }, 765*b4436a18SJonathan Marek { 0 } }, 766*b4436a18SJonathan Marek .reg = { "csid3" }, 767*b4436a18SJonathan Marek .interrupt = { "csid3" } 768*b4436a18SJonathan Marek } 769*b4436a18SJonathan Marek }; 770*b4436a18SJonathan Marek 771*b4436a18SJonathan Marek static const struct resources vfe_res_8250[] = { 772*b4436a18SJonathan Marek /* VFE0 */ 773*b4436a18SJonathan Marek { 774*b4436a18SJonathan Marek .regulator = { NULL }, 775*b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 776*b4436a18SJonathan Marek "camnoc_axi", "vfe0_ahb", "vfe0_areg", "vfe0", 777*b4436a18SJonathan Marek "vfe0_axi", "cam_hf_axi" }, 778*b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 779*b4436a18SJonathan Marek { 19200000, 80000000 }, 780*b4436a18SJonathan Marek { 19200000 }, 781*b4436a18SJonathan Marek { 0 }, 782*b4436a18SJonathan Marek { 0 }, 783*b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 784*b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 785*b4436a18SJonathan Marek { 0 }, 786*b4436a18SJonathan Marek { 0 } }, 787*b4436a18SJonathan Marek .reg = { "vfe0" }, 788*b4436a18SJonathan Marek .interrupt = { "vfe0" } 789*b4436a18SJonathan Marek }, 790*b4436a18SJonathan Marek /* VFE1 */ 791*b4436a18SJonathan Marek { 792*b4436a18SJonathan Marek .regulator = { NULL }, 793*b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 794*b4436a18SJonathan Marek "camnoc_axi", "vfe1_ahb", "vfe1_areg", "vfe1", 795*b4436a18SJonathan Marek "vfe1_axi", "cam_hf_axi" }, 796*b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 797*b4436a18SJonathan Marek { 19200000, 80000000 }, 798*b4436a18SJonathan Marek { 19200000 }, 799*b4436a18SJonathan Marek { 0 }, 800*b4436a18SJonathan Marek { 0 }, 801*b4436a18SJonathan Marek { 100000000, 200000000, 300000000, 400000000 }, 802*b4436a18SJonathan Marek { 350000000, 475000000, 576000000, 720000000 }, 803*b4436a18SJonathan Marek { 0 }, 804*b4436a18SJonathan Marek { 0 } }, 805*b4436a18SJonathan Marek .reg = { "vfe1" }, 806*b4436a18SJonathan Marek .interrupt = { "vfe1" } 807*b4436a18SJonathan Marek }, 808*b4436a18SJonathan Marek /* VFE2 (lite) */ 809*b4436a18SJonathan Marek { 810*b4436a18SJonathan Marek .regulator = { NULL }, 811*b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 812*b4436a18SJonathan Marek "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi", 813*b4436a18SJonathan Marek "vfe_lite", "cam_hf_axi" }, 814*b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 815*b4436a18SJonathan Marek { 19200000, 80000000 }, 816*b4436a18SJonathan Marek { 19200000 }, 817*b4436a18SJonathan Marek { 0 }, 818*b4436a18SJonathan Marek { 0 }, 819*b4436a18SJonathan Marek { 0 }, 820*b4436a18SJonathan Marek { 400000000, 480000000 }, 821*b4436a18SJonathan Marek { 0 } }, 822*b4436a18SJonathan Marek .reg = { "vfe_lite0" }, 823*b4436a18SJonathan Marek .interrupt = { "vfe_lite0" } 824*b4436a18SJonathan Marek }, 825*b4436a18SJonathan Marek /* VFE3 (lite) */ 826*b4436a18SJonathan Marek { 827*b4436a18SJonathan Marek .regulator = { NULL }, 828*b4436a18SJonathan Marek .clock = { "camnoc_axi_src", "slow_ahb_src", "cpas_ahb", 829*b4436a18SJonathan Marek "camnoc_axi", "vfe_lite_ahb", "vfe_lite_axi", 830*b4436a18SJonathan Marek "vfe_lite", "cam_hf_axi" }, 831*b4436a18SJonathan Marek .clock_rate = { { 19200000, 300000000, 400000000, 480000000 }, 832*b4436a18SJonathan Marek { 19200000, 80000000 }, 833*b4436a18SJonathan Marek { 19200000 }, 834*b4436a18SJonathan Marek { 0 }, 835*b4436a18SJonathan Marek { 0 }, 836*b4436a18SJonathan Marek { 0 }, 837*b4436a18SJonathan Marek { 400000000, 480000000 }, 838*b4436a18SJonathan Marek { 0 } }, 839*b4436a18SJonathan Marek .reg = { "vfe_lite1" }, 840*b4436a18SJonathan Marek .interrupt = { "vfe_lite1" } 841*b4436a18SJonathan Marek }, 842*b4436a18SJonathan Marek }; 843*b4436a18SJonathan Marek 844ec6859b2STodor Tomov /* 845ec6859b2STodor Tomov * camss_add_clock_margin - Add margin to clock frequency rate 846ec6859b2STodor Tomov * @rate: Clock frequency rate 847ec6859b2STodor Tomov * 848ec6859b2STodor Tomov * When making calculations with physical clock frequency values 849ec6859b2STodor Tomov * some safety margin must be added. Add it. 850ec6859b2STodor Tomov */ 851ec6859b2STodor Tomov inline void camss_add_clock_margin(u64 *rate) 852ec6859b2STodor Tomov { 853ec6859b2STodor Tomov *rate *= CAMSS_CLOCK_MARGIN_NUMERATOR; 854ec6859b2STodor Tomov *rate = div_u64(*rate, CAMSS_CLOCK_MARGIN_DENOMINATOR); 855ec6859b2STodor Tomov } 856ec6859b2STodor Tomov 857ec6859b2STodor Tomov /* 858ec6859b2STodor Tomov * camss_enable_clocks - Enable multiple clocks 859ec6859b2STodor Tomov * @nclocks: Number of clocks in clock array 860ec6859b2STodor Tomov * @clock: Clock array 861ec6859b2STodor Tomov * @dev: Device 862ec6859b2STodor Tomov * 863ec6859b2STodor Tomov * Return 0 on success or a negative error code otherwise 864ec6859b2STodor Tomov */ 865ec6859b2STodor Tomov int camss_enable_clocks(int nclocks, struct camss_clock *clock, 866ec6859b2STodor Tomov struct device *dev) 867ec6859b2STodor Tomov { 868ec6859b2STodor Tomov int ret; 869ec6859b2STodor Tomov int i; 870ec6859b2STodor Tomov 871ec6859b2STodor Tomov for (i = 0; i < nclocks; i++) { 872ec6859b2STodor Tomov ret = clk_prepare_enable(clock[i].clk); 873ec6859b2STodor Tomov if (ret) { 874ec6859b2STodor Tomov dev_err(dev, "clock enable failed: %d\n", ret); 875ec6859b2STodor Tomov goto error; 876ec6859b2STodor Tomov } 877ec6859b2STodor Tomov } 878ec6859b2STodor Tomov 879ec6859b2STodor Tomov return 0; 880ec6859b2STodor Tomov 881ec6859b2STodor Tomov error: 882ec6859b2STodor Tomov for (i--; i >= 0; i--) 883ec6859b2STodor Tomov clk_disable_unprepare(clock[i].clk); 884ec6859b2STodor Tomov 885ec6859b2STodor Tomov return ret; 886ec6859b2STodor Tomov } 887ec6859b2STodor Tomov 888ec6859b2STodor Tomov /* 889ec6859b2STodor Tomov * camss_disable_clocks - Disable multiple clocks 890ec6859b2STodor Tomov * @nclocks: Number of clocks in clock array 891ec6859b2STodor Tomov * @clock: Clock array 892ec6859b2STodor Tomov */ 893ec6859b2STodor Tomov void camss_disable_clocks(int nclocks, struct camss_clock *clock) 894ec6859b2STodor Tomov { 895ec6859b2STodor Tomov int i; 896ec6859b2STodor Tomov 897ec6859b2STodor Tomov for (i = nclocks - 1; i >= 0; i--) 898ec6859b2STodor Tomov clk_disable_unprepare(clock[i].clk); 899ec6859b2STodor Tomov } 900ec6859b2STodor Tomov 901ec6859b2STodor Tomov /* 902ec6859b2STodor Tomov * camss_find_sensor - Find a linked media entity which represents a sensor 903ec6859b2STodor Tomov * @entity: Media entity to start searching from 904ec6859b2STodor Tomov * 905ec6859b2STodor Tomov * Return a pointer to sensor media entity or NULL if not found 906ec6859b2STodor Tomov */ 90725f5c34bSTodor Tomov struct media_entity *camss_find_sensor(struct media_entity *entity) 908ec6859b2STodor Tomov { 909ec6859b2STodor Tomov struct media_pad *pad; 910ec6859b2STodor Tomov 911ec6859b2STodor Tomov while (1) { 912ec6859b2STodor Tomov pad = &entity->pads[0]; 913ec6859b2STodor Tomov if (!(pad->flags & MEDIA_PAD_FL_SINK)) 914ec6859b2STodor Tomov return NULL; 915ec6859b2STodor Tomov 916ec6859b2STodor Tomov pad = media_entity_remote_pad(pad); 917ec6859b2STodor Tomov if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) 918ec6859b2STodor Tomov return NULL; 919ec6859b2STodor Tomov 920ec6859b2STodor Tomov entity = pad->entity; 921ec6859b2STodor Tomov 922ec6859b2STodor Tomov if (entity->function == MEDIA_ENT_F_CAM_SENSOR) 923ec6859b2STodor Tomov return entity; 924ec6859b2STodor Tomov } 925ec6859b2STodor Tomov } 926ec6859b2STodor Tomov 92778c2cc28SAndrey Konovalov /** 92878c2cc28SAndrey Konovalov * camss_get_link_freq - Get link frequency from sensor 92978c2cc28SAndrey Konovalov * @entity: Media entity in the current pipeline 93078c2cc28SAndrey Konovalov * @bpp: Number of bits per pixel for the current format 93178c2cc28SAndrey Konovalov * @lanes: Number of lanes in the link to the sensor 93278c2cc28SAndrey Konovalov * 93378c2cc28SAndrey Konovalov * Return link frequency on success or a negative error code otherwise 93478c2cc28SAndrey Konovalov */ 93578c2cc28SAndrey Konovalov s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, 93678c2cc28SAndrey Konovalov unsigned int lanes) 93778c2cc28SAndrey Konovalov { 93878c2cc28SAndrey Konovalov struct media_entity *sensor; 93978c2cc28SAndrey Konovalov struct v4l2_subdev *subdev; 94078c2cc28SAndrey Konovalov 94178c2cc28SAndrey Konovalov sensor = camss_find_sensor(entity); 94278c2cc28SAndrey Konovalov if (!sensor) 94378c2cc28SAndrey Konovalov return -ENODEV; 94478c2cc28SAndrey Konovalov 94578c2cc28SAndrey Konovalov subdev = media_entity_to_v4l2_subdev(sensor); 94678c2cc28SAndrey Konovalov 94778c2cc28SAndrey Konovalov return v4l2_get_link_freq(subdev->ctrl_handler, bpp, 2 * lanes); 94878c2cc28SAndrey Konovalov } 94978c2cc28SAndrey Konovalov 950ec6859b2STodor Tomov /* 951ec6859b2STodor Tomov * camss_get_pixel_clock - Get pixel clock rate from sensor 952ec6859b2STodor Tomov * @entity: Media entity in the current pipeline 953ec6859b2STodor Tomov * @pixel_clock: Received pixel clock value 954ec6859b2STodor Tomov * 955ec6859b2STodor Tomov * Return 0 on success or a negative error code otherwise 956ec6859b2STodor Tomov */ 9572f908577SVladimir Lypak int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock) 958ec6859b2STodor Tomov { 959ec6859b2STodor Tomov struct media_entity *sensor; 960ec6859b2STodor Tomov struct v4l2_subdev *subdev; 961ec6859b2STodor Tomov struct v4l2_ctrl *ctrl; 962ec6859b2STodor Tomov 963ec6859b2STodor Tomov sensor = camss_find_sensor(entity); 964ec6859b2STodor Tomov if (!sensor) 965ec6859b2STodor Tomov return -ENODEV; 966ec6859b2STodor Tomov 967ec6859b2STodor Tomov subdev = media_entity_to_v4l2_subdev(sensor); 968ec6859b2STodor Tomov 969ec6859b2STodor Tomov ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); 970ec6859b2STodor Tomov 971ec6859b2STodor Tomov if (!ctrl) 972ec6859b2STodor Tomov return -EINVAL; 973ec6859b2STodor Tomov 974ec6859b2STodor Tomov *pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); 975ec6859b2STodor Tomov 976ec6859b2STodor Tomov return 0; 977ec6859b2STodor Tomov } 978ec6859b2STodor Tomov 97902afa816STodor Tomov int camss_pm_domain_on(struct camss *camss, int id) 98002afa816STodor Tomov { 9812f6f8af6SRobert Foss int ret = 0; 98202afa816STodor Tomov 9832f6f8af6SRobert Foss if (id < camss->vfe_num) { 9842f6f8af6SRobert Foss struct vfe_device *vfe = &camss->vfe[id]; 9852f6f8af6SRobert Foss 9862f6f8af6SRobert Foss ret = vfe->ops->pm_domain_on(vfe); 98702afa816STodor Tomov } 98802afa816STodor Tomov 9892f6f8af6SRobert Foss return ret; 99002afa816STodor Tomov } 99102afa816STodor Tomov 99202afa816STodor Tomov void camss_pm_domain_off(struct camss *camss, int id) 99302afa816STodor Tomov { 9942f6f8af6SRobert Foss if (id < camss->vfe_num) { 9952f6f8af6SRobert Foss struct vfe_device *vfe = &camss->vfe[id]; 9962f6f8af6SRobert Foss 9972f6f8af6SRobert Foss vfe->ops->pm_domain_off(vfe); 9982f6f8af6SRobert Foss } 99902afa816STodor Tomov } 100002afa816STodor Tomov 1001ec6859b2STodor Tomov /* 1002ec6859b2STodor Tomov * camss_of_parse_endpoint_node - Parse port endpoint node 1003ec6859b2STodor Tomov * @dev: Device 1004ec6859b2STodor Tomov * @node: Device node to be parsed 1005ec6859b2STodor Tomov * @csd: Parsed data from port endpoint node 1006ec6859b2STodor Tomov * 1007ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1008ec6859b2STodor Tomov */ 1009ec6859b2STodor Tomov static int camss_of_parse_endpoint_node(struct device *dev, 1010ec6859b2STodor Tomov struct device_node *node, 1011ec6859b2STodor Tomov struct camss_async_subdev *csd) 1012ec6859b2STodor Tomov { 1013ec6859b2STodor Tomov struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; 1014ec6859b2STodor Tomov struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2; 1015ec6859b2STodor Tomov struct v4l2_fwnode_endpoint vep = { { 0 } }; 1016ec6859b2STodor Tomov unsigned int i; 1017ec6859b2STodor Tomov 1018ec6859b2STodor Tomov v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); 1019ec6859b2STodor Tomov 1020ec6859b2STodor Tomov csd->interface.csiphy_id = vep.base.port; 1021ec6859b2STodor Tomov 1022ec6859b2STodor Tomov mipi_csi2 = &vep.bus.mipi_csi2; 1023ec6859b2STodor Tomov lncfg->clk.pos = mipi_csi2->clock_lane; 1024ec6859b2STodor Tomov lncfg->clk.pol = mipi_csi2->lane_polarities[0]; 1025ec6859b2STodor Tomov lncfg->num_data = mipi_csi2->num_data_lanes; 1026ec6859b2STodor Tomov 1027ec6859b2STodor Tomov lncfg->data = devm_kcalloc(dev, 1028ec6859b2STodor Tomov lncfg->num_data, sizeof(*lncfg->data), 1029ec6859b2STodor Tomov GFP_KERNEL); 1030ec6859b2STodor Tomov if (!lncfg->data) 1031ec6859b2STodor Tomov return -ENOMEM; 1032ec6859b2STodor Tomov 1033ec6859b2STodor Tomov for (i = 0; i < lncfg->num_data; i++) { 1034ec6859b2STodor Tomov lncfg->data[i].pos = mipi_csi2->data_lanes[i]; 1035ec6859b2STodor Tomov lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1]; 1036ec6859b2STodor Tomov } 1037ec6859b2STodor Tomov 1038ec6859b2STodor Tomov return 0; 1039ec6859b2STodor Tomov } 1040ec6859b2STodor Tomov 1041ec6859b2STodor Tomov /* 1042ec6859b2STodor Tomov * camss_of_parse_ports - Parse ports node 1043ec6859b2STodor Tomov * @dev: Device 1044ec6859b2STodor Tomov * @notifier: v4l2_device notifier data 1045ec6859b2STodor Tomov * 1046ec6859b2STodor Tomov * Return number of "port" nodes found in "ports" node 1047ec6859b2STodor Tomov */ 1048d079f94cSSteve Longerbeam static int camss_of_parse_ports(struct camss *camss) 1049ec6859b2STodor Tomov { 1050d079f94cSSteve Longerbeam struct device *dev = camss->dev; 1051ec6859b2STodor Tomov struct device_node *node = NULL; 1052ec6859b2STodor Tomov struct device_node *remote = NULL; 1053d079f94cSSteve Longerbeam int ret, num_subdevs = 0; 1054ec6859b2STodor Tomov 1055d079f94cSSteve Longerbeam for_each_endpoint_of_node(dev->of_node, node) { 1056ec6859b2STodor Tomov struct camss_async_subdev *csd; 1057ec6859b2STodor Tomov 1058ec6859b2STodor Tomov if (!of_device_is_available(node)) 1059ec6859b2STodor Tomov continue; 1060ec6859b2STodor Tomov 1061ec6859b2STodor Tomov remote = of_graph_get_remote_port_parent(node); 1062ec6859b2STodor Tomov if (!remote) { 1063ec6859b2STodor Tomov dev_err(dev, "Cannot get remote parent\n"); 1064d079f94cSSteve Longerbeam ret = -EINVAL; 1065d079f94cSSteve Longerbeam goto err_cleanup; 1066ec6859b2STodor Tomov } 1067ec6859b2STodor Tomov 10683c8c1539SSakari Ailus csd = v4l2_async_nf_add_fwnode(&camss->notifier, 10693c8c1539SSakari Ailus of_fwnode_handle(remote), 1070b01edcbdSLaurent Pinchart struct camss_async_subdev); 1071016413d9SSakari Ailus of_node_put(remote); 1072b01edcbdSLaurent Pinchart if (IS_ERR(csd)) { 1073b01edcbdSLaurent Pinchart ret = PTR_ERR(csd); 1074d079f94cSSteve Longerbeam goto err_cleanup; 1075ec6859b2STodor Tomov } 1076ec6859b2STodor Tomov 1077d079f94cSSteve Longerbeam ret = camss_of_parse_endpoint_node(dev, node, csd); 1078d079f94cSSteve Longerbeam if (ret < 0) 1079d079f94cSSteve Longerbeam goto err_cleanup; 1080d079f94cSSteve Longerbeam 1081d079f94cSSteve Longerbeam num_subdevs++; 1082d079f94cSSteve Longerbeam } 1083d079f94cSSteve Longerbeam 1084d079f94cSSteve Longerbeam return num_subdevs; 1085d079f94cSSteve Longerbeam 1086d079f94cSSteve Longerbeam err_cleanup: 1087d079f94cSSteve Longerbeam of_node_put(node); 1088d079f94cSSteve Longerbeam return ret; 1089ec6859b2STodor Tomov } 1090ec6859b2STodor Tomov 1091ec6859b2STodor Tomov /* 1092ec6859b2STodor Tomov * camss_init_subdevices - Initialize subdev structures and resources 1093ec6859b2STodor Tomov * @camss: CAMSS device 1094ec6859b2STodor Tomov * 1095ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1096ec6859b2STodor Tomov */ 1097ec6859b2STodor Tomov static int camss_init_subdevices(struct camss *camss) 1098ec6859b2STodor Tomov { 10999c3e59deSTodor Tomov const struct resources *csiphy_res; 11009c3e59deSTodor Tomov const struct resources *csid_res; 11019c3e59deSTodor Tomov const struct resources_ispif *ispif_res; 11029c3e59deSTodor Tomov const struct resources *vfe_res; 1103ec6859b2STodor Tomov unsigned int i; 1104ec6859b2STodor Tomov int ret; 1105ec6859b2STodor Tomov 11069c3e59deSTodor Tomov if (camss->version == CAMSS_8x16) { 11079c3e59deSTodor Tomov csiphy_res = csiphy_res_8x16; 11089c3e59deSTodor Tomov csid_res = csid_res_8x16; 11099c3e59deSTodor Tomov ispif_res = &ispif_res_8x16; 11109c3e59deSTodor Tomov vfe_res = vfe_res_8x16; 11119c3e59deSTodor Tomov } else if (camss->version == CAMSS_8x96) { 11129c3e59deSTodor Tomov csiphy_res = csiphy_res_8x96; 11139c3e59deSTodor Tomov csid_res = csid_res_8x96; 11149c3e59deSTodor Tomov ispif_res = &ispif_res_8x96; 11159c3e59deSTodor Tomov vfe_res = vfe_res_8x96; 11169e5d1581SAngeloGioacchino Del Regno } else if (camss->version == CAMSS_660) { 11179e5d1581SAngeloGioacchino Del Regno csiphy_res = csiphy_res_660; 11189e5d1581SAngeloGioacchino Del Regno csid_res = csid_res_660; 11199e5d1581SAngeloGioacchino Del Regno ispif_res = &ispif_res_660; 11209e5d1581SAngeloGioacchino Del Regno vfe_res = vfe_res_660; 112170524567SRobert Foss } else if (camss->version == CAMSS_845) { 112270524567SRobert Foss csiphy_res = csiphy_res_845; 112370524567SRobert Foss csid_res = csid_res_845; 112470524567SRobert Foss /* Titan VFEs don't have an ISPIF */ 112570524567SRobert Foss ispif_res = NULL; 112670524567SRobert Foss vfe_res = vfe_res_845; 1127*b4436a18SJonathan Marek } else if (camss->version == CAMSS_8250) { 1128*b4436a18SJonathan Marek csiphy_res = csiphy_res_8250; 1129*b4436a18SJonathan Marek csid_res = csid_res_8250; 1130*b4436a18SJonathan Marek /* Titan VFEs don't have an ISPIF */ 1131*b4436a18SJonathan Marek ispif_res = NULL; 1132*b4436a18SJonathan Marek vfe_res = vfe_res_8250; 11339c3e59deSTodor Tomov } else { 11349c3e59deSTodor Tomov return -EINVAL; 11359c3e59deSTodor Tomov } 11369c3e59deSTodor Tomov 11379c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 11389c3e59deSTodor Tomov ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], 1139ec6859b2STodor Tomov &csiphy_res[i], i); 1140ec6859b2STodor Tomov if (ret < 0) { 1141ec6859b2STodor Tomov dev_err(camss->dev, 1142ec6859b2STodor Tomov "Failed to init csiphy%d sub-device: %d\n", 1143ec6859b2STodor Tomov i, ret); 1144ec6859b2STodor Tomov return ret; 1145ec6859b2STodor Tomov } 1146ec6859b2STodor Tomov } 1147ec6859b2STodor Tomov 1148*b4436a18SJonathan Marek /* note: SM8250 requires VFE to be initialized before CSID */ 1149*b4436a18SJonathan Marek for (i = 0; i < camss->vfe_num; i++) { 1150*b4436a18SJonathan Marek ret = msm_vfe_subdev_init(camss, &camss->vfe[i], 1151*b4436a18SJonathan Marek &vfe_res[i], i); 1152*b4436a18SJonathan Marek if (ret < 0) { 1153*b4436a18SJonathan Marek dev_err(camss->dev, 1154*b4436a18SJonathan Marek "Fail to init vfe%d sub-device: %d\n", i, ret); 1155*b4436a18SJonathan Marek return ret; 1156*b4436a18SJonathan Marek } 1157*b4436a18SJonathan Marek } 1158*b4436a18SJonathan Marek 11599c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 11609c3e59deSTodor Tomov ret = msm_csid_subdev_init(camss, &camss->csid[i], 1161ec6859b2STodor Tomov &csid_res[i], i); 1162ec6859b2STodor Tomov if (ret < 0) { 1163ec6859b2STodor Tomov dev_err(camss->dev, 1164ec6859b2STodor Tomov "Failed to init csid%d sub-device: %d\n", 1165ec6859b2STodor Tomov i, ret); 1166ec6859b2STodor Tomov return ret; 1167ec6859b2STodor Tomov } 1168ec6859b2STodor Tomov } 1169ec6859b2STodor Tomov 11709d95baf9SRobert Foss ret = msm_ispif_subdev_init(camss, ispif_res); 1171ec6859b2STodor Tomov if (ret < 0) { 1172ec6859b2STodor Tomov dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", 1173ec6859b2STodor Tomov ret); 1174ec6859b2STodor Tomov return ret; 1175ec6859b2STodor Tomov } 1176ec6859b2STodor Tomov 1177ec6859b2STodor Tomov return 0; 1178ec6859b2STodor Tomov } 1179ec6859b2STodor Tomov 1180ec6859b2STodor Tomov /* 1181ec6859b2STodor Tomov * camss_register_entities - Register subdev nodes and create links 1182ec6859b2STodor Tomov * @camss: CAMSS device 1183ec6859b2STodor Tomov * 1184ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1185ec6859b2STodor Tomov */ 1186ec6859b2STodor Tomov static int camss_register_entities(struct camss *camss) 1187ec6859b2STodor Tomov { 11889c3e59deSTodor Tomov int i, j, k; 1189ec6859b2STodor Tomov int ret; 1190ec6859b2STodor Tomov 11919c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 1192ec6859b2STodor Tomov ret = msm_csiphy_register_entity(&camss->csiphy[i], 1193ec6859b2STodor Tomov &camss->v4l2_dev); 1194ec6859b2STodor Tomov if (ret < 0) { 1195ec6859b2STodor Tomov dev_err(camss->dev, 1196ec6859b2STodor Tomov "Failed to register csiphy%d entity: %d\n", 1197ec6859b2STodor Tomov i, ret); 1198ec6859b2STodor Tomov goto err_reg_csiphy; 1199ec6859b2STodor Tomov } 1200ec6859b2STodor Tomov } 1201ec6859b2STodor Tomov 12029c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 1203ec6859b2STodor Tomov ret = msm_csid_register_entity(&camss->csid[i], 1204ec6859b2STodor Tomov &camss->v4l2_dev); 1205ec6859b2STodor Tomov if (ret < 0) { 1206ec6859b2STodor Tomov dev_err(camss->dev, 1207ec6859b2STodor Tomov "Failed to register csid%d entity: %d\n", 1208ec6859b2STodor Tomov i, ret); 1209ec6859b2STodor Tomov goto err_reg_csid; 1210ec6859b2STodor Tomov } 1211ec6859b2STodor Tomov } 1212ec6859b2STodor Tomov 12139d95baf9SRobert Foss ret = msm_ispif_register_entities(camss->ispif, 12149d95baf9SRobert Foss &camss->v4l2_dev); 1215ec6859b2STodor Tomov if (ret < 0) { 1216ec6859b2STodor Tomov dev_err(camss->dev, "Failed to register ispif entities: %d\n", 1217ec6859b2STodor Tomov ret); 1218ec6859b2STodor Tomov goto err_reg_ispif; 1219ec6859b2STodor Tomov } 1220ec6859b2STodor Tomov 12219c3e59deSTodor Tomov for (i = 0; i < camss->vfe_num; i++) { 12229c3e59deSTodor Tomov ret = msm_vfe_register_entities(&camss->vfe[i], 12239c3e59deSTodor Tomov &camss->v4l2_dev); 1224ec6859b2STodor Tomov if (ret < 0) { 12259c3e59deSTodor Tomov dev_err(camss->dev, 12269c3e59deSTodor Tomov "Failed to register vfe%d entities: %d\n", 12279c3e59deSTodor Tomov i, ret); 1228ec6859b2STodor Tomov goto err_reg_vfe; 1229ec6859b2STodor Tomov } 12309c3e59deSTodor Tomov } 1231ec6859b2STodor Tomov 12329c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) { 12339c3e59deSTodor Tomov for (j = 0; j < camss->csid_num; j++) { 1234ec6859b2STodor Tomov ret = media_create_pad_link( 1235ec6859b2STodor Tomov &camss->csiphy[i].subdev.entity, 1236ec6859b2STodor Tomov MSM_CSIPHY_PAD_SRC, 1237ec6859b2STodor Tomov &camss->csid[j].subdev.entity, 1238ec6859b2STodor Tomov MSM_CSID_PAD_SINK, 1239ec6859b2STodor Tomov 0); 1240ec6859b2STodor Tomov if (ret < 0) { 1241ec6859b2STodor Tomov dev_err(camss->dev, 1242ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1243ec6859b2STodor Tomov camss->csiphy[i].subdev.entity.name, 1244ec6859b2STodor Tomov camss->csid[j].subdev.entity.name, 1245ec6859b2STodor Tomov ret); 1246ec6859b2STodor Tomov goto err_link; 1247ec6859b2STodor Tomov } 1248ec6859b2STodor Tomov } 1249ec6859b2STodor Tomov } 1250ec6859b2STodor Tomov 12519d95baf9SRobert Foss if (camss->ispif) { 12529c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) { 12539d95baf9SRobert Foss for (j = 0; j < camss->ispif->line_num; j++) { 1254ec6859b2STodor Tomov ret = media_create_pad_link( 1255ec6859b2STodor Tomov &camss->csid[i].subdev.entity, 1256ec6859b2STodor Tomov MSM_CSID_PAD_SRC, 12579d95baf9SRobert Foss &camss->ispif->line[j].subdev.entity, 1258ec6859b2STodor Tomov MSM_ISPIF_PAD_SINK, 1259ec6859b2STodor Tomov 0); 1260ec6859b2STodor Tomov if (ret < 0) { 1261ec6859b2STodor Tomov dev_err(camss->dev, 1262ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1263ec6859b2STodor Tomov camss->csid[i].subdev.entity.name, 12649d95baf9SRobert Foss camss->ispif->line[j].subdev.entity.name, 1265ec6859b2STodor Tomov ret); 1266ec6859b2STodor Tomov goto err_link; 1267ec6859b2STodor Tomov } 1268ec6859b2STodor Tomov } 1269ec6859b2STodor Tomov } 1270ec6859b2STodor Tomov 12719d95baf9SRobert Foss for (i = 0; i < camss->ispif->line_num; i++) 12729c3e59deSTodor Tomov for (k = 0; k < camss->vfe_num; k++) 1273633b388fSRobert Foss for (j = 0; j < camss->vfe[k].line_num; j++) { 12749d95baf9SRobert Foss struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev; 12759d95baf9SRobert Foss struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; 12769d95baf9SRobert Foss 12779d95baf9SRobert Foss ret = media_create_pad_link(&ispif->entity, 1278ec6859b2STodor Tomov MSM_ISPIF_PAD_SRC, 12799d95baf9SRobert Foss &vfe->entity, 1280ec6859b2STodor Tomov MSM_VFE_PAD_SINK, 1281ec6859b2STodor Tomov 0); 1282ec6859b2STodor Tomov if (ret < 0) { 1283ec6859b2STodor Tomov dev_err(camss->dev, 1284ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 12859d95baf9SRobert Foss ispif->entity.name, 12869d95baf9SRobert Foss vfe->entity.name, 1287ec6859b2STodor Tomov ret); 1288ec6859b2STodor Tomov goto err_link; 1289ec6859b2STodor Tomov } 1290ec6859b2STodor Tomov } 12919d95baf9SRobert Foss } else { 12929d95baf9SRobert Foss for (i = 0; i < camss->csid_num; i++) 12939d95baf9SRobert Foss for (k = 0; k < camss->vfe_num; k++) 1294633b388fSRobert Foss for (j = 0; j < camss->vfe[k].line_num; j++) { 12959d95baf9SRobert Foss struct v4l2_subdev *csid = &camss->csid[i].subdev; 12969d95baf9SRobert Foss struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; 12979d95baf9SRobert Foss 12989d95baf9SRobert Foss ret = media_create_pad_link(&csid->entity, 12999d95baf9SRobert Foss MSM_CSID_PAD_SRC, 13009d95baf9SRobert Foss &vfe->entity, 13019d95baf9SRobert Foss MSM_VFE_PAD_SINK, 13029d95baf9SRobert Foss 0); 13039d95baf9SRobert Foss if (ret < 0) { 13049d95baf9SRobert Foss dev_err(camss->dev, 13059d95baf9SRobert Foss "Failed to link %s->%s entities: %d\n", 13069d95baf9SRobert Foss csid->entity.name, 13079d95baf9SRobert Foss vfe->entity.name, 13089d95baf9SRobert Foss ret); 13099d95baf9SRobert Foss goto err_link; 13109d95baf9SRobert Foss } 13119d95baf9SRobert Foss } 13129d95baf9SRobert Foss } 1313ec6859b2STodor Tomov 1314ec6859b2STodor Tomov return 0; 1315ec6859b2STodor Tomov 1316ec6859b2STodor Tomov err_link: 13179c3e59deSTodor Tomov i = camss->vfe_num; 1318ec6859b2STodor Tomov err_reg_vfe: 13199c3e59deSTodor Tomov for (i--; i >= 0; i--) 13209c3e59deSTodor Tomov msm_vfe_unregister_entities(&camss->vfe[i]); 13219c3e59deSTodor Tomov 1322ec6859b2STodor Tomov err_reg_ispif: 13239d95baf9SRobert Foss msm_ispif_unregister_entities(camss->ispif); 1324ec6859b2STodor Tomov 13259c3e59deSTodor Tomov i = camss->csid_num; 1326ec6859b2STodor Tomov err_reg_csid: 1327ec6859b2STodor Tomov for (i--; i >= 0; i--) 1328ec6859b2STodor Tomov msm_csid_unregister_entity(&camss->csid[i]); 1329ec6859b2STodor Tomov 13309c3e59deSTodor Tomov i = camss->csiphy_num; 1331ec6859b2STodor Tomov err_reg_csiphy: 1332ec6859b2STodor Tomov for (i--; i >= 0; i--) 1333ec6859b2STodor Tomov msm_csiphy_unregister_entity(&camss->csiphy[i]); 1334ec6859b2STodor Tomov 1335ec6859b2STodor Tomov return ret; 1336ec6859b2STodor Tomov } 1337ec6859b2STodor Tomov 1338ec6859b2STodor Tomov /* 1339ec6859b2STodor Tomov * camss_unregister_entities - Unregister subdev nodes 1340ec6859b2STodor Tomov * @camss: CAMSS device 1341ec6859b2STodor Tomov * 1342ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1343ec6859b2STodor Tomov */ 1344ec6859b2STodor Tomov static void camss_unregister_entities(struct camss *camss) 1345ec6859b2STodor Tomov { 1346ec6859b2STodor Tomov unsigned int i; 1347ec6859b2STodor Tomov 13489c3e59deSTodor Tomov for (i = 0; i < camss->csiphy_num; i++) 1349ec6859b2STodor Tomov msm_csiphy_unregister_entity(&camss->csiphy[i]); 1350ec6859b2STodor Tomov 13519c3e59deSTodor Tomov for (i = 0; i < camss->csid_num; i++) 1352ec6859b2STodor Tomov msm_csid_unregister_entity(&camss->csid[i]); 1353ec6859b2STodor Tomov 13549d95baf9SRobert Foss msm_ispif_unregister_entities(camss->ispif); 13559c3e59deSTodor Tomov 13569c3e59deSTodor Tomov for (i = 0; i < camss->vfe_num; i++) 13579c3e59deSTodor Tomov msm_vfe_unregister_entities(&camss->vfe[i]); 1358ec6859b2STodor Tomov } 1359ec6859b2STodor Tomov 1360ec6859b2STodor Tomov static int camss_subdev_notifier_bound(struct v4l2_async_notifier *async, 1361ec6859b2STodor Tomov struct v4l2_subdev *subdev, 1362ec6859b2STodor Tomov struct v4l2_async_subdev *asd) 1363ec6859b2STodor Tomov { 1364ec6859b2STodor Tomov struct camss *camss = container_of(async, struct camss, notifier); 1365ec6859b2STodor Tomov struct camss_async_subdev *csd = 1366ec6859b2STodor Tomov container_of(asd, struct camss_async_subdev, asd); 1367ec6859b2STodor Tomov u8 id = csd->interface.csiphy_id; 1368ec6859b2STodor Tomov struct csiphy_device *csiphy = &camss->csiphy[id]; 1369ec6859b2STodor Tomov 1370ec6859b2STodor Tomov csiphy->cfg.csi2 = &csd->interface.csi2; 1371ec6859b2STodor Tomov subdev->host_priv = csiphy; 1372ec6859b2STodor Tomov 1373ec6859b2STodor Tomov return 0; 1374ec6859b2STodor Tomov } 1375ec6859b2STodor Tomov 1376ec6859b2STodor Tomov static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) 1377ec6859b2STodor Tomov { 1378ec6859b2STodor Tomov struct camss *camss = container_of(async, struct camss, notifier); 1379ec6859b2STodor Tomov struct v4l2_device *v4l2_dev = &camss->v4l2_dev; 1380ec6859b2STodor Tomov struct v4l2_subdev *sd; 1381ec6859b2STodor Tomov int ret; 1382ec6859b2STodor Tomov 1383ec6859b2STodor Tomov list_for_each_entry(sd, &v4l2_dev->subdevs, list) { 1384ec6859b2STodor Tomov if (sd->host_priv) { 1385ec6859b2STodor Tomov struct media_entity *sensor = &sd->entity; 1386ec6859b2STodor Tomov struct csiphy_device *csiphy = 1387ec6859b2STodor Tomov (struct csiphy_device *) sd->host_priv; 1388ec6859b2STodor Tomov struct media_entity *input = &csiphy->subdev.entity; 1389ec6859b2STodor Tomov unsigned int i; 1390ec6859b2STodor Tomov 1391ec6859b2STodor Tomov for (i = 0; i < sensor->num_pads; i++) { 1392ec6859b2STodor Tomov if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) 1393ec6859b2STodor Tomov break; 1394ec6859b2STodor Tomov } 1395ec6859b2STodor Tomov if (i == sensor->num_pads) { 1396ec6859b2STodor Tomov dev_err(camss->dev, 1397ec6859b2STodor Tomov "No source pad in external entity\n"); 1398ec6859b2STodor Tomov return -EINVAL; 1399ec6859b2STodor Tomov } 1400ec6859b2STodor Tomov 1401ec6859b2STodor Tomov ret = media_create_pad_link(sensor, i, 1402ec6859b2STodor Tomov input, MSM_CSIPHY_PAD_SINK, 1403ec6859b2STodor Tomov MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 1404ec6859b2STodor Tomov if (ret < 0) { 1405ec6859b2STodor Tomov dev_err(camss->dev, 1406ec6859b2STodor Tomov "Failed to link %s->%s entities: %d\n", 1407ec6859b2STodor Tomov sensor->name, input->name, ret); 1408ec6859b2STodor Tomov return ret; 1409ec6859b2STodor Tomov } 1410ec6859b2STodor Tomov } 1411ec6859b2STodor Tomov } 1412ec6859b2STodor Tomov 1413ec6859b2STodor Tomov ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); 1414ec6859b2STodor Tomov if (ret < 0) 1415ec6859b2STodor Tomov return ret; 1416ec6859b2STodor Tomov 1417ec6859b2STodor Tomov return media_device_register(&camss->media_dev); 1418ec6859b2STodor Tomov } 1419ec6859b2STodor Tomov 1420ec6859b2STodor Tomov static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { 1421ec6859b2STodor Tomov .bound = camss_subdev_notifier_bound, 1422ec6859b2STodor Tomov .complete = camss_subdev_notifier_complete, 1423ec6859b2STodor Tomov }; 1424ec6859b2STodor Tomov 1425ec6859b2STodor Tomov static const struct media_device_ops camss_media_ops = { 1426ec6859b2STodor Tomov .link_notify = v4l2_pipeline_link_notify, 1427ec6859b2STodor Tomov }; 1428ec6859b2STodor Tomov 14292f6f8af6SRobert Foss static int camss_configure_pd(struct camss *camss) 14302f6f8af6SRobert Foss { 14312f6f8af6SRobert Foss int nbr_pm_domains = 0; 14322f6f8af6SRobert Foss int last_pm_domain = 0; 14332f6f8af6SRobert Foss int i; 14342f6f8af6SRobert Foss int ret; 14352f6f8af6SRobert Foss 14362f6f8af6SRobert Foss if (camss->version == CAMSS_8x96 || 14372f6f8af6SRobert Foss camss->version == CAMSS_660) 14382f6f8af6SRobert Foss nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; 1439*b4436a18SJonathan Marek else if (camss->version == CAMSS_845 || 1440*b4436a18SJonathan Marek camss->version == CAMSS_8250) 144170524567SRobert Foss nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; 14422f6f8af6SRobert Foss 14432f6f8af6SRobert Foss for (i = 0; i < nbr_pm_domains; i++) { 14442f6f8af6SRobert Foss camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); 14452f6f8af6SRobert Foss if (IS_ERR(camss->genpd[i])) { 14462f6f8af6SRobert Foss ret = PTR_ERR(camss->genpd[i]); 14472f6f8af6SRobert Foss goto fail_pm; 14482f6f8af6SRobert Foss } 14492f6f8af6SRobert Foss 14502f6f8af6SRobert Foss camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i], 14512f6f8af6SRobert Foss DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | 14522f6f8af6SRobert Foss DL_FLAG_RPM_ACTIVE); 14532f6f8af6SRobert Foss if (!camss->genpd_link[i]) { 14542f6f8af6SRobert Foss dev_pm_domain_detach(camss->genpd[i], true); 14552f6f8af6SRobert Foss ret = -EINVAL; 14562f6f8af6SRobert Foss goto fail_pm; 14572f6f8af6SRobert Foss } 14582f6f8af6SRobert Foss 14592f6f8af6SRobert Foss last_pm_domain = i; 14602f6f8af6SRobert Foss } 14612f6f8af6SRobert Foss 14622f6f8af6SRobert Foss return 0; 14632f6f8af6SRobert Foss 14642f6f8af6SRobert Foss fail_pm: 14652f6f8af6SRobert Foss for (i = 0; i < last_pm_domain; i++) { 14662f6f8af6SRobert Foss device_link_del(camss->genpd_link[i]); 14672f6f8af6SRobert Foss dev_pm_domain_detach(camss->genpd[i], true); 14682f6f8af6SRobert Foss } 14692f6f8af6SRobert Foss 14702f6f8af6SRobert Foss return ret; 14712f6f8af6SRobert Foss } 14722f6f8af6SRobert Foss 1473ec6859b2STodor Tomov /* 1474ec6859b2STodor Tomov * camss_probe - Probe CAMSS platform device 1475ec6859b2STodor Tomov * @pdev: Pointer to CAMSS platform device 1476ec6859b2STodor Tomov * 1477ec6859b2STodor Tomov * Return 0 on success or a negative error code on failure 1478ec6859b2STodor Tomov */ 1479ec6859b2STodor Tomov static int camss_probe(struct platform_device *pdev) 1480ec6859b2STodor Tomov { 1481ec6859b2STodor Tomov struct device *dev = &pdev->dev; 1482ec6859b2STodor Tomov struct camss *camss; 1483d079f94cSSteve Longerbeam int num_subdevs, ret; 1484ec6859b2STodor Tomov 1485ec6859b2STodor Tomov camss = kzalloc(sizeof(*camss), GFP_KERNEL); 1486ec6859b2STodor Tomov if (!camss) 1487ec6859b2STodor Tomov return -ENOMEM; 1488ec6859b2STodor Tomov 1489ec6859b2STodor Tomov atomic_set(&camss->ref_count, 0); 1490ec6859b2STodor Tomov camss->dev = dev; 1491ec6859b2STodor Tomov platform_set_drvdata(pdev, camss); 1492ec6859b2STodor Tomov 14939c3e59deSTodor Tomov if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) { 14949c3e59deSTodor Tomov camss->version = CAMSS_8x16; 14959c3e59deSTodor Tomov camss->csiphy_num = 2; 14969c3e59deSTodor Tomov camss->csid_num = 2; 14979c3e59deSTodor Tomov camss->vfe_num = 1; 14989c3e59deSTodor Tomov } else if (of_device_is_compatible(dev->of_node, 14999c3e59deSTodor Tomov "qcom,msm8996-camss")) { 15009c3e59deSTodor Tomov camss->version = CAMSS_8x96; 15019c3e59deSTodor Tomov camss->csiphy_num = 3; 15029c3e59deSTodor Tomov camss->csid_num = 4; 15039c3e59deSTodor Tomov camss->vfe_num = 2; 15049e5d1581SAngeloGioacchino Del Regno } else if (of_device_is_compatible(dev->of_node, 15059e5d1581SAngeloGioacchino Del Regno "qcom,sdm660-camss")) { 15069e5d1581SAngeloGioacchino Del Regno camss->version = CAMSS_660; 15079e5d1581SAngeloGioacchino Del Regno camss->csiphy_num = 3; 15089e5d1581SAngeloGioacchino Del Regno camss->csid_num = 4; 15099e5d1581SAngeloGioacchino Del Regno camss->vfe_num = 2; 151070524567SRobert Foss } else if (of_device_is_compatible(dev->of_node, 151170524567SRobert Foss "qcom,sdm845-camss")) { 151270524567SRobert Foss camss->version = CAMSS_845; 151370524567SRobert Foss camss->csiphy_num = 4; 151470524567SRobert Foss camss->csid_num = 3; 151570524567SRobert Foss camss->vfe_num = 3; 1516*b4436a18SJonathan Marek } else if (of_device_is_compatible(dev->of_node, 1517*b4436a18SJonathan Marek "qcom,sm8250-camss")) { 1518*b4436a18SJonathan Marek camss->version = CAMSS_8250; 1519*b4436a18SJonathan Marek camss->csiphy_num = 6; 1520*b4436a18SJonathan Marek camss->csid_num = 4; 1521*b4436a18SJonathan Marek camss->vfe_num = 4; 15229c3e59deSTodor Tomov } else { 1523f45882cfSEvgeny Novikov ret = -EINVAL; 1524f45882cfSEvgeny Novikov goto err_free; 15259c3e59deSTodor Tomov } 15269c3e59deSTodor Tomov 152755b51899STodor Tomov camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, 152855b51899STodor Tomov sizeof(*camss->csiphy), GFP_KERNEL); 1529f45882cfSEvgeny Novikov if (!camss->csiphy) { 1530f45882cfSEvgeny Novikov ret = -ENOMEM; 1531f45882cfSEvgeny Novikov goto err_free; 1532f45882cfSEvgeny Novikov } 15339c3e59deSTodor Tomov 153455b51899STodor Tomov camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), 15359c3e59deSTodor Tomov GFP_KERNEL); 1536f45882cfSEvgeny Novikov if (!camss->csid) { 1537f45882cfSEvgeny Novikov ret = -ENOMEM; 1538f45882cfSEvgeny Novikov goto err_free; 1539f45882cfSEvgeny Novikov } 15409c3e59deSTodor Tomov 15419d95baf9SRobert Foss if (camss->version == CAMSS_8x16 || 15429d95baf9SRobert Foss camss->version == CAMSS_8x96) { 15439d95baf9SRobert Foss camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); 15449d95baf9SRobert Foss if (!camss->ispif) { 15459d95baf9SRobert Foss ret = -ENOMEM; 15469d95baf9SRobert Foss goto err_free; 15479d95baf9SRobert Foss } 15489d95baf9SRobert Foss } 15499d95baf9SRobert Foss 155055b51899STodor Tomov camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), 155155b51899STodor Tomov GFP_KERNEL); 1552f45882cfSEvgeny Novikov if (!camss->vfe) { 1553f45882cfSEvgeny Novikov ret = -ENOMEM; 1554f45882cfSEvgeny Novikov goto err_free; 1555f45882cfSEvgeny Novikov } 15569c3e59deSTodor Tomov 15573c8c1539SSakari Ailus v4l2_async_nf_init(&camss->notifier); 1558d079f94cSSteve Longerbeam 1559d079f94cSSteve Longerbeam num_subdevs = camss_of_parse_ports(camss); 1560f45882cfSEvgeny Novikov if (num_subdevs < 0) { 1561f45882cfSEvgeny Novikov ret = num_subdevs; 1562f45882cfSEvgeny Novikov goto err_cleanup; 1563f45882cfSEvgeny Novikov } 1564ec6859b2STodor Tomov 1565ec6859b2STodor Tomov ret = camss_init_subdevices(camss); 1566ec6859b2STodor Tomov if (ret < 0) 1567d079f94cSSteve Longerbeam goto err_cleanup; 1568ec6859b2STodor Tomov 1569ec6859b2STodor Tomov ret = dma_set_mask_and_coherent(dev, 0xffffffff); 1570ec6859b2STodor Tomov if (ret) 1571d079f94cSSteve Longerbeam goto err_cleanup; 1572ec6859b2STodor Tomov 1573ec6859b2STodor Tomov camss->media_dev.dev = camss->dev; 1574c0decac1SMauro Carvalho Chehab strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem", 1575ec6859b2STodor Tomov sizeof(camss->media_dev.model)); 1576ec6859b2STodor Tomov camss->media_dev.ops = &camss_media_ops; 1577ec6859b2STodor Tomov media_device_init(&camss->media_dev); 1578ec6859b2STodor Tomov 1579ec6859b2STodor Tomov camss->v4l2_dev.mdev = &camss->media_dev; 1580ec6859b2STodor Tomov ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); 1581ec6859b2STodor Tomov if (ret < 0) { 1582ec6859b2STodor Tomov dev_err(dev, "Failed to register V4L2 device: %d\n", ret); 1583d079f94cSSteve Longerbeam goto err_cleanup; 1584ec6859b2STodor Tomov } 1585ec6859b2STodor Tomov 1586ec6859b2STodor Tomov ret = camss_register_entities(camss); 1587ec6859b2STodor Tomov if (ret < 0) 1588ec6859b2STodor Tomov goto err_register_entities; 1589ec6859b2STodor Tomov 1590d079f94cSSteve Longerbeam if (num_subdevs) { 1591ec6859b2STodor Tomov camss->notifier.ops = &camss_subdev_notifier_ops; 1592ec6859b2STodor Tomov 15933c8c1539SSakari Ailus ret = v4l2_async_nf_register(&camss->v4l2_dev, 1594ec6859b2STodor Tomov &camss->notifier); 1595ec6859b2STodor Tomov if (ret) { 1596ec6859b2STodor Tomov dev_err(dev, 1597ec6859b2STodor Tomov "Failed to register async subdev nodes: %d\n", 1598ec6859b2STodor Tomov ret); 1599ec6859b2STodor Tomov goto err_register_subdevs; 1600ec6859b2STodor Tomov } 1601ec6859b2STodor Tomov } else { 1602ec6859b2STodor Tomov ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); 1603ec6859b2STodor Tomov if (ret < 0) { 1604ec6859b2STodor Tomov dev_err(dev, "Failed to register subdev nodes: %d\n", 1605ec6859b2STodor Tomov ret); 1606ec6859b2STodor Tomov goto err_register_subdevs; 1607ec6859b2STodor Tomov } 1608ec6859b2STodor Tomov 1609ec6859b2STodor Tomov ret = media_device_register(&camss->media_dev); 1610ec6859b2STodor Tomov if (ret < 0) { 1611ec6859b2STodor Tomov dev_err(dev, "Failed to register media device: %d\n", 1612ec6859b2STodor Tomov ret); 1613ec6859b2STodor Tomov goto err_register_subdevs; 1614ec6859b2STodor Tomov } 1615ec6859b2STodor Tomov } 1616ec6859b2STodor Tomov 16172f6f8af6SRobert Foss ret = camss_configure_pd(camss); 16182f6f8af6SRobert Foss if (ret < 0) { 16192f6f8af6SRobert Foss dev_err(dev, "Failed to configure power domains: %d\n", ret); 16202f6f8af6SRobert Foss return ret; 162102afa816STodor Tomov } 162202afa816STodor Tomov 162302afa816STodor Tomov pm_runtime_enable(dev); 162402afa816STodor Tomov 1625ec6859b2STodor Tomov return 0; 1626ec6859b2STodor Tomov 1627ec6859b2STodor Tomov err_register_subdevs: 1628ec6859b2STodor Tomov camss_unregister_entities(camss); 1629ec6859b2STodor Tomov err_register_entities: 1630ec6859b2STodor Tomov v4l2_device_unregister(&camss->v4l2_dev); 1631d079f94cSSteve Longerbeam err_cleanup: 16323c8c1539SSakari Ailus v4l2_async_nf_cleanup(&camss->notifier); 1633f45882cfSEvgeny Novikov err_free: 1634f45882cfSEvgeny Novikov kfree(camss); 1635ec6859b2STodor Tomov 1636ec6859b2STodor Tomov return ret; 1637ec6859b2STodor Tomov } 1638ec6859b2STodor Tomov 1639ec6859b2STodor Tomov void camss_delete(struct camss *camss) 1640ec6859b2STodor Tomov { 16412f6f8af6SRobert Foss int nbr_pm_domains = 0; 16422f6f8af6SRobert Foss int i; 16432f6f8af6SRobert Foss 1644ec6859b2STodor Tomov v4l2_device_unregister(&camss->v4l2_dev); 1645ec6859b2STodor Tomov media_device_unregister(&camss->media_dev); 1646ec6859b2STodor Tomov media_device_cleanup(&camss->media_dev); 1647ec6859b2STodor Tomov 164802afa816STodor Tomov pm_runtime_disable(camss->dev); 164902afa816STodor Tomov 16509e5d1581SAngeloGioacchino Del Regno if (camss->version == CAMSS_8x96 || 16512f6f8af6SRobert Foss camss->version == CAMSS_660) 16522f6f8af6SRobert Foss nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; 1653*b4436a18SJonathan Marek else if (camss->version == CAMSS_845 || 1654*b4436a18SJonathan Marek camss->version == CAMSS_8250) 165570524567SRobert Foss nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; 16562f6f8af6SRobert Foss 16572f6f8af6SRobert Foss for (i = 0; i < nbr_pm_domains; i++) { 16582f6f8af6SRobert Foss device_link_del(camss->genpd_link[i]); 16592f6f8af6SRobert Foss dev_pm_domain_detach(camss->genpd[i], true); 166002afa816STodor Tomov } 166102afa816STodor Tomov 1662ec6859b2STodor Tomov kfree(camss); 1663ec6859b2STodor Tomov } 1664ec6859b2STodor Tomov 1665ec6859b2STodor Tomov /* 1666ec6859b2STodor Tomov * camss_remove - Remove CAMSS platform device 1667ec6859b2STodor Tomov * @pdev: Pointer to CAMSS platform device 1668ec6859b2STodor Tomov * 1669ec6859b2STodor Tomov * Always returns 0. 1670ec6859b2STodor Tomov */ 1671ec6859b2STodor Tomov static int camss_remove(struct platform_device *pdev) 1672ec6859b2STodor Tomov { 1673ec6859b2STodor Tomov struct camss *camss = platform_get_drvdata(pdev); 1674ec6859b2STodor Tomov 16753c8c1539SSakari Ailus v4l2_async_nf_unregister(&camss->notifier); 16763c8c1539SSakari Ailus v4l2_async_nf_cleanup(&camss->notifier); 1677ec6859b2STodor Tomov camss_unregister_entities(camss); 1678ec6859b2STodor Tomov 1679ec6859b2STodor Tomov if (atomic_read(&camss->ref_count) == 0) 1680ec6859b2STodor Tomov camss_delete(camss); 1681ec6859b2STodor Tomov 1682ec6859b2STodor Tomov return 0; 1683ec6859b2STodor Tomov } 1684ec6859b2STodor Tomov 1685ec6859b2STodor Tomov static const struct of_device_id camss_dt_match[] = { 1686ec6859b2STodor Tomov { .compatible = "qcom,msm8916-camss" }, 16879c3e59deSTodor Tomov { .compatible = "qcom,msm8996-camss" }, 16889e5d1581SAngeloGioacchino Del Regno { .compatible = "qcom,sdm660-camss" }, 168970524567SRobert Foss { .compatible = "qcom,sdm845-camss" }, 1690*b4436a18SJonathan Marek { .compatible = "qcom,sm8250-camss" }, 1691ec6859b2STodor Tomov { } 1692ec6859b2STodor Tomov }; 1693ec6859b2STodor Tomov 1694ec6859b2STodor Tomov MODULE_DEVICE_TABLE(of, camss_dt_match); 1695ec6859b2STodor Tomov 169644a9ffd4SArnd Bergmann static int __maybe_unused camss_runtime_suspend(struct device *dev) 169702afa816STodor Tomov { 169802afa816STodor Tomov return 0; 169902afa816STodor Tomov } 170002afa816STodor Tomov 170144a9ffd4SArnd Bergmann static int __maybe_unused camss_runtime_resume(struct device *dev) 170202afa816STodor Tomov { 170302afa816STodor Tomov return 0; 170402afa816STodor Tomov } 170502afa816STodor Tomov 170602afa816STodor Tomov static const struct dev_pm_ops camss_pm_ops = { 170702afa816STodor Tomov SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 170802afa816STodor Tomov pm_runtime_force_resume) 170902afa816STodor Tomov SET_RUNTIME_PM_OPS(camss_runtime_suspend, camss_runtime_resume, NULL) 171002afa816STodor Tomov }; 171102afa816STodor Tomov 1712ec6859b2STodor Tomov static struct platform_driver qcom_camss_driver = { 1713ec6859b2STodor Tomov .probe = camss_probe, 1714ec6859b2STodor Tomov .remove = camss_remove, 1715ec6859b2STodor Tomov .driver = { 1716ec6859b2STodor Tomov .name = "qcom-camss", 1717ec6859b2STodor Tomov .of_match_table = camss_dt_match, 171802afa816STodor Tomov .pm = &camss_pm_ops, 1719ec6859b2STodor Tomov }, 1720ec6859b2STodor Tomov }; 1721ec6859b2STodor Tomov 1722ec6859b2STodor Tomov module_platform_driver(qcom_camss_driver); 1723ec6859b2STodor Tomov 1724ec6859b2STodor Tomov MODULE_ALIAS("platform:qcom-camss"); 1725ec6859b2STodor Tomov MODULE_DESCRIPTION("Qualcomm Camera Subsystem driver"); 1726ec6859b2STodor Tomov MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); 1727ec6859b2STodor Tomov MODULE_LICENSE("GPL v2"); 1728