1be1589e5SKate Hsuan // SPDX-License-Identifier: GPL-2.0 2be1589e5SKate Hsuan /* 3be1589e5SKate Hsuan * imx471.c - imx471 sensor driver 4be1589e5SKate Hsuan * 5be1589e5SKate Hsuan * Copyright (C) 2025 Intel Corporation 6be1589e5SKate Hsuan * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com> 7be1589e5SKate Hsuan */ 8be1589e5SKate Hsuan 9be1589e5SKate Hsuan #include <linux/clk.h> 10be1589e5SKate Hsuan #include <linux/delay.h> 11be1589e5SKate Hsuan #include <linux/i2c.h> 12be1589e5SKate Hsuan #include <linux/module.h> 13be1589e5SKate Hsuan #include <linux/pm_runtime.h> 14be1589e5SKate Hsuan #include <linux/regulator/consumer.h> 15be1589e5SKate Hsuan #include <media/v4l2-cci.h> 16be1589e5SKate Hsuan #include <media/v4l2-ctrls.h> 17be1589e5SKate Hsuan #include <media/v4l2-subdev.h> 18be1589e5SKate Hsuan #include <media/v4l2-fwnode.h> 19be1589e5SKate Hsuan 20be1589e5SKate Hsuan #define IMX471_REG_MODE_SELECT CCI_REG8(0x0100) 21be1589e5SKate Hsuan #define IMX471_MODE_STANDBY 0x00 22be1589e5SKate Hsuan #define IMX471_MODE_STREAMING 0x01 23be1589e5SKate Hsuan 24be1589e5SKate Hsuan /* Chip ID */ 25be1589e5SKate Hsuan #define IMX471_REG_CHIP_ID CCI_REG16(0x0016) 26be1589e5SKate Hsuan #define IMX471_CHIP_ID 0x0471 27be1589e5SKate Hsuan 28be1589e5SKate Hsuan /* V_TIMING internal */ 29be1589e5SKate Hsuan #define IMX471_REG_FLL CCI_REG16(0x0340) 30be1589e5SKate Hsuan #define IMX471_FLL_MAX 0xffff 31be1589e5SKate Hsuan 32be1589e5SKate Hsuan /* Exposure control */ 33be1589e5SKate Hsuan #define IMX471_REG_EXPOSURE CCI_REG16(0x0202) 34be1589e5SKate Hsuan #define IMX471_EXPOSURE_MIN 1 35be1589e5SKate Hsuan #define IMX471_EXPOSURE_STEP 1 36be1589e5SKate Hsuan #define IMX471_EXPOSURE_DEFAULT 1270 37be1589e5SKate Hsuan 38be1589e5SKate Hsuan /* Default exposure margin */ 39be1589e5SKate Hsuan #define IMX471_EXPOSURE_MARGIN 18 40be1589e5SKate Hsuan 41be1589e5SKate Hsuan /* Analog gain control */ 42be1589e5SKate Hsuan #define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204) 43be1589e5SKate Hsuan #define IMX471_ANA_GAIN_MIN 0 44be1589e5SKate Hsuan #define IMX471_ANA_GAIN_MAX 800 45be1589e5SKate Hsuan #define IMX471_ANA_GAIN_STEP 1 46be1589e5SKate Hsuan #define IMX471_ANA_GAIN_DEFAULT 0 47be1589e5SKate Hsuan 48be1589e5SKate Hsuan /* Digital gain control */ 49be1589e5SKate Hsuan #define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9) 50be1589e5SKate Hsuan #define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) 51be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_MIN 256 52be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_MAX 4095 53be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_STEP 1 54be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_DEFAULT 256 55be1589e5SKate Hsuan 56be1589e5SKate Hsuan /* HFLIP and VFLIP control */ 57be1589e5SKate Hsuan #define IMX471_REG_ORIENTATION CCI_REG8(0x0101) 58be1589e5SKate Hsuan 59be1589e5SKate Hsuan /* Test Pattern Control */ 60be1589e5SKate Hsuan #define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600) 61be1589e5SKate Hsuan 62be1589e5SKate Hsuan /* default link frequency and external clock */ 63be1589e5SKate Hsuan #define IMX471_LINK_FREQ_DEFAULT 200000000LL 64be1589e5SKate Hsuan #define IMX471_EXT_CLK 19200000 65be1589e5SKate Hsuan 66be1589e5SKate Hsuan /* PLL */ 67be1589e5SKate Hsuan #define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301) 68be1589e5SKate Hsuan #define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303) 69be1589e5SKate Hsuan #define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305) 70be1589e5SKate Hsuan #define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306) 71be1589e5SKate Hsuan #define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309) 72be1589e5SKate Hsuan #define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b) 73be1589e5SKate Hsuan #define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310) 74be1589e5SKate Hsuan #define IMX471_PLL_SINGLE 0 75be1589e5SKate Hsuan #define IMX471_PLL_DUAL 1 76be1589e5SKate Hsuan 77be1589e5SKate Hsuan /* IMX471 native and active pixel array size */ 78be1589e5SKate Hsuan #define IMX471_NATIVE_WIDTH 4672 79be1589e5SKate Hsuan #define IMX471_NATIVE_HEIGHT 3512 80be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_LEFT 8 81be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_TOP 8 82be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_WIDTH 4656 83be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_HEIGHT 3496 84be1589e5SKate Hsuan 85be1589e5SKate Hsuan #define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136) 86be1589e5SKate Hsuan 87be1589e5SKate Hsuan #define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112) 88be1589e5SKate Hsuan #define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a 89be1589e5SKate Hsuan 90be1589e5SKate Hsuan #define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114) 91be1589e5SKate Hsuan #define IMX471_CSI_2_LANE_MODE 1 92be1589e5SKate Hsuan #define IMX471_CSI_4_LANE_MODE 3 93be1589e5SKate Hsuan 94be1589e5SKate Hsuan #define IMX471_REG_X_ADD_STA CCI_REG16(0x0344) 95be1589e5SKate Hsuan #define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346) 96be1589e5SKate Hsuan #define IMX471_REG_X_ADD_END CCI_REG16(0x0348) 97be1589e5SKate Hsuan #define IMX471_REG_Y_ADD_END CCI_REG16(0x034a) 98be1589e5SKate Hsuan #define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c) 99be1589e5SKate Hsuan #define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e) 100be1589e5SKate Hsuan #define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381) 101be1589e5SKate Hsuan #define IMX471_REG_X_ODD_INC CCI_REG8(0x0383) 102be1589e5SKate Hsuan #define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385) 103be1589e5SKate Hsuan #define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387) 104be1589e5SKate Hsuan 105be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408) 106be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a) 107be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c) 108be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e) 109be1589e5SKate Hsuan 110be1589e5SKate Hsuan /* Binning mode */ 111be1589e5SKate Hsuan #define IMX471_REG_BINNING_MODE CCI_REG8(0x0900) 112be1589e5SKate Hsuan #define IMX471_BINNING_NONE 0 113be1589e5SKate Hsuan #define IMX471_BINNING_ENABLE 1 114be1589e5SKate Hsuan #define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901) 115be1589e5SKate Hsuan #define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902) 116be1589e5SKate Hsuan 117be1589e5SKate Hsuan #define to_imx471(_sd) container_of_const(_sd, struct imx471, sd) 118be1589e5SKate Hsuan 119be1589e5SKate Hsuan static const char * const imx471_supply_name[] = { 120be1589e5SKate Hsuan "vana", 121be1589e5SKate Hsuan }; 122be1589e5SKate Hsuan 123be1589e5SKate Hsuan struct imx471_mode { 124be1589e5SKate Hsuan u32 width; 125be1589e5SKate Hsuan u32 height; 126be1589e5SKate Hsuan 127be1589e5SKate Hsuan /* V-timing */ 128be1589e5SKate Hsuan u32 fll_def; 129be1589e5SKate Hsuan u32 fll_min; 130be1589e5SKate Hsuan 131be1589e5SKate Hsuan /* H-timing */ 132be1589e5SKate Hsuan u32 llp; 133be1589e5SKate Hsuan 134be1589e5SKate Hsuan const struct cci_reg_sequence *default_mode_regs; 135be1589e5SKate Hsuan unsigned int default_mode_regs_length; 136be1589e5SKate Hsuan }; 137be1589e5SKate Hsuan 138be1589e5SKate Hsuan struct imx471 { 139be1589e5SKate Hsuan struct v4l2_subdev sd; 140be1589e5SKate Hsuan struct media_pad pad; 141be1589e5SKate Hsuan 142be1589e5SKate Hsuan struct v4l2_ctrl_handler ctrl_handler; 143be1589e5SKate Hsuan struct v4l2_ctrl *vblank; 144be1589e5SKate Hsuan struct v4l2_ctrl *hblank; 145be1589e5SKate Hsuan struct v4l2_ctrl *vflip; 146be1589e5SKate Hsuan struct v4l2_ctrl *hflip; 147be1589e5SKate Hsuan struct v4l2_ctrl *exposure; 148be1589e5SKate Hsuan 149be1589e5SKate Hsuan struct gpio_desc *reset_gpio; 150be1589e5SKate Hsuan struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)]; 151be1589e5SKate Hsuan struct clk *img_clk; 152be1589e5SKate Hsuan 153be1589e5SKate Hsuan struct device *dev; 154be1589e5SKate Hsuan struct regmap *regmap; 155be1589e5SKate Hsuan }; 156be1589e5SKate Hsuan 157be1589e5SKate Hsuan static const struct cci_reg_sequence imx471_global_regs[] = { 158be1589e5SKate Hsuan { IMX471_REG_EXCK_FREQ, 0x1333 }, 159be1589e5SKate Hsuan { CCI_REG8(0x3c7e), 0x08 }, 160be1589e5SKate Hsuan { CCI_REG8(0x3c7f), 0x05 }, 161be1589e5SKate Hsuan { CCI_REG8(0x3e35), 0x00 }, 162be1589e5SKate Hsuan { CCI_REG8(0x3e36), 0x00 }, 163be1589e5SKate Hsuan { CCI_REG8(0x3e37), 0x00 }, 164be1589e5SKate Hsuan { CCI_REG8(0x3f7f), 0x01 }, 165be1589e5SKate Hsuan { CCI_REG8(0x4431), 0x04 }, 166be1589e5SKate Hsuan { CCI_REG8(0x531c), 0x01 }, 167be1589e5SKate Hsuan { CCI_REG8(0x531d), 0x02 }, 168be1589e5SKate Hsuan { CCI_REG8(0x531e), 0x04 }, 169be1589e5SKate Hsuan { CCI_REG8(0x5928), 0x00 }, 170be1589e5SKate Hsuan { CCI_REG8(0x5929), 0x2f }, 171be1589e5SKate Hsuan { CCI_REG8(0x592a), 0x00 }, 172be1589e5SKate Hsuan { CCI_REG8(0x592b), 0x85 }, 173be1589e5SKate Hsuan { CCI_REG8(0x592c), 0x00 }, 174be1589e5SKate Hsuan { CCI_REG8(0x592d), 0x32 }, 175be1589e5SKate Hsuan { CCI_REG8(0x592e), 0x00 }, 176be1589e5SKate Hsuan { CCI_REG8(0x592f), 0x88 }, 177be1589e5SKate Hsuan { CCI_REG8(0x5930), 0x00 }, 178be1589e5SKate Hsuan { CCI_REG8(0x5931), 0x3d }, 179be1589e5SKate Hsuan { CCI_REG8(0x5932), 0x00 }, 180be1589e5SKate Hsuan { CCI_REG8(0x5933), 0x93 }, 181be1589e5SKate Hsuan { CCI_REG8(0x5938), 0x00 }, 182be1589e5SKate Hsuan { CCI_REG8(0x5939), 0x24 }, 183be1589e5SKate Hsuan { CCI_REG8(0x593a), 0x00 }, 184be1589e5SKate Hsuan { CCI_REG8(0x593b), 0x7a }, 185be1589e5SKate Hsuan { CCI_REG8(0x593c), 0x00 }, 186be1589e5SKate Hsuan { CCI_REG8(0x593d), 0x24 }, 187be1589e5SKate Hsuan { CCI_REG8(0x593e), 0x00 }, 188be1589e5SKate Hsuan { CCI_REG8(0x593f), 0x7a }, 189be1589e5SKate Hsuan { CCI_REG8(0x5940), 0x00 }, 190be1589e5SKate Hsuan { CCI_REG8(0x5941), 0x2f }, 191be1589e5SKate Hsuan { CCI_REG8(0x5942), 0x00 }, 192be1589e5SKate Hsuan { CCI_REG8(0x5943), 0x85 }, 193be1589e5SKate Hsuan { CCI_REG8(0x5f0e), 0x6e }, 194be1589e5SKate Hsuan { CCI_REG8(0x5f11), 0xc6 }, 195be1589e5SKate Hsuan { CCI_REG8(0x5f17), 0x5e }, 196be1589e5SKate Hsuan { CCI_REG8(0x7990), 0x01 }, 197be1589e5SKate Hsuan { CCI_REG8(0x7993), 0x5d }, 198be1589e5SKate Hsuan { CCI_REG8(0x7994), 0x5d }, 199be1589e5SKate Hsuan { CCI_REG8(0x7995), 0xa1 }, 200be1589e5SKate Hsuan { CCI_REG8(0x799a), 0x01 }, 201be1589e5SKate Hsuan { CCI_REG8(0x799d), 0x00 }, 202be1589e5SKate Hsuan { CCI_REG8(0x8169), 0x01 }, 203be1589e5SKate Hsuan { CCI_REG8(0x8359), 0x01 }, 204be1589e5SKate Hsuan { CCI_REG8(0x9302), 0x1e }, 205be1589e5SKate Hsuan { CCI_REG8(0x9306), 0x1f }, 206be1589e5SKate Hsuan { CCI_REG8(0x930a), 0x26 }, 207be1589e5SKate Hsuan { CCI_REG8(0x930e), 0x23 }, 208be1589e5SKate Hsuan { CCI_REG8(0x9312), 0x23 }, 209be1589e5SKate Hsuan { CCI_REG8(0x9316), 0x2c }, 210be1589e5SKate Hsuan { CCI_REG8(0x9317), 0x19 }, 211be1589e5SKate Hsuan { CCI_REG8(0xb046), 0x01 }, 212be1589e5SKate Hsuan { CCI_REG8(0xb048), 0x01 }, 213be1589e5SKate Hsuan }; 214be1589e5SKate Hsuan 215be1589e5SKate Hsuan static const struct cci_reg_sequence mode_1928x1088_regs[] = { 216be1589e5SKate Hsuan { IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 }, 217be1589e5SKate Hsuan { IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE }, 218be1589e5SKate Hsuan { IMX471_REG_X_ADD_STA, 8 }, 219be1589e5SKate Hsuan { IMX471_REG_Y_ADD_STA, 408 }, 220be1589e5SKate Hsuan { IMX471_REG_X_ADD_END, 4647 }, 221be1589e5SKate Hsuan { IMX471_REG_Y_ADD_END, 3051 }, 222be1589e5SKate Hsuan { IMX471_REG_X_EVEN_INC, 1 }, 223be1589e5SKate Hsuan { IMX471_REG_X_ODD_INC, 1 }, 224be1589e5SKate Hsuan { IMX471_REG_Y_EVEN_INC, 1 }, 225be1589e5SKate Hsuan { IMX471_REG_Y_ODD_INC, 1 }, 226be1589e5SKate Hsuan { IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE }, 227be1589e5SKate Hsuan { IMX471_REG_BINNING_TYPE, 0x22 }, 228be1589e5SKate Hsuan { IMX471_REG_BINNING_WEIGHTING, 0x08 }, 229be1589e5SKate Hsuan { IMX471_REG_DIG_CROP_X_OFFSET, 208 }, 230be1589e5SKate Hsuan { IMX471_REG_DIG_CROP_Y_OFFSET, 108 }, 231be1589e5SKate Hsuan { IMX471_REG_DIG_CROP_WIDTH, 1928 }, 232be1589e5SKate Hsuan { IMX471_REG_DIG_CROP_HEIGHT, 1088 }, 233be1589e5SKate Hsuan { IMX471_REG_X_OUTPUT_SIZE, 1928 }, 234be1589e5SKate Hsuan { IMX471_REG_Y_OUTPUT_SIZE, 1088 }, 235be1589e5SKate Hsuan { IMX471_REG_VTPXCK_DIV, 0x06 }, 236be1589e5SKate Hsuan { IMX471_REG_VTSYCK_DIV, 0x02 }, 237be1589e5SKate Hsuan { IMX471_REG_PREPLLCK_VT_DIV, 0x02 }, 238be1589e5SKate Hsuan { IMX471_REG_PLL_VT_MPY, 0x0079 }, 239be1589e5SKate Hsuan { IMX471_REG_OPSYCK_DIV, 0x01 }, 240be1589e5SKate Hsuan { CCI_REG8(0x030d), 0x02 }, 241be1589e5SKate Hsuan { CCI_REG8(0x030e), 0x00 }, 242be1589e5SKate Hsuan { CCI_REG8(0x030f), 0x53 }, 243be1589e5SKate Hsuan { IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL }, 244be1589e5SKate Hsuan { CCI_REG8(0x3f4c), 0x81 }, 245be1589e5SKate Hsuan { CCI_REG8(0x3f4d), 0x81 }, 246be1589e5SKate Hsuan { CCI_REG8(0x3f78), 0x01 }, 247be1589e5SKate Hsuan { CCI_REG8(0x3f79), 0x31 }, 248be1589e5SKate Hsuan { CCI_REG8(0x3ffe), 0x00 }, 249be1589e5SKate Hsuan { CCI_REG8(0x3fff), 0x8a }, 250be1589e5SKate Hsuan { CCI_REG8(0x5f0a), 0xb6 }, 251be1589e5SKate Hsuan }; 252be1589e5SKate Hsuan 253be1589e5SKate Hsuan static const char * const imx471_test_pattern_menu[] = { 254be1589e5SKate Hsuan "Disabled", 255be1589e5SKate Hsuan "Solid Colour", 256be1589e5SKate Hsuan "Eight Vertical Colour Bars", 257be1589e5SKate Hsuan "Colour Bars With Fade to Grey", 258be1589e5SKate Hsuan "Pseudorandom Sequence (PN9)", 259be1589e5SKate Hsuan }; 260be1589e5SKate Hsuan 261be1589e5SKate Hsuan static const s64 link_freq_menu_items[] = { 262be1589e5SKate Hsuan IMX471_LINK_FREQ_DEFAULT, 263be1589e5SKate Hsuan }; 264be1589e5SKate Hsuan 265be1589e5SKate Hsuan /* 266be1589e5SKate Hsuan * The Bayer formats for the flipping. 267be1589e5SKate Hsuan * - no flip 268be1589e5SKate Hsuan * - h flip 269be1589e5SKate Hsuan * - v flip 270be1589e5SKate Hsuan * - h and v flips 271be1589e5SKate Hsuan */ 272be1589e5SKate Hsuan static const u32 imx471_hv_flips_bayer_order[] = { 273be1589e5SKate Hsuan MEDIA_BUS_FMT_SRGGB10_1X10, 274be1589e5SKate Hsuan MEDIA_BUS_FMT_SGRBG10_1X10, 275be1589e5SKate Hsuan MEDIA_BUS_FMT_SGBRG10_1X10, 276be1589e5SKate Hsuan MEDIA_BUS_FMT_SBGGR10_1X10, 277be1589e5SKate Hsuan }; 278be1589e5SKate Hsuan 279be1589e5SKate Hsuan static const struct imx471_mode imx471_modes[] = { 280be1589e5SKate Hsuan { 281be1589e5SKate Hsuan .width = 1928, 282be1589e5SKate Hsuan .height = 1088, 283be1589e5SKate Hsuan .fll_def = 1308, 284be1589e5SKate Hsuan .fll_min = 1308, 285be1589e5SKate Hsuan .llp = 2328, 286be1589e5SKate Hsuan .default_mode_regs = mode_1928x1088_regs, 287be1589e5SKate Hsuan .default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs), 288be1589e5SKate Hsuan }, 289be1589e5SKate Hsuan }; 290be1589e5SKate Hsuan 291be1589e5SKate Hsuan static int imx471_get_regulators(struct device *dev, struct imx471 *sensor) 292be1589e5SKate Hsuan { 293be1589e5SKate Hsuan for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++) 294be1589e5SKate Hsuan sensor->supplies[i].supply = imx471_supply_name[i]; 295be1589e5SKate Hsuan 296be1589e5SKate Hsuan return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name), 297be1589e5SKate Hsuan sensor->supplies); 298be1589e5SKate Hsuan } 299be1589e5SKate Hsuan 300be1589e5SKate Hsuan static int imx471_set_ctrl(struct v4l2_ctrl *ctrl) 301be1589e5SKate Hsuan { 302be1589e5SKate Hsuan struct imx471 *sensor = container_of_const(ctrl->handler, 303be1589e5SKate Hsuan struct imx471, 304be1589e5SKate Hsuan ctrl_handler); 305be1589e5SKate Hsuan struct v4l2_subdev_state *state = 306be1589e5SKate Hsuan v4l2_subdev_get_locked_active_state(&sensor->sd); 307be1589e5SKate Hsuan const struct v4l2_mbus_framefmt *format = 308be1589e5SKate Hsuan v4l2_subdev_state_get_format(state, 0); 309be1589e5SKate Hsuan int ret; 310be1589e5SKate Hsuan 311be1589e5SKate Hsuan if (ctrl->id == V4L2_CID_VBLANK) { 312be1589e5SKate Hsuan s64 exposure_max = format->height + ctrl->val - 313be1589e5SKate Hsuan IMX471_EXPOSURE_MARGIN; 314be1589e5SKate Hsuan ret = __v4l2_ctrl_modify_range(sensor->exposure, 315be1589e5SKate Hsuan sensor->exposure->minimum, 316be1589e5SKate Hsuan exposure_max, 317be1589e5SKate Hsuan sensor->exposure->step, 318be1589e5SKate Hsuan exposure_max); 319be1589e5SKate Hsuan if (ret) 320be1589e5SKate Hsuan return ret; 321be1589e5SKate Hsuan } 322be1589e5SKate Hsuan 323be1589e5SKate Hsuan if (!pm_runtime_get_if_in_use(sensor->dev)) 324be1589e5SKate Hsuan return 0; 325be1589e5SKate Hsuan 326be1589e5SKate Hsuan switch (ctrl->id) { 327be1589e5SKate Hsuan case V4L2_CID_ANALOGUE_GAIN: 328be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN, 329be1589e5SKate Hsuan ctrl->val, NULL); 330be1589e5SKate Hsuan break; 331be1589e5SKate Hsuan case V4L2_CID_DIGITAL_GAIN: 332be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL, 333be1589e5SKate Hsuan ctrl->val, NULL); 334be1589e5SKate Hsuan break; 335be1589e5SKate Hsuan case V4L2_CID_EXPOSURE: 336be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE, 337*b272a178SDavid Carlier ctrl->val, NULL); 338be1589e5SKate Hsuan break; 339be1589e5SKate Hsuan case V4L2_CID_VBLANK: 340be1589e5SKate Hsuan /* Update FLL that meets expected vertical blanking */ 341be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_FLL, 342*b272a178SDavid Carlier format->height + ctrl->val, NULL); 343be1589e5SKate Hsuan break; 344be1589e5SKate Hsuan case V4L2_CID_TEST_PATTERN: 345be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN, 346be1589e5SKate Hsuan ctrl->val, NULL); 347be1589e5SKate Hsuan break; 348be1589e5SKate Hsuan case V4L2_CID_HFLIP: 349be1589e5SKate Hsuan case V4L2_CID_VFLIP: 350be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION, 351be1589e5SKate Hsuan sensor->hflip->val | sensor->vflip->val << 1, 352be1589e5SKate Hsuan NULL); 353be1589e5SKate Hsuan break; 354be1589e5SKate Hsuan default: 355be1589e5SKate Hsuan ret = -EINVAL; 356be1589e5SKate Hsuan dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", 357be1589e5SKate Hsuan ctrl->id, ctrl->val); 358be1589e5SKate Hsuan break; 359be1589e5SKate Hsuan } 360be1589e5SKate Hsuan 361be1589e5SKate Hsuan pm_runtime_put(sensor->dev); 362be1589e5SKate Hsuan 363be1589e5SKate Hsuan return ret; 364be1589e5SKate Hsuan } 365be1589e5SKate Hsuan 366be1589e5SKate Hsuan static const struct v4l2_ctrl_ops imx471_ctrl_ops = { 367be1589e5SKate Hsuan .s_ctrl = imx471_set_ctrl, 368be1589e5SKate Hsuan }; 369be1589e5SKate Hsuan 370be1589e5SKate Hsuan static u32 imx471_get_format_code(struct imx471 *sensor) 371be1589e5SKate Hsuan { 372be1589e5SKate Hsuan unsigned int i; 373be1589e5SKate Hsuan 374be1589e5SKate Hsuan i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0); 375be1589e5SKate Hsuan 376be1589e5SKate Hsuan return imx471_hv_flips_bayer_order[i]; 377be1589e5SKate Hsuan } 378be1589e5SKate Hsuan 379be1589e5SKate Hsuan static int imx471_enum_mbus_code(struct v4l2_subdev *sd, 380be1589e5SKate Hsuan struct v4l2_subdev_state *sd_state, 381be1589e5SKate Hsuan struct v4l2_subdev_mbus_code_enum *code) 382be1589e5SKate Hsuan { 383be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 384be1589e5SKate Hsuan 385be1589e5SKate Hsuan if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4)) 386be1589e5SKate Hsuan return -EINVAL; 387be1589e5SKate Hsuan 388be1589e5SKate Hsuan code->code = imx471_get_format_code(sensor); 389be1589e5SKate Hsuan 390be1589e5SKate Hsuan return 0; 391be1589e5SKate Hsuan } 392be1589e5SKate Hsuan 393be1589e5SKate Hsuan static int imx471_enum_frame_size(struct v4l2_subdev *sd, 394be1589e5SKate Hsuan struct v4l2_subdev_state *sd_state, 395be1589e5SKate Hsuan struct v4l2_subdev_frame_size_enum *fse) 396be1589e5SKate Hsuan { 397be1589e5SKate Hsuan if (fse->index >= ARRAY_SIZE(imx471_modes)) 398be1589e5SKate Hsuan return -EINVAL; 399be1589e5SKate Hsuan 400be1589e5SKate Hsuan fse->min_width = imx471_modes[fse->index].width; 401be1589e5SKate Hsuan fse->max_width = fse->min_width; 402be1589e5SKate Hsuan fse->min_height = imx471_modes[fse->index].height; 403be1589e5SKate Hsuan fse->max_height = fse->min_height; 404be1589e5SKate Hsuan 405be1589e5SKate Hsuan return 0; 406be1589e5SKate Hsuan } 407be1589e5SKate Hsuan 408be1589e5SKate Hsuan static void imx471_update_pad_format(struct imx471 *sensor, 409be1589e5SKate Hsuan const struct imx471_mode *mode, 410be1589e5SKate Hsuan struct v4l2_subdev_format *fmt) 411be1589e5SKate Hsuan { 412be1589e5SKate Hsuan fmt->format.code = imx471_get_format_code(sensor); 413be1589e5SKate Hsuan fmt->format.width = mode->width; 414be1589e5SKate Hsuan fmt->format.height = mode->height; 415be1589e5SKate Hsuan fmt->format.field = V4L2_FIELD_NONE; 416be1589e5SKate Hsuan } 417be1589e5SKate Hsuan 418be1589e5SKate Hsuan static int imx471_set_pad_format(struct v4l2_subdev *sd, 419be1589e5SKate Hsuan struct v4l2_subdev_state *sd_state, 420be1589e5SKate Hsuan struct v4l2_subdev_format *fmt) 421be1589e5SKate Hsuan { 422be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 423be1589e5SKate Hsuan const struct imx471_mode *mode; 424be1589e5SKate Hsuan int h_blank, ret; 425be1589e5SKate Hsuan 426be1589e5SKate Hsuan mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), 427be1589e5SKate Hsuan width, height, fmt->format.width, 428be1589e5SKate Hsuan fmt->format.height); 429be1589e5SKate Hsuan 430be1589e5SKate Hsuan imx471_update_pad_format(sensor, mode, fmt); 431be1589e5SKate Hsuan 432be1589e5SKate Hsuan *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; 433be1589e5SKate Hsuan 434be1589e5SKate Hsuan if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 435be1589e5SKate Hsuan return 0; 436be1589e5SKate Hsuan 437be1589e5SKate Hsuan if (media_entity_is_streaming(&sensor->sd.entity)) 438be1589e5SKate Hsuan return -EBUSY; 439be1589e5SKate Hsuan 440be1589e5SKate Hsuan ret = __v4l2_ctrl_modify_range(sensor->vblank, 441be1589e5SKate Hsuan mode->fll_min - mode->height, 442be1589e5SKate Hsuan IMX471_FLL_MAX - mode->height, 443be1589e5SKate Hsuan 1, 444be1589e5SKate Hsuan mode->fll_def - mode->height); 445be1589e5SKate Hsuan if (ret) 446be1589e5SKate Hsuan return ret; 447be1589e5SKate Hsuan 448be1589e5SKate Hsuan h_blank = mode->llp - mode->width; 449be1589e5SKate Hsuan /* 450be1589e5SKate Hsuan * Currently hblank is not changeable. 451be1589e5SKate Hsuan * So FPS control is done only by vblank. 452be1589e5SKate Hsuan */ 453be1589e5SKate Hsuan return __v4l2_ctrl_modify_range(sensor->hblank, h_blank, 454be1589e5SKate Hsuan h_blank, 1, h_blank); 455be1589e5SKate Hsuan } 456be1589e5SKate Hsuan 457be1589e5SKate Hsuan static int imx471_get_selection(struct v4l2_subdev *sd, 458be1589e5SKate Hsuan struct v4l2_subdev_state *sd_state, 459be1589e5SKate Hsuan struct v4l2_subdev_selection *sel) 460be1589e5SKate Hsuan { 461be1589e5SKate Hsuan switch (sel->target) { 462be1589e5SKate Hsuan case V4L2_SEL_TGT_CROP: 463be1589e5SKate Hsuan sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); 464be1589e5SKate Hsuan break; 465be1589e5SKate Hsuan 466be1589e5SKate Hsuan case V4L2_SEL_TGT_NATIVE_SIZE: 467be1589e5SKate Hsuan sel->r.top = 0; 468be1589e5SKate Hsuan sel->r.left = 0; 469be1589e5SKate Hsuan sel->r.width = IMX471_NATIVE_WIDTH; 470be1589e5SKate Hsuan sel->r.height = IMX471_NATIVE_HEIGHT; 471be1589e5SKate Hsuan return 0; 472be1589e5SKate Hsuan 473be1589e5SKate Hsuan case V4L2_SEL_TGT_CROP_DEFAULT: 474be1589e5SKate Hsuan case V4L2_SEL_TGT_CROP_BOUNDS: 475be1589e5SKate Hsuan sel->r.top = IMX471_PIXEL_ARRAY_TOP; 476be1589e5SKate Hsuan sel->r.left = IMX471_PIXEL_ARRAY_LEFT; 477be1589e5SKate Hsuan sel->r.width = IMX471_PIXEL_ARRAY_WIDTH; 478be1589e5SKate Hsuan sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT; 479be1589e5SKate Hsuan return 0; 480be1589e5SKate Hsuan } 481be1589e5SKate Hsuan 482be1589e5SKate Hsuan return -EINVAL; 483be1589e5SKate Hsuan } 484be1589e5SKate Hsuan 485be1589e5SKate Hsuan static int imx471_init_state(struct v4l2_subdev *sd, 486be1589e5SKate Hsuan struct v4l2_subdev_state *sd_state) 487be1589e5SKate Hsuan { 488be1589e5SKate Hsuan struct v4l2_subdev_format fmt = { 489be1589e5SKate Hsuan .which = V4L2_SUBDEV_FORMAT_TRY, 490be1589e5SKate Hsuan .format = { 491be1589e5SKate Hsuan .code = MEDIA_BUS_FMT_SRGGB10_1X10, 492be1589e5SKate Hsuan .width = imx471_modes[0].width, 493be1589e5SKate Hsuan .height = imx471_modes[0].height, 494be1589e5SKate Hsuan }, 495be1589e5SKate Hsuan }; 496be1589e5SKate Hsuan 497be1589e5SKate Hsuan return imx471_set_pad_format(sd, sd_state, &fmt); 498be1589e5SKate Hsuan } 499be1589e5SKate Hsuan 500be1589e5SKate Hsuan static int imx471_identify_module(struct imx471 *sensor) 501be1589e5SKate Hsuan { 502be1589e5SKate Hsuan int ret; 503be1589e5SKate Hsuan u64 val; 504be1589e5SKate Hsuan 505be1589e5SKate Hsuan ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL); 506be1589e5SKate Hsuan if (ret) 507be1589e5SKate Hsuan return dev_err_probe(sensor->dev, ret, 508be1589e5SKate Hsuan "failed to read chip id\n"); 509be1589e5SKate Hsuan 510be1589e5SKate Hsuan if (val != IMX471_CHIP_ID) 511be1589e5SKate Hsuan return dev_err_probe(sensor->dev, -EIO, 512be1589e5SKate Hsuan "chip id mismatch: %x!=%llx\n", 513be1589e5SKate Hsuan IMX471_CHIP_ID, val); 514be1589e5SKate Hsuan 515be1589e5SKate Hsuan return 0; 516be1589e5SKate Hsuan } 517be1589e5SKate Hsuan 518be1589e5SKate Hsuan static int imx471_power_off(struct device *dev) 519be1589e5SKate Hsuan { 520be1589e5SKate Hsuan struct v4l2_subdev *sd = dev_get_drvdata(dev); 521be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 522be1589e5SKate Hsuan 523be1589e5SKate Hsuan clk_disable_unprepare(sensor->img_clk); 524be1589e5SKate Hsuan gpiod_set_value_cansleep(sensor->reset_gpio, 1); 525be1589e5SKate Hsuan 526be1589e5SKate Hsuan regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), 527be1589e5SKate Hsuan sensor->supplies); 528be1589e5SKate Hsuan 529be1589e5SKate Hsuan return 0; 530be1589e5SKate Hsuan } 531be1589e5SKate Hsuan 532be1589e5SKate Hsuan static int imx471_power_on(struct device *dev) 533be1589e5SKate Hsuan { 534be1589e5SKate Hsuan struct v4l2_subdev *sd = dev_get_drvdata(dev); 535be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 536be1589e5SKate Hsuan int ret; 537be1589e5SKate Hsuan 538be1589e5SKate Hsuan ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name), 539be1589e5SKate Hsuan sensor->supplies); 540be1589e5SKate Hsuan if (ret < 0) { 541be1589e5SKate Hsuan dev_err(dev, "failed to enable regulators: %d\n", ret); 542be1589e5SKate Hsuan return ret; 543be1589e5SKate Hsuan } 544be1589e5SKate Hsuan 545be1589e5SKate Hsuan ret = clk_prepare_enable(sensor->img_clk); 546be1589e5SKate Hsuan if (ret < 0) { 547be1589e5SKate Hsuan regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), 548be1589e5SKate Hsuan sensor->supplies); 549be1589e5SKate Hsuan dev_err(dev, "failed to enable imaging clock: %d\n", ret); 550be1589e5SKate Hsuan return ret; 551be1589e5SKate Hsuan } 552be1589e5SKate Hsuan 553be1589e5SKate Hsuan gpiod_set_value_cansleep(sensor->reset_gpio, 0); 554be1589e5SKate Hsuan 555be1589e5SKate Hsuan usleep_range(10000, 15000); 556be1589e5SKate Hsuan 557be1589e5SKate Hsuan return 0; 558be1589e5SKate Hsuan } 559be1589e5SKate Hsuan 560be1589e5SKate Hsuan static int imx471_enable_stream(struct v4l2_subdev *sd, 561be1589e5SKate Hsuan struct v4l2_subdev_state *state, 562be1589e5SKate Hsuan u32 pad, u64 streams_mask) 563be1589e5SKate Hsuan { 564be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 565be1589e5SKate Hsuan const struct imx471_mode *mode; 566be1589e5SKate Hsuan struct v4l2_mbus_framefmt *fmt; 567be1589e5SKate Hsuan int ret; 568be1589e5SKate Hsuan 569be1589e5SKate Hsuan ret = pm_runtime_resume_and_get(sensor->dev); 570be1589e5SKate Hsuan if (ret) 571be1589e5SKate Hsuan return ret; 572be1589e5SKate Hsuan 573be1589e5SKate Hsuan ret = imx471_identify_module(sensor); 574be1589e5SKate Hsuan if (ret) 575be1589e5SKate Hsuan goto error_powerdown; 576be1589e5SKate Hsuan 577be1589e5SKate Hsuan ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs, 578be1589e5SKate Hsuan ARRAY_SIZE(imx471_global_regs), NULL); 579be1589e5SKate Hsuan if (ret) { 580be1589e5SKate Hsuan dev_err(sensor->dev, "failed to set global settings: %d\n", 581be1589e5SKate Hsuan ret); 582be1589e5SKate Hsuan goto error_powerdown; 583be1589e5SKate Hsuan } 584be1589e5SKate Hsuan 585be1589e5SKate Hsuan fmt = v4l2_subdev_state_get_format(state, 0); 586be1589e5SKate Hsuan mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), 587be1589e5SKate Hsuan width, height, fmt->width, fmt->height); 588be1589e5SKate Hsuan 589be1589e5SKate Hsuan ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs, 590be1589e5SKate Hsuan mode->default_mode_regs_length, NULL); 591be1589e5SKate Hsuan if (ret) { 592be1589e5SKate Hsuan dev_err(sensor->dev, "failed to set mode: %d\n", ret); 593be1589e5SKate Hsuan goto error_powerdown; 594be1589e5SKate Hsuan } 595be1589e5SKate Hsuan 596be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1, 597be1589e5SKate Hsuan NULL); 598be1589e5SKate Hsuan if (ret) 599be1589e5SKate Hsuan goto error_powerdown; 600be1589e5SKate Hsuan 601be1589e5SKate Hsuan ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); 602be1589e5SKate Hsuan if (ret) 603be1589e5SKate Hsuan goto error_powerdown; 604be1589e5SKate Hsuan 605be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, 606be1589e5SKate Hsuan IMX471_MODE_STREAMING, NULL); 607be1589e5SKate Hsuan if (ret) 608be1589e5SKate Hsuan goto error_powerdown; 609be1589e5SKate Hsuan 610be1589e5SKate Hsuan __v4l2_ctrl_grab(sensor->vflip, true); 611be1589e5SKate Hsuan __v4l2_ctrl_grab(sensor->hflip, true); 612be1589e5SKate Hsuan 613be1589e5SKate Hsuan return ret; 614be1589e5SKate Hsuan 615be1589e5SKate Hsuan error_powerdown: 616be1589e5SKate Hsuan pm_runtime_put(sensor->dev); 617be1589e5SKate Hsuan 618be1589e5SKate Hsuan return ret; 619be1589e5SKate Hsuan } 620be1589e5SKate Hsuan 621be1589e5SKate Hsuan static int imx471_disable_stream(struct v4l2_subdev *sd, 622be1589e5SKate Hsuan struct v4l2_subdev_state *state, 623be1589e5SKate Hsuan u32 pad, u64 streams_mask) 624be1589e5SKate Hsuan { 625be1589e5SKate Hsuan struct imx471 *sensor = to_imx471(sd); 626be1589e5SKate Hsuan int ret; 627be1589e5SKate Hsuan 628be1589e5SKate Hsuan ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, 629be1589e5SKate Hsuan IMX471_MODE_STANDBY, NULL); 630be1589e5SKate Hsuan pm_runtime_put(sensor->dev); 631be1589e5SKate Hsuan 632be1589e5SKate Hsuan if (ret) 633be1589e5SKate Hsuan dev_err(sensor->dev, 634be1589e5SKate Hsuan "failed to disable stream with return value: %d\n", 635be1589e5SKate Hsuan ret); 636be1589e5SKate Hsuan 637be1589e5SKate Hsuan __v4l2_ctrl_grab(sensor->vflip, false); 638be1589e5SKate Hsuan __v4l2_ctrl_grab(sensor->hflip, false); 639be1589e5SKate Hsuan 640be1589e5SKate Hsuan return 0; 641be1589e5SKate Hsuan } 642be1589e5SKate Hsuan 643be1589e5SKate Hsuan static const struct v4l2_subdev_video_ops imx471_video_ops = { 644be1589e5SKate Hsuan .s_stream = v4l2_subdev_s_stream_helper, 645be1589e5SKate Hsuan }; 646be1589e5SKate Hsuan 647be1589e5SKate Hsuan static const struct v4l2_subdev_pad_ops imx471_pad_ops = { 648be1589e5SKate Hsuan .enum_mbus_code = imx471_enum_mbus_code, 649be1589e5SKate Hsuan .get_fmt = v4l2_subdev_get_fmt, 650be1589e5SKate Hsuan .set_fmt = imx471_set_pad_format, 651be1589e5SKate Hsuan .get_selection = imx471_get_selection, 652be1589e5SKate Hsuan .enum_frame_size = imx471_enum_frame_size, 653be1589e5SKate Hsuan .enable_streams = imx471_enable_stream, 654be1589e5SKate Hsuan .disable_streams = imx471_disable_stream, 655be1589e5SKate Hsuan }; 656be1589e5SKate Hsuan 657be1589e5SKate Hsuan static const struct v4l2_subdev_ops imx471_subdev_ops = { 658be1589e5SKate Hsuan .video = &imx471_video_ops, 659be1589e5SKate Hsuan .pad = &imx471_pad_ops, 660be1589e5SKate Hsuan }; 661be1589e5SKate Hsuan 662be1589e5SKate Hsuan static const struct v4l2_subdev_internal_ops imx471_internal_ops = { 663be1589e5SKate Hsuan .init_state = imx471_init_state, 664be1589e5SKate Hsuan }; 665be1589e5SKate Hsuan 666be1589e5SKate Hsuan static int imx471_init_controls(struct imx471 *sensor) 667be1589e5SKate Hsuan { 668be1589e5SKate Hsuan const struct imx471_mode *mode = &imx471_modes[0]; 669be1589e5SKate Hsuan struct v4l2_fwnode_device_properties props; 670be1589e5SKate Hsuan struct v4l2_ctrl_handler *ctrl_hdlr; 671be1589e5SKate Hsuan struct v4l2_ctrl *link_freq; 672be1589e5SKate Hsuan s64 exposure_max, hblank; 673be1589e5SKate Hsuan u64 pixel_rate; 674be1589e5SKate Hsuan int ret; 675be1589e5SKate Hsuan 676be1589e5SKate Hsuan ret = v4l2_fwnode_device_parse(sensor->dev, &props); 677be1589e5SKate Hsuan if (ret) { 678be1589e5SKate Hsuan dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret); 679be1589e5SKate Hsuan return ret; 680be1589e5SKate Hsuan } 681be1589e5SKate Hsuan 682be1589e5SKate Hsuan ctrl_hdlr = &sensor->ctrl_handler; 683be1589e5SKate Hsuan v4l2_ctrl_handler_init(ctrl_hdlr, 12); 684be1589e5SKate Hsuan 685be1589e5SKate Hsuan v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props); 686be1589e5SKate Hsuan 687be1589e5SKate Hsuan link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, 688be1589e5SKate Hsuan &imx471_ctrl_ops, 689be1589e5SKate Hsuan V4L2_CID_LINK_FREQ, 690be1589e5SKate Hsuan ARRAY_SIZE(link_freq_menu_items) - 1, 691be1589e5SKate Hsuan 0, 692be1589e5SKate Hsuan link_freq_menu_items); 693be1589e5SKate Hsuan 694be1589e5SKate Hsuan /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ 695be1589e5SKate Hsuan pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10); 696be1589e5SKate Hsuan 697be1589e5SKate Hsuan v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, 698be1589e5SKate Hsuan V4L2_CID_PIXEL_RATE, pixel_rate, 699be1589e5SKate Hsuan pixel_rate, 1, pixel_rate); 700be1589e5SKate Hsuan 701be1589e5SKate Hsuan sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr, 702be1589e5SKate Hsuan &imx471_ctrl_ops, 703be1589e5SKate Hsuan V4L2_CID_VBLANK, 704be1589e5SKate Hsuan mode->fll_min - mode->height, 705be1589e5SKate Hsuan IMX471_FLL_MAX - mode->height, 706be1589e5SKate Hsuan 1, 707be1589e5SKate Hsuan mode->fll_def - mode->height); 708be1589e5SKate Hsuan 709be1589e5SKate Hsuan hblank = mode->llp - mode->width; 710be1589e5SKate Hsuan sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, 711be1589e5SKate Hsuan V4L2_CID_HBLANK, hblank, hblank, 712be1589e5SKate Hsuan 1, hblank); 713be1589e5SKate Hsuan 714be1589e5SKate Hsuan /* fll >= exposure time + adjust parameter (default value is 18) */ 715be1589e5SKate Hsuan exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN; 716be1589e5SKate Hsuan sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, 717be1589e5SKate Hsuan V4L2_CID_EXPOSURE, 718be1589e5SKate Hsuan IMX471_EXPOSURE_MIN, exposure_max, 719be1589e5SKate Hsuan IMX471_EXPOSURE_STEP, 720be1589e5SKate Hsuan IMX471_EXPOSURE_DEFAULT); 721be1589e5SKate Hsuan 722be1589e5SKate Hsuan v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 723be1589e5SKate Hsuan IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX, 724be1589e5SKate Hsuan IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT); 725be1589e5SKate Hsuan 726be1589e5SKate Hsuan v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN, 727be1589e5SKate Hsuan IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX, 728be1589e5SKate Hsuan IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT); 729be1589e5SKate Hsuan 730be1589e5SKate Hsuan v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops, 731be1589e5SKate Hsuan V4L2_CID_TEST_PATTERN, 732be1589e5SKate Hsuan ARRAY_SIZE(imx471_test_pattern_menu) - 1, 733be1589e5SKate Hsuan 0, 0, imx471_test_pattern_menu); 734be1589e5SKate Hsuan 735be1589e5SKate Hsuan sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, 736be1589e5SKate Hsuan V4L2_CID_HFLIP, 0, 1, 1, 0); 737be1589e5SKate Hsuan 738be1589e5SKate Hsuan sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, 739be1589e5SKate Hsuan V4L2_CID_VFLIP, 0, 1, 1, 0); 740be1589e5SKate Hsuan 741be1589e5SKate Hsuan if (ctrl_hdlr->error) { 742be1589e5SKate Hsuan dev_err(sensor->dev, "%s control init failed: %d\n", 743be1589e5SKate Hsuan __func__, ctrl_hdlr->error); 744be1589e5SKate Hsuan goto error; 745be1589e5SKate Hsuan } 746be1589e5SKate Hsuan 747be1589e5SKate Hsuan link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 748be1589e5SKate Hsuan sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 749be1589e5SKate Hsuan sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 750be1589e5SKate Hsuan sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 751be1589e5SKate Hsuan 752be1589e5SKate Hsuan sensor->sd.ctrl_handler = ctrl_hdlr; 753be1589e5SKate Hsuan 754be1589e5SKate Hsuan return 0; 755be1589e5SKate Hsuan 756be1589e5SKate Hsuan error: 757be1589e5SKate Hsuan v4l2_ctrl_handler_free(ctrl_hdlr); 758be1589e5SKate Hsuan 759be1589e5SKate Hsuan return ctrl_hdlr->error; 760be1589e5SKate Hsuan } 761be1589e5SKate Hsuan 762be1589e5SKate Hsuan static int imx471_check_hwcfg(struct imx471 *sensor) 763be1589e5SKate Hsuan { 764be1589e5SKate Hsuan struct v4l2_fwnode_endpoint bus_cfg = { 765be1589e5SKate Hsuan .bus_type = V4L2_MBUS_CSI2_DPHY, 766be1589e5SKate Hsuan }; 767be1589e5SKate Hsuan struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev); 768be1589e5SKate Hsuan unsigned long link_freq_bitmap; 769be1589e5SKate Hsuan struct clk *clk; 770be1589e5SKate Hsuan int ret; 771be1589e5SKate Hsuan 772be1589e5SKate Hsuan clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); 773be1589e5SKate Hsuan if (IS_ERR(clk)) 774be1589e5SKate Hsuan return dev_err_probe(sensor->dev, PTR_ERR(clk), 775be1589e5SKate Hsuan "can't get clock frequency\n"); 776be1589e5SKate Hsuan 777be1589e5SKate Hsuan if (clk_get_rate(clk) != IMX471_EXT_CLK) 778be1589e5SKate Hsuan return dev_err_probe(sensor->dev, -EINVAL, 779be1589e5SKate Hsuan "external clock %lu is not supported\n", 780be1589e5SKate Hsuan clk_get_rate(clk)); 781be1589e5SKate Hsuan 782be1589e5SKate Hsuan ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0); 783be1589e5SKate Hsuan ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 784be1589e5SKate Hsuan fwnode_handle_put(ep); 785be1589e5SKate Hsuan if (ret) 786be1589e5SKate Hsuan return dev_err_probe(sensor->dev, ret, 787be1589e5SKate Hsuan "parsing endpoint failed\n"); 788be1589e5SKate Hsuan 789be1589e5SKate Hsuan if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { 790be1589e5SKate Hsuan ret = dev_err_probe(sensor->dev, -EINVAL, 791be1589e5SKate Hsuan "number of CSI2 data lanes %u is not supported\n", 792be1589e5SKate Hsuan bus_cfg.bus.mipi_csi2.num_data_lanes); 793be1589e5SKate Hsuan goto done_endpoint_free; 794be1589e5SKate Hsuan } 795be1589e5SKate Hsuan 796be1589e5SKate Hsuan ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies, 797be1589e5SKate Hsuan bus_cfg.nr_of_link_frequencies, 798be1589e5SKate Hsuan link_freq_menu_items, 799be1589e5SKate Hsuan ARRAY_SIZE(link_freq_menu_items), 800be1589e5SKate Hsuan &link_freq_bitmap); 801be1589e5SKate Hsuan 802be1589e5SKate Hsuan done_endpoint_free: 803be1589e5SKate Hsuan v4l2_fwnode_endpoint_free(&bus_cfg); 804be1589e5SKate Hsuan 805be1589e5SKate Hsuan return ret; 806be1589e5SKate Hsuan } 807be1589e5SKate Hsuan 808be1589e5SKate Hsuan static int imx471_probe(struct i2c_client *client) 809be1589e5SKate Hsuan { 810be1589e5SKate Hsuan struct imx471 *sensor; 811be1589e5SKate Hsuan int ret; 812be1589e5SKate Hsuan 813be1589e5SKate Hsuan sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); 814be1589e5SKate Hsuan if (!sensor) 815be1589e5SKate Hsuan return dev_err_probe(&client->dev, -ENOMEM, 816be1589e5SKate Hsuan "failed to allocate memory\n"); 817be1589e5SKate Hsuan 818be1589e5SKate Hsuan sensor->dev = &client->dev; 819be1589e5SKate Hsuan 820be1589e5SKate Hsuan ret = imx471_check_hwcfg(sensor); 821be1589e5SKate Hsuan if (ret) 822be1589e5SKate Hsuan return dev_err_probe(sensor->dev, ret, 823be1589e5SKate Hsuan "failed to check hwcfg: %d\n", ret); 824be1589e5SKate Hsuan 825be1589e5SKate Hsuan ret = imx471_get_regulators(sensor->dev, sensor); 826be1589e5SKate Hsuan if (ret) 827be1589e5SKate Hsuan return dev_err_probe(sensor->dev, ret, 828be1589e5SKate Hsuan "failed to get regulators\n"); 829be1589e5SKate Hsuan 830be1589e5SKate Hsuan sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset", 831be1589e5SKate Hsuan GPIOD_OUT_HIGH); 832be1589e5SKate Hsuan if (IS_ERR(sensor->reset_gpio)) 833be1589e5SKate Hsuan return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio), 834be1589e5SKate Hsuan "failed to get reset gpio\n"); 835be1589e5SKate Hsuan 836be1589e5SKate Hsuan sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); 837be1589e5SKate Hsuan if (IS_ERR(sensor->img_clk)) 838be1589e5SKate Hsuan return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk), 839be1589e5SKate Hsuan "failed to get imaging clock\n"); 840be1589e5SKate Hsuan 841be1589e5SKate Hsuan v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops); 842be1589e5SKate Hsuan 843be1589e5SKate Hsuan sensor->regmap = devm_cci_regmap_init_i2c(client, 16); 844be1589e5SKate Hsuan if (IS_ERR(sensor->regmap)) 845be1589e5SKate Hsuan return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap), 846be1589e5SKate Hsuan "failed to initialize CCI\n"); 847be1589e5SKate Hsuan 848be1589e5SKate Hsuan ret = imx471_power_on(sensor->dev); 849be1589e5SKate Hsuan if (ret) 850be1589e5SKate Hsuan return dev_err_probe(sensor->dev, ret, 851be1589e5SKate Hsuan "failed to power on\n"); 852be1589e5SKate Hsuan 853be1589e5SKate Hsuan ret = imx471_identify_module(sensor); 854be1589e5SKate Hsuan if (ret) { 855be1589e5SKate Hsuan dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n", 856be1589e5SKate Hsuan ret); 857be1589e5SKate Hsuan goto error_power_off; 858be1589e5SKate Hsuan } 859be1589e5SKate Hsuan 860be1589e5SKate Hsuan ret = imx471_init_controls(sensor); 861be1589e5SKate Hsuan if (ret) { 862be1589e5SKate Hsuan dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n", 863be1589e5SKate Hsuan ret); 864be1589e5SKate Hsuan goto error_power_off; 865be1589e5SKate Hsuan } 866be1589e5SKate Hsuan 867be1589e5SKate Hsuan sensor->sd.internal_ops = &imx471_internal_ops; 868be1589e5SKate Hsuan sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 869be1589e5SKate Hsuan sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 870be1589e5SKate Hsuan sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 871be1589e5SKate Hsuan 872be1589e5SKate Hsuan ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 873be1589e5SKate Hsuan if (ret) { 874be1589e5SKate Hsuan dev_err_probe(sensor->dev, ret, 875be1589e5SKate Hsuan "failed to init entity pads: %d\n", ret); 876be1589e5SKate Hsuan goto error_v4l2_ctrl_handler_free; 877be1589e5SKate Hsuan } 878be1589e5SKate Hsuan 879be1589e5SKate Hsuan sensor->sd.state_lock = sensor->ctrl_handler.lock; 880be1589e5SKate Hsuan ret = v4l2_subdev_init_finalize(&sensor->sd); 881be1589e5SKate Hsuan if (ret < 0) { 882be1589e5SKate Hsuan dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n", 883be1589e5SKate Hsuan ret); 884be1589e5SKate Hsuan goto error_media_entity_pm; 885be1589e5SKate Hsuan } 886be1589e5SKate Hsuan 887be1589e5SKate Hsuan pm_runtime_set_active(sensor->dev); 888be1589e5SKate Hsuan pm_runtime_enable(sensor->dev); 889be1589e5SKate Hsuan 890be1589e5SKate Hsuan ret = v4l2_async_register_subdev_sensor(&sensor->sd); 891be1589e5SKate Hsuan if (ret < 0) 892be1589e5SKate Hsuan goto error_v4l2_subdev_cleanup; 893be1589e5SKate Hsuan 894be1589e5SKate Hsuan pm_runtime_idle(sensor->dev); 895be1589e5SKate Hsuan 896be1589e5SKate Hsuan return 0; 897be1589e5SKate Hsuan 898be1589e5SKate Hsuan error_v4l2_subdev_cleanup: 899be1589e5SKate Hsuan pm_runtime_disable(sensor->dev); 900be1589e5SKate Hsuan pm_runtime_set_suspended(sensor->dev); 901be1589e5SKate Hsuan v4l2_subdev_cleanup(&sensor->sd); 902be1589e5SKate Hsuan 903be1589e5SKate Hsuan error_media_entity_pm: 904be1589e5SKate Hsuan media_entity_cleanup(&sensor->sd.entity); 905be1589e5SKate Hsuan 906be1589e5SKate Hsuan error_v4l2_ctrl_handler_free: 907be1589e5SKate Hsuan v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); 908be1589e5SKate Hsuan 909be1589e5SKate Hsuan error_power_off: 910be1589e5SKate Hsuan imx471_power_off(sensor->dev); 911be1589e5SKate Hsuan 912be1589e5SKate Hsuan return ret; 913be1589e5SKate Hsuan } 914be1589e5SKate Hsuan 915be1589e5SKate Hsuan static void imx471_remove(struct i2c_client *client) 916be1589e5SKate Hsuan { 917be1589e5SKate Hsuan struct v4l2_subdev *sd = i2c_get_clientdata(client); 918be1589e5SKate Hsuan 919be1589e5SKate Hsuan v4l2_async_unregister_subdev(sd); 920be1589e5SKate Hsuan v4l2_subdev_cleanup(sd); 921be1589e5SKate Hsuan media_entity_cleanup(&sd->entity); 922be1589e5SKate Hsuan v4l2_ctrl_handler_free(sd->ctrl_handler); 923be1589e5SKate Hsuan 924be1589e5SKate Hsuan pm_runtime_disable(&client->dev); 925be1589e5SKate Hsuan 926be1589e5SKate Hsuan if (!pm_runtime_status_suspended(&client->dev)) { 927be1589e5SKate Hsuan imx471_power_off(&client->dev); 928be1589e5SKate Hsuan pm_runtime_set_suspended(&client->dev); 929be1589e5SKate Hsuan } 930be1589e5SKate Hsuan } 931be1589e5SKate Hsuan 932be1589e5SKate Hsuan static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off, 933be1589e5SKate Hsuan imx471_power_on, NULL); 934be1589e5SKate Hsuan 935be1589e5SKate Hsuan static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = { 936be1589e5SKate Hsuan { "SONY471A" }, 937be1589e5SKate Hsuan { "TBE20A0" }, 938be1589e5SKate Hsuan { /* sentinel */ } 939be1589e5SKate Hsuan }; 940be1589e5SKate Hsuan MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids); 941be1589e5SKate Hsuan 942be1589e5SKate Hsuan static struct i2c_driver imx471_i2c_driver = { 943be1589e5SKate Hsuan .driver = { 944be1589e5SKate Hsuan .name = "imx471", 945be1589e5SKate Hsuan .acpi_match_table = ACPI_PTR(imx471_acpi_ids), 946be1589e5SKate Hsuan .pm = pm_sleep_ptr(&imx471_pm_ops), 947be1589e5SKate Hsuan }, 948be1589e5SKate Hsuan .probe = imx471_probe, 949be1589e5SKate Hsuan .remove = imx471_remove, 950be1589e5SKate Hsuan }; 951be1589e5SKate Hsuan module_i2c_driver(imx471_i2c_driver); 952be1589e5SKate Hsuan 953be1589e5SKate Hsuan MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>"); 954be1589e5SKate Hsuan MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>"); 955be1589e5SKate Hsuan MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>"); 956be1589e5SKate Hsuan MODULE_DESCRIPTION("Sony imx471 sensor driver"); 957be1589e5SKate Hsuan MODULE_LICENSE("GPL"); 958