1b63ef604SKeke Li // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2b63ef604SKeke Li /* 3b63ef604SKeke Li * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4b63ef604SKeke Li */ 5b63ef604SKeke Li 6b63ef604SKeke Li #include <linux/clk.h> 7b63ef604SKeke Li #include <linux/device.h> 8*1b83a9f4SJacopo Mondi #include <linux/math.h> 9b63ef604SKeke Li #include <linux/module.h> 10b63ef604SKeke Li #include <linux/mutex.h> 11b63ef604SKeke Li #include <linux/platform_device.h> 12b63ef604SKeke Li #include <linux/pm_runtime.h> 13b63ef604SKeke Li 14b63ef604SKeke Li #include <media/v4l2-async.h> 15b63ef604SKeke Li #include <media/v4l2-common.h> 16b63ef604SKeke Li #include <media/v4l2-device.h> 17b63ef604SKeke Li #include <media/v4l2-fwnode.h> 18b63ef604SKeke Li #include <media/v4l2-mc.h> 19b63ef604SKeke Li #include <media/v4l2-subdev.h> 20b63ef604SKeke Li 21b63ef604SKeke Li /* C3 CSI-2 submodule definition */ 22b63ef604SKeke Li enum { 23b63ef604SKeke Li SUBMD_APHY, 24b63ef604SKeke Li SUBMD_DPHY, 25b63ef604SKeke Li SUBMD_HOST, 26b63ef604SKeke Li }; 27b63ef604SKeke Li 28b63ef604SKeke Li #define CSI2_SUBMD_MASK GENMASK(17, 16) 29b63ef604SKeke Li #define CSI2_SUBMD_SHIFT 16 30b63ef604SKeke Li #define CSI2_SUBMD(x) (((x) & (CSI2_SUBMD_MASK)) >> (CSI2_SUBMD_SHIFT)) 31b63ef604SKeke Li #define CSI2_REG_ADDR_MASK GENMASK(15, 0) 32b63ef604SKeke Li #define CSI2_REG_ADDR(x) ((x) & (CSI2_REG_ADDR_MASK)) 33b63ef604SKeke Li #define CSI2_REG_A(x) ((SUBMD_APHY << CSI2_SUBMD_SHIFT) | (x)) 34b63ef604SKeke Li #define CSI2_REG_D(x) ((SUBMD_DPHY << CSI2_SUBMD_SHIFT) | (x)) 35b63ef604SKeke Li #define CSI2_REG_H(x) ((SUBMD_HOST << CSI2_SUBMD_SHIFT) | (x)) 36b63ef604SKeke Li 37b63ef604SKeke Li #define MIPI_CSI2_CLOCK_NUM_MAX 3 38b63ef604SKeke Li #define MIPI_CSI2_SUBDEV_NAME "c3-mipi-csi2" 39b63ef604SKeke Li 40b63ef604SKeke Li /* C3 CSI-2 APHY register */ 41b63ef604SKeke Li #define CSI_PHY_CNTL0 CSI2_REG_A(0x44) 42b63ef604SKeke Li #define CSI_PHY_CNTL0_HS_LP_BIAS_EN BIT(10) 43b63ef604SKeke Li #define CSI_PHY_CNTL0_HS_RX_TRIM_11 (11 << 11) 44b63ef604SKeke Li #define CSI_PHY_CNTL0_LP_LOW_VTH_2 (2 << 16) 45b63ef604SKeke Li #define CSI_PHY_CNTL0_LP_HIGH_VTH_4 (4 << 20) 46b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE0_HS_DIG_EN BIT(24) 47b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE1_HS_DIG_EN BIT(25) 48b63ef604SKeke Li #define CSI_PHY_CNTL0_CLK0_LANE_HS_DIG_EN BIT(26) 49b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE2_HS_DIG_EN BIT(27) 50b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE3_HS_DIG_EN BIT(28) 51b63ef604SKeke Li 52b63ef604SKeke Li #define CSI_PHY_CNTL1 CSI2_REG_A(0x48) 53b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_CAP_SMALL (2 << 16) 54b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_CAP_BIG (3 << 16) 55b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MIN (3 << 18) 56b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MED (2 << 18) 57b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MAX BIT(18) 58b63ef604SKeke Li #define CSI_PHY_CNTL1_CLK_CHN_EQ_MAX_GAIN BIT(20) 59b63ef604SKeke Li #define CSI_PHY_CNTL1_DATA_CHN_EQ_MAX_GAIN BIT(21) 60b63ef604SKeke Li #define CSI_PHY_CNTL1_COM_BG_EN BIT(24) 61b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_SYNC_EN BIT(25) 62b63ef604SKeke Li 63b63ef604SKeke Li /* C3 CSI-2 DPHY register */ 64b63ef604SKeke Li #define MIPI_PHY_CTRL CSI2_REG_D(0x00) 65b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE0_EN (0 << 0) 66b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE0_DIS BIT(0) 67b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE1_EN (0 << 1) 68b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE1_DIS BIT(1) 69b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE2_EN (0 << 2) 70b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE2_DIS BIT(2) 71b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE3_EN (0 << 3) 72b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE3_DIS BIT(3) 73b63ef604SKeke Li #define MIPI_PHY_CTRL_CLOCK_LANE_EN (0 << 4) 74b63ef604SKeke Li #define MIPI_PHY_CTRL_CLOCK_LANE_DIS BIT(4) 75b63ef604SKeke Li 76b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL CSI2_REG_D(0x04) 77b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_FORCE_ULPS_ENTER BIT(0) 78b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_FORCE_ULPS_EXIT BIT(1) 79b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS (0 << 3) 80b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_2 BIT(3) 81b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_4 (2 << 3) 82b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_8 (3 << 3) 83b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_16 (4 << 3) 84b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_EN BIT(6) 85b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_LPEN_DIS BIT(7) 86b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_END_EN BIT(8) 87b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_HS_RX_EN BIT(9) 88b63ef604SKeke Li 89b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1 CSI2_REG_D(0x0c) 90b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_INSERT_ERRESC BIT(0) 91b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_HS_SYNC_CHK_EN BIT(1) 92b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_MASK GENMASK(6, 2) 93b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_ALL_EN (0x1f << 2) 94b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_MASK GENMASK(9, 7) 95b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_3 (3 << 7) 96b63ef604SKeke Li 97b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS CSI2_REG_D(0x10) 98b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS_CYCLES_MASK GENMASK(7, 0) 99b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS_CYCLES_9 (9 << 0) 100b63ef604SKeke Li 101b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE CSI2_REG_D(0x14) 102b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE_CYCLES_MASK GENMASK(7, 0) 103b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE_CYCLES_31 (31 << 0) 104b63ef604SKeke Li 105b63ef604SKeke Li #define MIPI_PHY_THS_EXIT CSI2_REG_D(0x18) 106b63ef604SKeke Li #define MIPI_PHY_THS_EXIT_CYCLES_MASK GENMASK(7, 0) 107b63ef604SKeke Li #define MIPI_PHY_THS_EXIT_CYCLES_8 (8 << 0) 108b63ef604SKeke Li 109b63ef604SKeke Li #define MIPI_PHY_THS_SKIP CSI2_REG_D(0x1c) 110b63ef604SKeke Li #define MIPI_PHY_THS_SKIP_CYCLES_MASK GENMASK(7, 0) 111b63ef604SKeke Li #define MIPI_PHY_THS_SKIP_CYCLES_10 (10 << 0) 112b63ef604SKeke Li 113b63ef604SKeke Li #define MIPI_PHY_THS_SETTLE CSI2_REG_D(0x20) 114b63ef604SKeke Li #define MIPI_PHY_THS_SETTLE_CYCLES_MASK GENMASK(7, 0) 115b63ef604SKeke Li 116b63ef604SKeke Li #define MIPI_PHY_TINIT CSI2_REG_D(0x24) 117b63ef604SKeke Li #define MIPI_PHY_TINIT_CYCLES_MASK GENMASK(31, 0) 118b63ef604SKeke Li #define MIPI_PHY_TINIT_CYCLES_20000 (20000 << 0) 119b63ef604SKeke Li 120b63ef604SKeke Li #define MIPI_PHY_TULPS_C CSI2_REG_D(0x28) 121b63ef604SKeke Li #define MIPI_PHY_TULPS_C_CYCLES_MASK GENMASK(31, 0) 122b63ef604SKeke Li #define MIPI_PHY_TULPS_C_CYCLES_4096 (4096 << 0) 123b63ef604SKeke Li 124b63ef604SKeke Li #define MIPI_PHY_TULPS_S CSI2_REG_D(0x2c) 125b63ef604SKeke Li #define MIPI_PHY_TULPS_S_CYCLES_MASK GENMASK(31, 0) 126b63ef604SKeke Li #define MIPI_PHY_TULPS_S_CYCLES_256 (256 << 0) 127b63ef604SKeke Li 128b63ef604SKeke Li #define MIPI_PHY_TMBIAS CSI2_REG_D(0x30) 129b63ef604SKeke Li #define MIPI_PHY_TMBIAS_CYCLES_MASK GENMASK(31, 0) 130b63ef604SKeke Li #define MIPI_PHY_TMBIAS_CYCLES_256 (256 << 0) 131b63ef604SKeke Li 132b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W CSI2_REG_D(0x34) 133b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W_CYCLES_MASK GENMASK(31, 0) 134b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W_CYCLES_12 (12 << 0) 135b63ef604SKeke Li 136b63ef604SKeke Li #define MIPI_PHY_TLPOK CSI2_REG_D(0x38) 137b63ef604SKeke Li #define MIPI_PHY_TLPOK_CYCLES_MASK GENMASK(31, 0) 138b63ef604SKeke Li #define MIPI_PHY_TLPOK_CYCLES_256 (256 << 0) 139b63ef604SKeke Li 140b63ef604SKeke Li #define MIPI_PHY_TWD_INIT CSI2_REG_D(0x3c) 141b63ef604SKeke Li #define MIPI_PHY_TWD_INIT_DOG_MASK GENMASK(31, 0) 142b63ef604SKeke Li #define MIPI_PHY_TWD_INIT_DOG_0X400000 (0x400000 << 0) 143b63ef604SKeke Li 144b63ef604SKeke Li #define MIPI_PHY_TWD_HS CSI2_REG_D(0x40) 145b63ef604SKeke Li #define MIPI_PHY_TWD_HS_DOG_MASK GENMASK(31, 0) 146b63ef604SKeke Li #define MIPI_PHY_TWD_HS_DOG_0X400000 (0x400000 << 0) 147b63ef604SKeke Li 148b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0 CSI2_REG_D(0x284) 149b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_MASK GENMASK(3, 0) 150b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE0 (0 << 0) 151b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE1 BIT(0) 152b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE2 (2 << 0) 153b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE3 (3 << 0) 154b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_MASK GENMASK(7, 4) 155b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE0 (0 << 4) 156b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE1 BIT(4) 157b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE2 (2 << 4) 158b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE3 (3 << 4) 159b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_MASK GENMASK(11, 8) 160b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE0 (0 << 8) 161b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE1 BIT(8) 162b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE2 (2 << 8) 163b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE3 (3 << 8) 164b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_MASK GENMASK(14, 12) 165b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE0 (0 << 12) 166b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE1 BIT(12) 167b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE2 (2 << 12) 168b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE3 (3 << 12) 169b63ef604SKeke Li 170b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1 CSI2_REG_D(0x288) 171b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_MASK GENMASK(3, 0) 172b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN0 (0 << 0) 173b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN1 BIT(0) 174b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN2 (2 << 0) 175b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN3 (3 << 0) 176b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_MASK GENMASK(7, 4) 177b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN0 (0 << 4) 178b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN1 BIT(4) 179b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN2 (2 << 4) 180b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN3 (3 << 4) 181b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_MASK GENMASK(11, 8) 182b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN0 (0 << 8) 183b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN1 BIT(8) 184b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN2 (2 << 8) 185b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN3 (3 << 8) 186b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_MASK GENMASK(14, 12) 187b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN0 (0 << 12) 188b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN1 BIT(12) 189b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN2 (2 << 12) 190b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN3 (3 << 12) 191b63ef604SKeke Li 192b63ef604SKeke Li /* C3 CSI-2 HOST register */ 193b63ef604SKeke Li #define CSI2_HOST_N_LANES CSI2_REG_H(0x04) 194b63ef604SKeke Li #define CSI2_HOST_N_LANES_MASK GENMASK(1, 0) 195b63ef604SKeke Li #define CSI2_HOST_N_LANES_1 (0 << 0) 196b63ef604SKeke Li #define CSI2_HOST_N_LANES_2 BIT(0) 197b63ef604SKeke Li #define CSI2_HOST_N_LANES_3 (2 << 0) 198b63ef604SKeke Li #define CSI2_HOST_N_LANES_4 (3 << 0) 199b63ef604SKeke Li 200b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN CSI2_REG_H(0x10) 201b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_MASK BIT(0) 202b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_ACTIVE (0 << 0) 203b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_EXIT BIT(0) 204b63ef604SKeke Li 205b63ef604SKeke Li #define C3_MIPI_CSI2_MAX_WIDTH 2888 206b63ef604SKeke Li #define C3_MIPI_CSI2_MIN_WIDTH 160 207b63ef604SKeke Li #define C3_MIPI_CSI2_MAX_HEIGHT 2240 208b63ef604SKeke Li #define C3_MIPI_CSI2_MIN_HEIGHT 120 209b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_WIDTH 1920 210b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_HEIGHT 1080 211b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_FMT MEDIA_BUS_FMT_SRGGB10_1X10 212b63ef604SKeke Li 213b63ef604SKeke Li /* C3 CSI-2 pad list */ 214b63ef604SKeke Li enum { 215b63ef604SKeke Li C3_MIPI_CSI2_PAD_SINK, 216b63ef604SKeke Li C3_MIPI_CSI2_PAD_SRC, 217b63ef604SKeke Li C3_MIPI_CSI2_PAD_MAX 218b63ef604SKeke Li }; 219b63ef604SKeke Li 220b63ef604SKeke Li /* 221b63ef604SKeke Li * struct c3_csi_info - MIPI CSI2 information 222b63ef604SKeke Li * 223b63ef604SKeke Li * @clocks: array of MIPI CSI2 clock names 224b63ef604SKeke Li * @clock_num: actual clock number 225b63ef604SKeke Li */ 226b63ef604SKeke Li struct c3_csi_info { 227b63ef604SKeke Li char *clocks[MIPI_CSI2_CLOCK_NUM_MAX]; 228b63ef604SKeke Li u32 clock_num; 229b63ef604SKeke Li }; 230b63ef604SKeke Li 231b63ef604SKeke Li /* 232b63ef604SKeke Li * struct c3_csi_device - MIPI CSI2 platform device 233b63ef604SKeke Li * 234b63ef604SKeke Li * @dev: pointer to the struct device 235b63ef604SKeke Li * @aphy: MIPI CSI2 aphy register address 236b63ef604SKeke Li * @dphy: MIPI CSI2 dphy register address 237b63ef604SKeke Li * @host: MIPI CSI2 host register address 238b63ef604SKeke Li * @clks: array of MIPI CSI2 clocks 239b63ef604SKeke Li * @sd: MIPI CSI2 sub-device 240b63ef604SKeke Li * @pads: MIPI CSI2 sub-device pads 241b63ef604SKeke Li * @notifier: notifier to register on the v4l2-async API 242b63ef604SKeke Li * @src_pad: source sub-device pad 243b63ef604SKeke Li * @bus: MIPI CSI2 bus information 244b63ef604SKeke Li * @info: version-specific MIPI CSI2 information 245b63ef604SKeke Li */ 246b63ef604SKeke Li struct c3_csi_device { 247b63ef604SKeke Li struct device *dev; 248b63ef604SKeke Li void __iomem *aphy; 249b63ef604SKeke Li void __iomem *dphy; 250b63ef604SKeke Li void __iomem *host; 251b63ef604SKeke Li struct clk_bulk_data clks[MIPI_CSI2_CLOCK_NUM_MAX]; 252b63ef604SKeke Li 253b63ef604SKeke Li struct v4l2_subdev sd; 254b63ef604SKeke Li struct media_pad pads[C3_MIPI_CSI2_PAD_MAX]; 255b63ef604SKeke Li struct v4l2_async_notifier notifier; 256b63ef604SKeke Li struct media_pad *src_pad; 257b63ef604SKeke Li struct v4l2_mbus_config_mipi_csi2 bus; 258b63ef604SKeke Li 259b63ef604SKeke Li const struct c3_csi_info *info; 260b63ef604SKeke Li }; 261b63ef604SKeke Li 262b63ef604SKeke Li static const u32 c3_mipi_csi_formats[] = { 263b63ef604SKeke Li MEDIA_BUS_FMT_SBGGR10_1X10, 264b63ef604SKeke Li MEDIA_BUS_FMT_SGBRG10_1X10, 265b63ef604SKeke Li MEDIA_BUS_FMT_SGRBG10_1X10, 266b63ef604SKeke Li MEDIA_BUS_FMT_SRGGB10_1X10, 267b63ef604SKeke Li MEDIA_BUS_FMT_SBGGR12_1X12, 268b63ef604SKeke Li MEDIA_BUS_FMT_SGBRG12_1X12, 269b63ef604SKeke Li MEDIA_BUS_FMT_SGRBG12_1X12, 270b63ef604SKeke Li MEDIA_BUS_FMT_SRGGB12_1X12, 271b63ef604SKeke Li }; 272b63ef604SKeke Li 273b63ef604SKeke Li /* Hardware configuration */ 274b63ef604SKeke Li 275b63ef604SKeke Li static void c3_mipi_csi_write(struct c3_csi_device *csi, u32 reg, u32 val) 276b63ef604SKeke Li { 277b63ef604SKeke Li void __iomem *addr; 278b63ef604SKeke Li 279b63ef604SKeke Li switch (CSI2_SUBMD(reg)) { 280b63ef604SKeke Li case SUBMD_APHY: 281b63ef604SKeke Li addr = csi->aphy + CSI2_REG_ADDR(reg); 282b63ef604SKeke Li break; 283b63ef604SKeke Li case SUBMD_DPHY: 284b63ef604SKeke Li addr = csi->dphy + CSI2_REG_ADDR(reg); 285b63ef604SKeke Li break; 286b63ef604SKeke Li case SUBMD_HOST: 287b63ef604SKeke Li addr = csi->host + CSI2_REG_ADDR(reg); 288b63ef604SKeke Li break; 289b63ef604SKeke Li default: 290b63ef604SKeke Li dev_err(csi->dev, "Invalid sub-module: %lu\n", CSI2_SUBMD(reg)); 291b63ef604SKeke Li return; 292b63ef604SKeke Li } 293b63ef604SKeke Li 294b63ef604SKeke Li writel(val, addr); 295b63ef604SKeke Li } 296b63ef604SKeke Li 297b63ef604SKeke Li static void c3_mipi_csi_cfg_aphy(struct c3_csi_device *csi) 298b63ef604SKeke Li { 299b63ef604SKeke Li c3_mipi_csi_write(csi, CSI_PHY_CNTL0, 300b63ef604SKeke Li CSI_PHY_CNTL0_HS_LP_BIAS_EN | 301b63ef604SKeke Li CSI_PHY_CNTL0_HS_RX_TRIM_11 | 302b63ef604SKeke Li CSI_PHY_CNTL0_LP_LOW_VTH_2 | 303b63ef604SKeke Li CSI_PHY_CNTL0_LP_HIGH_VTH_4 | 304b63ef604SKeke Li CSI_PHY_CNTL0_DATA_LANE0_HS_DIG_EN | 305b63ef604SKeke Li CSI_PHY_CNTL0_DATA_LANE1_HS_DIG_EN | 306b63ef604SKeke Li CSI_PHY_CNTL0_CLK0_LANE_HS_DIG_EN | 307b63ef604SKeke Li CSI_PHY_CNTL0_DATA_LANE2_HS_DIG_EN | 308b63ef604SKeke Li CSI_PHY_CNTL0_DATA_LANE3_HS_DIG_EN); 309b63ef604SKeke Li 310b63ef604SKeke Li c3_mipi_csi_write(csi, CSI_PHY_CNTL1, 311b63ef604SKeke Li CSI_PHY_CNTL1_HS_EQ_CAP_SMALL | 312b63ef604SKeke Li CSI_PHY_CNTL1_HS_EQ_RES_MED | 313b63ef604SKeke Li CSI_PHY_CNTL1_CLK_CHN_EQ_MAX_GAIN | 314b63ef604SKeke Li CSI_PHY_CNTL1_DATA_CHN_EQ_MAX_GAIN | 315b63ef604SKeke Li CSI_PHY_CNTL1_COM_BG_EN | 316b63ef604SKeke Li CSI_PHY_CNTL1_HS_SYNC_EN); 317b63ef604SKeke Li } 318b63ef604SKeke Li 319b63ef604SKeke Li static void c3_mipi_csi_cfg_dphy(struct c3_csi_device *csi, s64 rate) 320b63ef604SKeke Li { 321b63ef604SKeke Li u32 val; 322b63ef604SKeke Li u32 settle; 323b63ef604SKeke Li 324b63ef604SKeke Li /* Calculate the high speed settle */ 325*1b83a9f4SJacopo Mondi val = DIV_ROUND_UP_ULL(1000000000, rate); 326b63ef604SKeke Li settle = (16 * val + 230) / 10; 327b63ef604SKeke Li 328b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_CLK_LANE_CTRL, 329b63ef604SKeke Li MIPI_PHY_CLK_LANE_CTRL_HS_RX_EN | 330b63ef604SKeke Li MIPI_PHY_CLK_LANE_CTRL_END_EN | 331b63ef604SKeke Li MIPI_PHY_CLK_LANE_CTRL_LPEN_DIS | 332b63ef604SKeke Li MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_EN | 333b63ef604SKeke Li MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_8); 334b63ef604SKeke Li 335b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TCLK_MISS, MIPI_PHY_TCLK_MISS_CYCLES_9); 336b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TCLK_SETTLE, 337b63ef604SKeke Li MIPI_PHY_TCLK_SETTLE_CYCLES_31); 338b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_THS_EXIT, MIPI_PHY_THS_EXIT_CYCLES_8); 339b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_THS_SKIP, MIPI_PHY_THS_SKIP_CYCLES_10); 340b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_THS_SETTLE, settle); 341b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TINIT, MIPI_PHY_TINIT_CYCLES_20000); 342b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TMBIAS, MIPI_PHY_TMBIAS_CYCLES_256); 343b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TULPS_C, MIPI_PHY_TULPS_C_CYCLES_4096); 344b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TULPS_S, MIPI_PHY_TULPS_S_CYCLES_256); 345b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TLP_EN_W, MIPI_PHY_TLP_EN_W_CYCLES_12); 346b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TLPOK, MIPI_PHY_TLPOK_CYCLES_256); 347b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TWD_INIT, 348b63ef604SKeke Li MIPI_PHY_TWD_INIT_DOG_0X400000); 349b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_TWD_HS, MIPI_PHY_TWD_HS_DOG_0X400000); 350b63ef604SKeke Li 351b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_DATA_LANE_CTRL1, 352b63ef604SKeke Li MIPI_PHY_DATA_LANE_CTRL1_INSERT_ERRESC | 353b63ef604SKeke Li MIPI_PHY_DATA_LANE_CTRL1_HS_SYNC_CHK_EN | 354b63ef604SKeke Li MIPI_PHY_DATA_LANE_CTRL1_PIPE_ALL_EN | 355b63ef604SKeke Li MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_3); 356b63ef604SKeke Li 357b63ef604SKeke Li /* Set the order of lanes */ 358b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_MUX_CTRL0, 359b63ef604SKeke Li MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE3 | 360b63ef604SKeke Li MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE2 | 361b63ef604SKeke Li MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE1 | 362b63ef604SKeke Li MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE0); 363b63ef604SKeke Li 364b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_MUX_CTRL1, 365b63ef604SKeke Li MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN3 | 366b63ef604SKeke Li MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN2 | 367b63ef604SKeke Li MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN1 | 368b63ef604SKeke Li MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN0); 369b63ef604SKeke Li 370b63ef604SKeke Li /* Enable digital data and clock lanes */ 371b63ef604SKeke Li c3_mipi_csi_write(csi, MIPI_PHY_CTRL, 372b63ef604SKeke Li MIPI_PHY_CTRL_DATA_LANE0_EN | 373b63ef604SKeke Li MIPI_PHY_CTRL_DATA_LANE1_EN | 374b63ef604SKeke Li MIPI_PHY_CTRL_DATA_LANE2_EN | 375b63ef604SKeke Li MIPI_PHY_CTRL_DATA_LANE3_EN | 376b63ef604SKeke Li MIPI_PHY_CTRL_CLOCK_LANE_EN); 377b63ef604SKeke Li } 378b63ef604SKeke Li 379b63ef604SKeke Li static void c3_mipi_csi_cfg_host(struct c3_csi_device *csi) 380b63ef604SKeke Li { 381b63ef604SKeke Li /* Reset CSI-2 controller output */ 382b63ef604SKeke Li c3_mipi_csi_write(csi, CSI2_HOST_CSI2_RESETN, 383b63ef604SKeke Li CSI2_HOST_CSI2_RESETN_ACTIVE); 384b63ef604SKeke Li c3_mipi_csi_write(csi, CSI2_HOST_CSI2_RESETN, 385b63ef604SKeke Li CSI2_HOST_CSI2_RESETN_EXIT); 386b63ef604SKeke Li 387b63ef604SKeke Li /* Set data lane number */ 388b63ef604SKeke Li c3_mipi_csi_write(csi, CSI2_HOST_N_LANES, csi->bus.num_data_lanes - 1); 389b63ef604SKeke Li } 390b63ef604SKeke Li 391b63ef604SKeke Li static int c3_mipi_csi_start_stream(struct c3_csi_device *csi, 392b63ef604SKeke Li struct v4l2_subdev *src_sd) 393b63ef604SKeke Li { 394b63ef604SKeke Li s64 link_freq; 395b63ef604SKeke Li s64 lane_rate; 396b63ef604SKeke Li 397b63ef604SKeke Li link_freq = v4l2_get_link_freq(src_sd->ctrl_handler, 0, 0); 398b63ef604SKeke Li if (link_freq < 0) { 399b63ef604SKeke Li dev_err(csi->dev, 400b63ef604SKeke Li "Unable to obtain link frequency: %lld\n", link_freq); 401b63ef604SKeke Li return link_freq; 402b63ef604SKeke Li } 403b63ef604SKeke Li 404b63ef604SKeke Li lane_rate = link_freq * 2; 405b63ef604SKeke Li if (lane_rate > 1500000000) { 406b63ef604SKeke Li dev_err(csi->dev, "Invalid lane rate: %lld\n", lane_rate); 407b63ef604SKeke Li return -EINVAL; 408b63ef604SKeke Li } 409b63ef604SKeke Li 410b63ef604SKeke Li c3_mipi_csi_cfg_aphy(csi); 411b63ef604SKeke Li c3_mipi_csi_cfg_dphy(csi, lane_rate); 412b63ef604SKeke Li c3_mipi_csi_cfg_host(csi); 413b63ef604SKeke Li 414b63ef604SKeke Li return 0; 415b63ef604SKeke Li } 416b63ef604SKeke Li 417b63ef604SKeke Li static int c3_mipi_csi_enable_streams(struct v4l2_subdev *sd, 418b63ef604SKeke Li struct v4l2_subdev_state *state, 419b63ef604SKeke Li u32 pad, u64 streams_mask) 420b63ef604SKeke Li { 421b63ef604SKeke Li struct c3_csi_device *csi = v4l2_get_subdevdata(sd); 422b63ef604SKeke Li struct media_pad *sink_pad; 423b63ef604SKeke Li struct v4l2_subdev *src_sd; 424b63ef604SKeke Li int ret; 425b63ef604SKeke Li 426b63ef604SKeke Li sink_pad = &csi->pads[C3_MIPI_CSI2_PAD_SINK]; 427b63ef604SKeke Li csi->src_pad = media_pad_remote_pad_unique(sink_pad); 428b63ef604SKeke Li if (IS_ERR(csi->src_pad)) { 429b63ef604SKeke Li dev_dbg(csi->dev, "Failed to get source pad for MIPI CSI-2\n"); 430b63ef604SKeke Li return -EPIPE; 431b63ef604SKeke Li } 432b63ef604SKeke Li 433b63ef604SKeke Li src_sd = media_entity_to_v4l2_subdev(csi->src_pad->entity); 434b63ef604SKeke Li 435b63ef604SKeke Li pm_runtime_resume_and_get(csi->dev); 436b63ef604SKeke Li 437b63ef604SKeke Li c3_mipi_csi_start_stream(csi, src_sd); 438b63ef604SKeke Li 439b63ef604SKeke Li ret = v4l2_subdev_enable_streams(src_sd, csi->src_pad->index, BIT(0)); 440b63ef604SKeke Li if (ret) { 441b63ef604SKeke Li pm_runtime_put(csi->dev); 442b63ef604SKeke Li return ret; 443b63ef604SKeke Li } 444b63ef604SKeke Li 445b63ef604SKeke Li return 0; 446b63ef604SKeke Li } 447b63ef604SKeke Li 448b63ef604SKeke Li static int c3_mipi_csi_disable_streams(struct v4l2_subdev *sd, 449b63ef604SKeke Li struct v4l2_subdev_state *state, 450b63ef604SKeke Li u32 pad, u64 streams_mask) 451b63ef604SKeke Li { 452b63ef604SKeke Li struct c3_csi_device *csi = v4l2_get_subdevdata(sd); 453b63ef604SKeke Li struct v4l2_subdev *src_sd; 454b63ef604SKeke Li 455b63ef604SKeke Li if (csi->src_pad) { 456b63ef604SKeke Li src_sd = media_entity_to_v4l2_subdev(csi->src_pad->entity); 457b63ef604SKeke Li v4l2_subdev_disable_streams(src_sd, csi->src_pad->index, 458b63ef604SKeke Li BIT(0)); 459b63ef604SKeke Li } 460b63ef604SKeke Li csi->src_pad = NULL; 461b63ef604SKeke Li 462b63ef604SKeke Li pm_runtime_put(csi->dev); 463b63ef604SKeke Li 464b63ef604SKeke Li return 0; 465b63ef604SKeke Li } 466b63ef604SKeke Li 467b63ef604SKeke Li static int c3_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd, 468b63ef604SKeke Li struct v4l2_subdev_state *state, 469b63ef604SKeke Li struct v4l2_subdev_mbus_code_enum *code) 470b63ef604SKeke Li { 471b63ef604SKeke Li struct v4l2_mbus_framefmt *fmt; 472b63ef604SKeke Li 473b63ef604SKeke Li switch (code->pad) { 474b63ef604SKeke Li case C3_MIPI_CSI2_PAD_SINK: 475b63ef604SKeke Li if (code->index >= ARRAY_SIZE(c3_mipi_csi_formats)) 476b63ef604SKeke Li return -EINVAL; 477b63ef604SKeke Li 478b63ef604SKeke Li code->code = c3_mipi_csi_formats[code->index]; 479b63ef604SKeke Li break; 480b63ef604SKeke Li case C3_MIPI_CSI2_PAD_SRC: 481b63ef604SKeke Li if (code->index) 482b63ef604SKeke Li return -EINVAL; 483b63ef604SKeke Li 484b63ef604SKeke Li fmt = v4l2_subdev_state_get_format(state, code->pad); 485b63ef604SKeke Li code->code = fmt->code; 486b63ef604SKeke Li break; 487b63ef604SKeke Li default: 488b63ef604SKeke Li return -EINVAL; 489b63ef604SKeke Li } 490b63ef604SKeke Li 491b63ef604SKeke Li return 0; 492b63ef604SKeke Li } 493b63ef604SKeke Li 494b63ef604SKeke Li static int c3_mipi_csi_set_fmt(struct v4l2_subdev *sd, 495b63ef604SKeke Li struct v4l2_subdev_state *state, 496b63ef604SKeke Li struct v4l2_subdev_format *format) 497b63ef604SKeke Li { 498b63ef604SKeke Li struct v4l2_mbus_framefmt *fmt; 499b63ef604SKeke Li unsigned int i; 500b63ef604SKeke Li 501b63ef604SKeke Li if (format->pad != C3_MIPI_CSI2_PAD_SINK) 502b63ef604SKeke Li return v4l2_subdev_get_fmt(sd, state, format); 503b63ef604SKeke Li 504b63ef604SKeke Li fmt = v4l2_subdev_state_get_format(state, format->pad); 505b63ef604SKeke Li 506b63ef604SKeke Li for (i = 0; i < ARRAY_SIZE(c3_mipi_csi_formats); i++) { 507b63ef604SKeke Li if (format->format.code == c3_mipi_csi_formats[i]) { 508b63ef604SKeke Li fmt->code = c3_mipi_csi_formats[i]; 509b63ef604SKeke Li break; 510b63ef604SKeke Li } 511b63ef604SKeke Li } 512b63ef604SKeke Li 513b63ef604SKeke Li if (i == ARRAY_SIZE(c3_mipi_csi_formats)) 514b63ef604SKeke Li fmt->code = c3_mipi_csi_formats[0]; 515b63ef604SKeke Li 516b63ef604SKeke Li fmt->width = clamp_t(u32, format->format.width, 517b63ef604SKeke Li C3_MIPI_CSI2_MIN_WIDTH, C3_MIPI_CSI2_MAX_WIDTH); 518b63ef604SKeke Li fmt->height = clamp_t(u32, format->format.height, 519b63ef604SKeke Li C3_MIPI_CSI2_MIN_HEIGHT, C3_MIPI_CSI2_MAX_HEIGHT); 520b63ef604SKeke Li fmt->colorspace = V4L2_COLORSPACE_RAW; 521b63ef604SKeke Li fmt->xfer_func = V4L2_XFER_FUNC_NONE; 522b63ef604SKeke Li fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 523b63ef604SKeke Li fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 524b63ef604SKeke Li 525b63ef604SKeke Li format->format = *fmt; 526b63ef604SKeke Li 527b63ef604SKeke Li /* Synchronize the format to source pad */ 528b63ef604SKeke Li fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SRC); 529b63ef604SKeke Li *fmt = format->format; 530b63ef604SKeke Li 531b63ef604SKeke Li return 0; 532b63ef604SKeke Li } 533b63ef604SKeke Li 534b63ef604SKeke Li static int c3_mipi_csi_init_state(struct v4l2_subdev *sd, 535b63ef604SKeke Li struct v4l2_subdev_state *state) 536b63ef604SKeke Li { 537b63ef604SKeke Li struct v4l2_mbus_framefmt *sink_fmt; 538b63ef604SKeke Li struct v4l2_mbus_framefmt *src_fmt; 539b63ef604SKeke Li 540b63ef604SKeke Li sink_fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SINK); 541b63ef604SKeke Li src_fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SRC); 542b63ef604SKeke Li 543b63ef604SKeke Li sink_fmt->width = C3_MIPI_CSI2_DEFAULT_WIDTH; 544b63ef604SKeke Li sink_fmt->height = C3_MIPI_CSI2_DEFAULT_HEIGHT; 545b63ef604SKeke Li sink_fmt->field = V4L2_FIELD_NONE; 546b63ef604SKeke Li sink_fmt->code = C3_MIPI_CSI2_DEFAULT_FMT; 547b63ef604SKeke Li sink_fmt->colorspace = V4L2_COLORSPACE_RAW; 548b63ef604SKeke Li sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 549b63ef604SKeke Li sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 550b63ef604SKeke Li sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 551b63ef604SKeke Li 552b63ef604SKeke Li *src_fmt = *sink_fmt; 553b63ef604SKeke Li 554b63ef604SKeke Li return 0; 555b63ef604SKeke Li } 556b63ef604SKeke Li 557b63ef604SKeke Li static const struct v4l2_subdev_pad_ops c3_mipi_csi_pad_ops = { 558b63ef604SKeke Li .enum_mbus_code = c3_mipi_csi_enum_mbus_code, 559b63ef604SKeke Li .get_fmt = v4l2_subdev_get_fmt, 560b63ef604SKeke Li .set_fmt = c3_mipi_csi_set_fmt, 561b63ef604SKeke Li .enable_streams = c3_mipi_csi_enable_streams, 562b63ef604SKeke Li .disable_streams = c3_mipi_csi_disable_streams, 563b63ef604SKeke Li }; 564b63ef604SKeke Li 565b63ef604SKeke Li static const struct v4l2_subdev_ops c3_mipi_csi_subdev_ops = { 566b63ef604SKeke Li .pad = &c3_mipi_csi_pad_ops, 567b63ef604SKeke Li }; 568b63ef604SKeke Li 569b63ef604SKeke Li static const struct v4l2_subdev_internal_ops c3_mipi_csi_internal_ops = { 570b63ef604SKeke Li .init_state = c3_mipi_csi_init_state, 571b63ef604SKeke Li }; 572b63ef604SKeke Li 573b63ef604SKeke Li /* Media entity operations */ 574b63ef604SKeke Li static const struct media_entity_operations c3_mipi_csi_entity_ops = { 575b63ef604SKeke Li .link_validate = v4l2_subdev_link_validate, 576b63ef604SKeke Li }; 577b63ef604SKeke Li 578b63ef604SKeke Li /* PM runtime */ 579b63ef604SKeke Li 580b63ef604SKeke Li static int c3_mipi_csi_runtime_suspend(struct device *dev) 581b63ef604SKeke Li { 582b63ef604SKeke Li struct c3_csi_device *csi = dev_get_drvdata(dev); 583b63ef604SKeke Li 584b63ef604SKeke Li clk_bulk_disable_unprepare(csi->info->clock_num, csi->clks); 585b63ef604SKeke Li 586b63ef604SKeke Li return 0; 587b63ef604SKeke Li } 588b63ef604SKeke Li 589b63ef604SKeke Li static int c3_mipi_csi_runtime_resume(struct device *dev) 590b63ef604SKeke Li { 591b63ef604SKeke Li struct c3_csi_device *csi = dev_get_drvdata(dev); 592b63ef604SKeke Li 593b63ef604SKeke Li return clk_bulk_prepare_enable(csi->info->clock_num, csi->clks); 594b63ef604SKeke Li } 595b63ef604SKeke Li 596b63ef604SKeke Li static const struct dev_pm_ops c3_mipi_csi_pm_ops = { 597b63ef604SKeke Li SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 598b63ef604SKeke Li pm_runtime_force_resume) 599b63ef604SKeke Li RUNTIME_PM_OPS(c3_mipi_csi_runtime_suspend, 600b63ef604SKeke Li c3_mipi_csi_runtime_resume, NULL) 601b63ef604SKeke Li }; 602b63ef604SKeke Li 603b63ef604SKeke Li /* Probe/remove & platform driver */ 604b63ef604SKeke Li 605b63ef604SKeke Li static int c3_mipi_csi_subdev_init(struct c3_csi_device *csi) 606b63ef604SKeke Li { 607b63ef604SKeke Li struct v4l2_subdev *sd = &csi->sd; 608b63ef604SKeke Li int ret; 609b63ef604SKeke Li 610b63ef604SKeke Li v4l2_subdev_init(sd, &c3_mipi_csi_subdev_ops); 611b63ef604SKeke Li sd->owner = THIS_MODULE; 612b63ef604SKeke Li sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 613b63ef604SKeke Li sd->internal_ops = &c3_mipi_csi_internal_ops; 614b63ef604SKeke Li snprintf(sd->name, sizeof(sd->name), "%s", MIPI_CSI2_SUBDEV_NAME); 615b63ef604SKeke Li 616b63ef604SKeke Li sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 617b63ef604SKeke Li sd->entity.ops = &c3_mipi_csi_entity_ops; 618b63ef604SKeke Li 619b63ef604SKeke Li sd->dev = csi->dev; 620b63ef604SKeke Li v4l2_set_subdevdata(sd, csi); 621b63ef604SKeke Li 622b63ef604SKeke Li csi->pads[C3_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 623b63ef604SKeke Li csi->pads[C3_MIPI_CSI2_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; 624b63ef604SKeke Li ret = media_entity_pads_init(&sd->entity, C3_MIPI_CSI2_PAD_MAX, 625b63ef604SKeke Li csi->pads); 626b63ef604SKeke Li if (ret) 627b63ef604SKeke Li return ret; 628b63ef604SKeke Li 629b63ef604SKeke Li ret = v4l2_subdev_init_finalize(sd); 630b63ef604SKeke Li if (ret) { 631b63ef604SKeke Li media_entity_cleanup(&sd->entity); 632b63ef604SKeke Li return ret; 633b63ef604SKeke Li } 634b63ef604SKeke Li 635b63ef604SKeke Li return 0; 636b63ef604SKeke Li } 637b63ef604SKeke Li 638b63ef604SKeke Li static void c3_mipi_csi_subdev_deinit(struct c3_csi_device *csi) 639b63ef604SKeke Li { 640b63ef604SKeke Li v4l2_subdev_cleanup(&csi->sd); 641b63ef604SKeke Li media_entity_cleanup(&csi->sd.entity); 642b63ef604SKeke Li } 643b63ef604SKeke Li 644b63ef604SKeke Li /* Subdev notifier register */ 645b63ef604SKeke Li static int c3_mipi_csi_notify_bound(struct v4l2_async_notifier *notifier, 646b63ef604SKeke Li struct v4l2_subdev *sd, 647b63ef604SKeke Li struct v4l2_async_connection *asc) 648b63ef604SKeke Li { 649b63ef604SKeke Li struct c3_csi_device *csi = v4l2_get_subdevdata(notifier->sd); 650b63ef604SKeke Li struct media_pad *sink = &csi->sd.entity.pads[C3_MIPI_CSI2_PAD_SINK]; 651b63ef604SKeke Li 652b63ef604SKeke Li return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED | 653b63ef604SKeke Li MEDIA_LNK_FL_IMMUTABLE); 654b63ef604SKeke Li } 655b63ef604SKeke Li 656b63ef604SKeke Li static const struct v4l2_async_notifier_operations c3_mipi_csi_notify_ops = { 657b63ef604SKeke Li .bound = c3_mipi_csi_notify_bound, 658b63ef604SKeke Li }; 659b63ef604SKeke Li 660b63ef604SKeke Li static int c3_mipi_csi_async_register(struct c3_csi_device *csi) 661b63ef604SKeke Li { 662b63ef604SKeke Li struct v4l2_fwnode_endpoint vep = { 663b63ef604SKeke Li .bus_type = V4L2_MBUS_CSI2_DPHY, 664b63ef604SKeke Li }; 665b63ef604SKeke Li struct v4l2_async_connection *asc; 666b63ef604SKeke Li struct fwnode_handle *ep; 667b63ef604SKeke Li int ret; 668b63ef604SKeke Li 669b63ef604SKeke Li v4l2_async_subdev_nf_init(&csi->notifier, &csi->sd); 670b63ef604SKeke Li 671b63ef604SKeke Li ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0, 672b63ef604SKeke Li FWNODE_GRAPH_ENDPOINT_NEXT); 673b63ef604SKeke Li if (!ep) 674b63ef604SKeke Li return -ENOTCONN; 675b63ef604SKeke Li 676b63ef604SKeke Li ret = v4l2_fwnode_endpoint_parse(ep, &vep); 677b63ef604SKeke Li if (ret) 678b63ef604SKeke Li goto err_put_handle; 679b63ef604SKeke Li 680b63ef604SKeke Li csi->bus = vep.bus.mipi_csi2; 681b63ef604SKeke Li 682b63ef604SKeke Li asc = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep, 683b63ef604SKeke Li struct v4l2_async_connection); 684b63ef604SKeke Li if (IS_ERR(asc)) { 685b63ef604SKeke Li ret = PTR_ERR(asc); 686b63ef604SKeke Li goto err_put_handle; 687b63ef604SKeke Li } 688b63ef604SKeke Li 689b63ef604SKeke Li csi->notifier.ops = &c3_mipi_csi_notify_ops; 690b63ef604SKeke Li ret = v4l2_async_nf_register(&csi->notifier); 691b63ef604SKeke Li if (ret) 692b63ef604SKeke Li goto err_cleanup_nf; 693b63ef604SKeke Li 694b63ef604SKeke Li ret = v4l2_async_register_subdev(&csi->sd); 695b63ef604SKeke Li if (ret) 696b63ef604SKeke Li goto err_unregister_nf; 697b63ef604SKeke Li 698b63ef604SKeke Li fwnode_handle_put(ep); 699b63ef604SKeke Li 700b63ef604SKeke Li return 0; 701b63ef604SKeke Li 702b63ef604SKeke Li err_unregister_nf: 703b63ef604SKeke Li v4l2_async_nf_unregister(&csi->notifier); 704b63ef604SKeke Li err_cleanup_nf: 705b63ef604SKeke Li v4l2_async_nf_cleanup(&csi->notifier); 706b63ef604SKeke Li err_put_handle: 707b63ef604SKeke Li fwnode_handle_put(ep); 708b63ef604SKeke Li return ret; 709b63ef604SKeke Li } 710b63ef604SKeke Li 711b63ef604SKeke Li static void c3_mipi_csi_async_unregister(struct c3_csi_device *csi) 712b63ef604SKeke Li { 713b63ef604SKeke Li v4l2_async_unregister_subdev(&csi->sd); 714b63ef604SKeke Li v4l2_async_nf_unregister(&csi->notifier); 715b63ef604SKeke Li v4l2_async_nf_cleanup(&csi->notifier); 716b63ef604SKeke Li } 717b63ef604SKeke Li 718b63ef604SKeke Li static int c3_mipi_csi_ioremap_resource(struct c3_csi_device *csi) 719b63ef604SKeke Li { 720b63ef604SKeke Li struct device *dev = csi->dev; 721b63ef604SKeke Li struct platform_device *pdev = to_platform_device(dev); 722b63ef604SKeke Li 723b63ef604SKeke Li csi->aphy = devm_platform_ioremap_resource_byname(pdev, "aphy"); 724b63ef604SKeke Li if (IS_ERR(csi->aphy)) 725b63ef604SKeke Li return PTR_ERR(csi->aphy); 726b63ef604SKeke Li 727b63ef604SKeke Li csi->dphy = devm_platform_ioremap_resource_byname(pdev, "dphy"); 728b63ef604SKeke Li if (IS_ERR(csi->dphy)) 729b63ef604SKeke Li return PTR_ERR(csi->dphy); 730b63ef604SKeke Li 731b63ef604SKeke Li csi->host = devm_platform_ioremap_resource_byname(pdev, "host"); 732b63ef604SKeke Li if (IS_ERR(csi->host)) 733b63ef604SKeke Li return PTR_ERR(csi->host); 734b63ef604SKeke Li 735b63ef604SKeke Li return 0; 736b63ef604SKeke Li } 737b63ef604SKeke Li 738b63ef604SKeke Li static int c3_mipi_csi_get_clocks(struct c3_csi_device *csi) 739b63ef604SKeke Li { 740b63ef604SKeke Li const struct c3_csi_info *info = csi->info; 741b63ef604SKeke Li 742b63ef604SKeke Li for (unsigned int i = 0; i < info->clock_num; i++) 743b63ef604SKeke Li csi->clks[i].id = info->clocks[i]; 744b63ef604SKeke Li 745b63ef604SKeke Li return devm_clk_bulk_get(csi->dev, info->clock_num, csi->clks); 746b63ef604SKeke Li } 747b63ef604SKeke Li 748b63ef604SKeke Li static int c3_mipi_csi_probe(struct platform_device *pdev) 749b63ef604SKeke Li { 750b63ef604SKeke Li struct device *dev = &pdev->dev; 751b63ef604SKeke Li struct c3_csi_device *csi; 752b63ef604SKeke Li int ret; 753b63ef604SKeke Li 754b63ef604SKeke Li csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL); 755b63ef604SKeke Li if (!csi) 756b63ef604SKeke Li return -ENOMEM; 757b63ef604SKeke Li 758b63ef604SKeke Li csi->info = of_device_get_match_data(dev); 759b63ef604SKeke Li csi->dev = dev; 760b63ef604SKeke Li 761b63ef604SKeke Li ret = c3_mipi_csi_ioremap_resource(csi); 762b63ef604SKeke Li if (ret) 763b63ef604SKeke Li return dev_err_probe(dev, ret, "Failed to ioremap resource\n"); 764b63ef604SKeke Li 765b63ef604SKeke Li ret = c3_mipi_csi_get_clocks(csi); 766b63ef604SKeke Li if (ret) 767b63ef604SKeke Li return dev_err_probe(dev, ret, "Failed to get clocks\n"); 768b63ef604SKeke Li 769b63ef604SKeke Li platform_set_drvdata(pdev, csi); 770b63ef604SKeke Li 771b63ef604SKeke Li pm_runtime_enable(dev); 772b63ef604SKeke Li 773b63ef604SKeke Li ret = c3_mipi_csi_subdev_init(csi); 774b63ef604SKeke Li if (ret) 775b63ef604SKeke Li goto err_disable_runtime_pm; 776b63ef604SKeke Li 777b63ef604SKeke Li ret = c3_mipi_csi_async_register(csi); 778b63ef604SKeke Li if (ret) 779b63ef604SKeke Li goto err_deinit_subdev; 780b63ef604SKeke Li 781b63ef604SKeke Li return 0; 782b63ef604SKeke Li 783b63ef604SKeke Li err_deinit_subdev: 784b63ef604SKeke Li c3_mipi_csi_subdev_deinit(csi); 785b63ef604SKeke Li err_disable_runtime_pm: 786b63ef604SKeke Li pm_runtime_disable(dev); 787b63ef604SKeke Li return ret; 788b63ef604SKeke Li }; 789b63ef604SKeke Li 790b63ef604SKeke Li static void c3_mipi_csi_remove(struct platform_device *pdev) 791b63ef604SKeke Li { 792b63ef604SKeke Li struct c3_csi_device *csi = platform_get_drvdata(pdev); 793b63ef604SKeke Li 794b63ef604SKeke Li c3_mipi_csi_async_unregister(csi); 795b63ef604SKeke Li c3_mipi_csi_subdev_deinit(csi); 796b63ef604SKeke Li 797b63ef604SKeke Li pm_runtime_disable(&pdev->dev); 798b63ef604SKeke Li }; 799b63ef604SKeke Li 800b63ef604SKeke Li static const struct c3_csi_info c3_mipi_csi_info = { 801b63ef604SKeke Li .clocks = {"vapb", "phy0"}, 802b63ef604SKeke Li .clock_num = 2 803b63ef604SKeke Li }; 804b63ef604SKeke Li 805b63ef604SKeke Li static const struct of_device_id c3_mipi_csi_of_match[] = { 806b63ef604SKeke Li { 807b63ef604SKeke Li .compatible = "amlogic,c3-mipi-csi2", 808b63ef604SKeke Li .data = &c3_mipi_csi_info, 809b63ef604SKeke Li }, 810b63ef604SKeke Li { }, 811b63ef604SKeke Li }; 812b63ef604SKeke Li MODULE_DEVICE_TABLE(of, c3_mipi_csi_of_match); 813b63ef604SKeke Li 814b63ef604SKeke Li static struct platform_driver c3_mipi_csi_driver = { 815b63ef604SKeke Li .probe = c3_mipi_csi_probe, 816b63ef604SKeke Li .remove = c3_mipi_csi_remove, 817b63ef604SKeke Li .driver = { 818b63ef604SKeke Li .name = "c3-mipi-csi2", 819b63ef604SKeke Li .of_match_table = c3_mipi_csi_of_match, 820b63ef604SKeke Li .pm = pm_ptr(&c3_mipi_csi_pm_ops), 821b63ef604SKeke Li }, 822b63ef604SKeke Li }; 823b63ef604SKeke Li 824b63ef604SKeke Li module_platform_driver(c3_mipi_csi_driver); 825b63ef604SKeke Li 826b63ef604SKeke Li MODULE_AUTHOR("Keke Li <keke.li@amlogic.com>"); 827b63ef604SKeke Li MODULE_DESCRIPTION("Amlogic C3 MIPI CSI-2 receiver"); 828b63ef604SKeke Li MODULE_LICENSE("GPL"); 829