1*7d402666SVladimir Zapolskiy // SPDX-License-Identifier: GPL-2.0 2*7d402666SVladimir Zapolskiy // Copyright (c) 2025 Linaro Ltd 3*7d402666SVladimir Zapolskiy 4*7d402666SVladimir Zapolskiy #include <linux/clk.h> 5*7d402666SVladimir Zapolskiy #include <linux/delay.h> 6*7d402666SVladimir Zapolskiy #include <linux/gpio/consumer.h> 7*7d402666SVladimir Zapolskiy #include <linux/i2c.h> 8*7d402666SVladimir Zapolskiy #include <linux/module.h> 9*7d402666SVladimir Zapolskiy #include <linux/pm_runtime.h> 10*7d402666SVladimir Zapolskiy #include <linux/regulator/consumer.h> 11*7d402666SVladimir Zapolskiy #include <linux/units.h> 12*7d402666SVladimir Zapolskiy #include <media/v4l2-cci.h> 13*7d402666SVladimir Zapolskiy #include <media/v4l2-ctrls.h> 14*7d402666SVladimir Zapolskiy #include <media/v4l2-device.h> 15*7d402666SVladimir Zapolskiy #include <media/v4l2-fwnode.h> 16*7d402666SVladimir Zapolskiy 17*7d402666SVladimir Zapolskiy #define S5K3M5_LINK_FREQ_602P5MHZ (602500ULL * HZ_PER_KHZ) 18*7d402666SVladimir Zapolskiy #define S5K3M5_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) 19*7d402666SVladimir Zapolskiy #define S5K3M5_DATA_LANES 4 20*7d402666SVladimir Zapolskiy 21*7d402666SVladimir Zapolskiy /* Register map is similar to MIPI CCS compliant camera sensors */ 22*7d402666SVladimir Zapolskiy #define S5K3M5_REG_CHIP_ID CCI_REG16(0x0000) 23*7d402666SVladimir Zapolskiy #define S5K3M5_CHIP_ID 0x30d5 24*7d402666SVladimir Zapolskiy 25*7d402666SVladimir Zapolskiy /* Both streaming and flipping settings are controlled at the same time */ 26*7d402666SVladimir Zapolskiy #define S5K3M5_REG_CTRL_MODE CCI_REG16(0x0100) 27*7d402666SVladimir Zapolskiy #define S5K3M5_MODE_STREAMING BIT(8) 28*7d402666SVladimir Zapolskiy #define S5K3M5_VFLIP BIT(1) 29*7d402666SVladimir Zapolskiy #define S5K3M5_HFLIP BIT(0) 30*7d402666SVladimir Zapolskiy 31*7d402666SVladimir Zapolskiy #define S5K3M5_REG_EXPOSURE CCI_REG16(0x0202) 32*7d402666SVladimir Zapolskiy #define S5K3M5_EXPOSURE_MIN 8 33*7d402666SVladimir Zapolskiy #define S5K3M5_EXPOSURE_STEP 1 34*7d402666SVladimir Zapolskiy #define S5K3M5_EXPOSURE_MARGIN 4 35*7d402666SVladimir Zapolskiy 36*7d402666SVladimir Zapolskiy #define S5K3M5_REG_AGAIN CCI_REG16(0x0204) 37*7d402666SVladimir Zapolskiy #define S5K3M5_AGAIN_MIN 1 38*7d402666SVladimir Zapolskiy #define S5K3M5_AGAIN_MAX 16 39*7d402666SVladimir Zapolskiy #define S5K3M5_AGAIN_STEP 1 40*7d402666SVladimir Zapolskiy #define S5K3M5_AGAIN_DEFAULT 1 41*7d402666SVladimir Zapolskiy #define S5K3M5_AGAIN_SHIFT 5 42*7d402666SVladimir Zapolskiy 43*7d402666SVladimir Zapolskiy #define S5K3M5_REG_VTS CCI_REG16(0x0340) 44*7d402666SVladimir Zapolskiy #define S5K3M5_VTS_MAX 0xffff 45*7d402666SVladimir Zapolskiy 46*7d402666SVladimir Zapolskiy #define S5K3M5_REG_HTS CCI_REG16(0x0342) 47*7d402666SVladimir Zapolskiy #define S5K3M5_REG_X_ADDR_START CCI_REG16(0x0344) 48*7d402666SVladimir Zapolskiy #define S5K3M5_REG_Y_ADDR_START CCI_REG16(0x0346) 49*7d402666SVladimir Zapolskiy #define S5K3M5_REG_X_ADDR_END CCI_REG16(0x0348) 50*7d402666SVladimir Zapolskiy #define S5K3M5_REG_Y_ADDR_END CCI_REG16(0x034a) 51*7d402666SVladimir Zapolskiy #define S5K3M5_REG_X_OUTPUT_SIZE CCI_REG16(0x034c) 52*7d402666SVladimir Zapolskiy #define S5K3M5_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e) 53*7d402666SVladimir Zapolskiy 54*7d402666SVladimir Zapolskiy #define S5K3M5_REG_TEST_PATTERN CCI_REG16(0x0600) 55*7d402666SVladimir Zapolskiy 56*7d402666SVladimir Zapolskiy #define to_s5k3m5(_sd) container_of(_sd, struct s5k3m5, sd) 57*7d402666SVladimir Zapolskiy 58*7d402666SVladimir Zapolskiy static const s64 s5k3m5_link_freq_menu[] = { 59*7d402666SVladimir Zapolskiy S5K3M5_LINK_FREQ_602P5MHZ, 60*7d402666SVladimir Zapolskiy }; 61*7d402666SVladimir Zapolskiy 62*7d402666SVladimir Zapolskiy /* List of supported formats to cover horizontal and vertical flip controls */ 63*7d402666SVladimir Zapolskiy static const u32 s5k3m5_mbus_formats[] = { 64*7d402666SVladimir Zapolskiy MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, 65*7d402666SVladimir Zapolskiy MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, 66*7d402666SVladimir Zapolskiy }; 67*7d402666SVladimir Zapolskiy 68*7d402666SVladimir Zapolskiy struct s5k3m5_reg_list { 69*7d402666SVladimir Zapolskiy const struct cci_reg_sequence *regs; 70*7d402666SVladimir Zapolskiy unsigned int num_regs; 71*7d402666SVladimir Zapolskiy }; 72*7d402666SVladimir Zapolskiy 73*7d402666SVladimir Zapolskiy struct s5k3m5_mode { 74*7d402666SVladimir Zapolskiy u32 width; /* Frame width in pixels */ 75*7d402666SVladimir Zapolskiy u32 height; /* Frame height in pixels */ 76*7d402666SVladimir Zapolskiy u32 hts; /* Horizontal timing size */ 77*7d402666SVladimir Zapolskiy u32 vts; /* Default vertical timing size */ 78*7d402666SVladimir Zapolskiy u32 exposure; /* Default exposure value */ 79*7d402666SVladimir Zapolskiy 80*7d402666SVladimir Zapolskiy const struct s5k3m5_reg_list reg_list; /* Sensor register setting */ 81*7d402666SVladimir Zapolskiy }; 82*7d402666SVladimir Zapolskiy 83*7d402666SVladimir Zapolskiy static const char * const s5k3m5_test_pattern_menu[] = { 84*7d402666SVladimir Zapolskiy "Disabled", 85*7d402666SVladimir Zapolskiy "Solid colour", 86*7d402666SVladimir Zapolskiy "Colour bars", 87*7d402666SVladimir Zapolskiy "Fade to grey colour bars", 88*7d402666SVladimir Zapolskiy "PN9", 89*7d402666SVladimir Zapolskiy }; 90*7d402666SVladimir Zapolskiy 91*7d402666SVladimir Zapolskiy static const char * const s5k3m5_supply_names[] = { 92*7d402666SVladimir Zapolskiy "afvdd", /* Autofocus power */ 93*7d402666SVladimir Zapolskiy "vdda", /* Analog power */ 94*7d402666SVladimir Zapolskiy "vddd", /* Digital core power */ 95*7d402666SVladimir Zapolskiy "vddio", /* Digital I/O power */ 96*7d402666SVladimir Zapolskiy }; 97*7d402666SVladimir Zapolskiy 98*7d402666SVladimir Zapolskiy #define S5K3M5_NUM_SUPPLIES ARRAY_SIZE(s5k3m5_supply_names) 99*7d402666SVladimir Zapolskiy 100*7d402666SVladimir Zapolskiy struct s5k3m5 { 101*7d402666SVladimir Zapolskiy struct device *dev; 102*7d402666SVladimir Zapolskiy struct regmap *regmap; 103*7d402666SVladimir Zapolskiy struct clk *mclk; 104*7d402666SVladimir Zapolskiy struct gpio_desc *reset_gpio; 105*7d402666SVladimir Zapolskiy struct regulator_bulk_data supplies[S5K3M5_NUM_SUPPLIES]; 106*7d402666SVladimir Zapolskiy 107*7d402666SVladimir Zapolskiy struct v4l2_subdev sd; 108*7d402666SVladimir Zapolskiy struct media_pad pad; 109*7d402666SVladimir Zapolskiy 110*7d402666SVladimir Zapolskiy struct v4l2_ctrl_handler ctrl_handler; 111*7d402666SVladimir Zapolskiy struct v4l2_ctrl *link_freq; 112*7d402666SVladimir Zapolskiy struct v4l2_ctrl *pixel_rate; 113*7d402666SVladimir Zapolskiy struct v4l2_ctrl *hblank; 114*7d402666SVladimir Zapolskiy struct v4l2_ctrl *vblank; 115*7d402666SVladimir Zapolskiy struct v4l2_ctrl *exposure; 116*7d402666SVladimir Zapolskiy struct v4l2_ctrl *vflip; 117*7d402666SVladimir Zapolskiy struct v4l2_ctrl *hflip; 118*7d402666SVladimir Zapolskiy 119*7d402666SVladimir Zapolskiy const struct s5k3m5_mode *mode; 120*7d402666SVladimir Zapolskiy }; 121*7d402666SVladimir Zapolskiy 122*7d402666SVladimir Zapolskiy static const struct cci_reg_sequence burst_array_setting[] = { 123*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 124*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 125*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0549 }, 126*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0448 }, 127*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x054a }, 128*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc1f8 }, 129*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc804 }, 130*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x101a }, 131*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa1f8 }, 132*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xcc04 }, 133*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 134*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1bb9 }, 135*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 136*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4210 }, 137*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 138*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2e50 }, 139*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 140*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7000 }, 141*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x10b5 }, 142*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 143*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4ff9 }, 144*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9949 }, 145*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0120 }, 146*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0880 }, 147*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x10bd }, 148*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2de9 }, 149*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf041 }, 150*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x974c }, 151*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x954f }, 152*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0026 }, 153*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb4f8 }, 154*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6a52 }, 155*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3888 }, 156*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x08b1 }, 157*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa4f8 }, 158*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6a62 }, 159*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 160*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x43f9 }, 161*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3e80 }, 162*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa4f8 }, 163*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6a52 }, 164*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xbde8 }, 165*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf081 }, 166*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2de9 }, 167*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf041 }, 168*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0746 }, 169*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8c48 }, 170*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0e46 }, 171*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 172*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4068 }, 173*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x84b2 }, 174*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x050c }, 175*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2146 }, 176*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2846 }, 177*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 178*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x36f9 }, 179*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3146 }, 180*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3846 }, 181*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 182*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x37f9 }, 183*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x874f }, 184*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4df2 }, 185*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0c26 }, 186*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4ff4 }, 187*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8061 }, 188*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3a78 }, 189*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3046 }, 190*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 191*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x29f9 }, 192*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7878 }, 193*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb8b3 }, 194*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 195*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8021 }, 196*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3046 }, 197*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 198*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x22f9 }, 199*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8048 }, 200*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0088 }, 201*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x804b }, 202*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 203*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5c02 }, 204*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7e48 }, 205*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x001d }, 206*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0088 }, 207*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 208*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5e02 }, 209*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 210*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5c02 }, 211*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 212*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5e12 }, 213*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4218 }, 214*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x02d0 }, 215*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8002 }, 216*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb0fb }, 217*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf2f2 }, 218*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x91b2 }, 219*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x784a }, 220*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 221*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6012 }, 222*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb2f8 }, 223*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1602 }, 224*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb2f8 }, 225*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1422 }, 226*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 227*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9805 }, 228*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 229*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9a25 }, 230*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8018 }, 231*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x04d0 }, 232*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9202 }, 233*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb2fb }, 234*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf0f0 }, 235*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa3f8 }, 236*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9c05 }, 237*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 238*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9c05 }, 239*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0a18 }, 240*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x01fb }, 241*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1020 }, 242*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x40f3 }, 243*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9510 }, 244*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1028 }, 245*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x06dc }, 246*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0028 }, 247*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x05da }, 248*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0020 }, 249*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x03e0 }, 250*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xffe7 }, 251*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0122 }, 252*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc5e7 }, 253*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1020 }, 254*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6849 }, 255*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0880 }, 256*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2146 }, 257*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2846 }, 258*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xbde8 }, 259*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf041 }, 260*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0122 }, 261*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 262*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xe2b8 }, 263*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf0b5 }, 264*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x644c }, 265*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xdde9 }, 266*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0565 }, 267*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x08b1 }, 268*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2788 }, 269*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0760 }, 270*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x09b1 }, 271*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6088 }, 272*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0860 }, 273*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x12b1 }, 274*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa088 }, 275*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x401c }, 276*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1060 }, 277*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0bb1 }, 278*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xe088 }, 279*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1860 }, 280*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0eb1 }, 281*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa07b }, 282*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3060 }, 283*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x002d }, 284*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x01d0 }, 285*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xe07b }, 286*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2860 }, 287*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf0bd }, 288*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x70b5 }, 289*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0646 }, 290*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5048 }, 291*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 292*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8068 }, 293*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x84b2 }, 294*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x050c }, 295*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2146 }, 296*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2846 }, 297*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 298*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xbef8 }, 299*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3046 }, 300*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 301*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc5f8 }, 302*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5248 }, 303*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0368 }, 304*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 305*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7401 }, 306*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x010a }, 307*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5048 }, 308*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4268 }, 309*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 310*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5010 }, 311*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 312*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7511 }, 313*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 314*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5210 }, 315*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 316*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7811 }, 317*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x090a }, 318*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 319*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5810 }, 320*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 321*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7911 }, 322*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 323*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5a10 }, 324*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x33f8 }, 325*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf01f }, 326*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0068 }, 327*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x090a }, 328*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f8 }, 329*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xce1f }, 330*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5978 }, 331*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8170 }, 332*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5988 }, 333*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x090a }, 334*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0171 }, 335*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xd978 }, 336*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8171 }, 337*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x988c }, 338*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000a }, 339*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9074 }, 340*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 341*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2500 }, 342*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1075 }, 343*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xd88c }, 344*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000a }, 345*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9075 }, 346*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 347*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2700 }, 348*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1076 }, 349*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb3f8 }, 350*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb000 }, 351*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000a }, 352*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 353*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7e00 }, 354*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 355*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb100 }, 356*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 357*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8000 }, 358*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2f48 }, 359*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x90f8 }, 360*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb313 }, 361*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 362*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8210 }, 363*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x90f8 }, 364*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb103 }, 365*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 366*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8400 }, 367*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 368*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xb400 }, 369*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 370*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8600 }, 371*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0020 }, 372*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 373*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8800 }, 374*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 375*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6211 }, 376*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 377*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9610 }, 378*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 379*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0112 }, 380*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 381*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9e10 }, 382*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 383*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0212 }, 384*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 385*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa010 }, 386*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 387*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa200 }, 388*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 389*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa400 }, 390*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 391*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0512 }, 392*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 393*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa610 }, 394*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 395*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0612 }, 396*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 397*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa810 }, 398*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 399*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0712 }, 400*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 401*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaa10 }, 402*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 403*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xac00 }, 404*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x5a20 }, 405*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 406*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xad00 }, 407*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x93f8 }, 408*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0902 }, 409*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x82f8 }, 410*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xae00 }, 411*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2146 }, 412*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2846 }, 413*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xbde8 }, 414*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7040 }, 415*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0122 }, 416*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 417*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x47b8 }, 418*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x10b5 }, 419*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0f4c }, 420*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0020 }, 421*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2080 }, 422*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaff2 }, 423*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3321 }, 424*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1748 }, 425*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0161 }, 426*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaff2 }, 427*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2d21 }, 428*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 429*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x8161 }, 430*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaff2 }, 431*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1121 }, 432*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1448 }, 433*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 434*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x45f8 }, 435*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 436*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaff2 }, 437*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2911 }, 438*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6060 }, 439*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1148 }, 440*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 441*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3ef8 }, 442*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0022 }, 443*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xaff2 }, 444*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6b11 }, 445*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa060 }, 446*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0f48 }, 447*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00f0 }, 448*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x37f8 }, 449*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xe060 }, 450*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x10bd }, 451*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 452*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4200 }, 453*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 454*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2e50 }, 455*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 456*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x41d0 }, 457*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4000 }, 458*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x9404 }, 459*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 460*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x38e0 }, 461*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4000 }, 462*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xd000 }, 463*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4000 }, 464*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xa410 }, 465*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 466*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2c66 }, 467*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 468*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0890 }, 469*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 470*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3620 }, 471*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x2000 }, 472*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0840 }, 473*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0001 }, 474*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x020d }, 475*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 476*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x67cd }, 477*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 478*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3ae1 }, 479*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x45f6 }, 480*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x250c }, 481*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 482*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 483*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 484*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x45f6 }, 485*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xf31c }, 486*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 487*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 488*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 489*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4af2 }, 490*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xd74c }, 491*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 492*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 493*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 494*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x40f2 }, 495*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0d2c }, 496*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 497*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x010c }, 498*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 499*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x46f2 }, 500*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xcd7c }, 501*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 502*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 503*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 504*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x4af6 }, 505*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xe75c }, 506*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0xc0f2 }, 507*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 508*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x6047 }, 509*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x30d5 }, 510*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x00fc }, 511*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 512*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000e }, 513*7d402666SVladimir Zapolskiy }; 514*7d402666SVladimir Zapolskiy 515*7d402666SVladimir Zapolskiy static const struct cci_reg_sequence init_array_setting[] = { 516*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x41d0 }, 517*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0100 }, 518*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x1662 }, 519*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x1e00 }, 520*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x1c9a }, 521*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 522*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 523*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 524*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 525*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 526*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 527*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 528*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 529*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 530*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 531*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 532*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 533*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 534*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 535*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 536*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 537*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0ff2 }, 538*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0020 }, 539*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0ef6 }, 540*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0100 }, 541*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x23b2 }, 542*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0001 }, 543*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0fe4 }, 544*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0107 }, 545*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x07d0 }, 546*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x12f8 }, 547*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x3d09 }, 548*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0e18 }, 549*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0040 }, 550*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x1066 }, 551*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x000c }, 552*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x13de }, 553*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 554*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x12f2 }, 555*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0f0f }, 556*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x13dc }, 557*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x806f }, 558*7d402666SVladimir Zapolskiy { CCI_REG16(0xf46e), 0x00c3 }, 559*7d402666SVladimir Zapolskiy { CCI_REG16(0xf46c), 0xbfa0 }, 560*7d402666SVladimir Zapolskiy { CCI_REG16(0xf44a), 0x0007 }, 561*7d402666SVladimir Zapolskiy { CCI_REG16(0xf456), 0x000a }, 562*7d402666SVladimir Zapolskiy { CCI_REG16(0x6028), 0x2000 }, 563*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x12f6 }, 564*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x7008 }, 565*7d402666SVladimir Zapolskiy { CCI_REG16(0x0bc6), 0x0000 }, 566*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b36), 0x0001 }, 567*7d402666SVladimir Zapolskiy }; 568*7d402666SVladimir Zapolskiy 569*7d402666SVladimir Zapolskiy static const struct cci_reg_sequence s5k3m5_4208x3120_30fps_mode[] = { 570*7d402666SVladimir Zapolskiy { CCI_REG16(0x6214), 0x7971 }, 571*7d402666SVladimir Zapolskiy { CCI_REG16(0x6218), 0x7150 }, 572*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_ADDR_START, 0x0000 }, 573*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_ADDR_START, 0x0008 }, 574*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_ADDR_END, 0x1077 }, 575*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_ADDR_END, 0x0c37 }, 576*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_OUTPUT_SIZE, 0x1070 }, 577*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_OUTPUT_SIZE, 0x0c30 }, 578*7d402666SVladimir Zapolskiy { S5K3M5_REG_VTS, 0x0cf2 }, 579*7d402666SVladimir Zapolskiy { S5K3M5_REG_HTS, 0x12f0 }, 580*7d402666SVladimir Zapolskiy 581*7d402666SVladimir Zapolskiy { CCI_REG16(0x0900), 0x0011 }, 582*7d402666SVladimir Zapolskiy { CCI_REG16(0x0380), 0x0001 }, 583*7d402666SVladimir Zapolskiy { CCI_REG16(0x0382), 0x0001 }, 584*7d402666SVladimir Zapolskiy { CCI_REG16(0x0384), 0x0001 }, 585*7d402666SVladimir Zapolskiy { CCI_REG16(0x0386), 0x0001 }, 586*7d402666SVladimir Zapolskiy { CCI_REG16(0x0402), 0x1010 }, 587*7d402666SVladimir Zapolskiy { CCI_REG16(0x0404), 0x1000 }, 588*7d402666SVladimir Zapolskiy { CCI_REG16(0x0350), 0x0008 }, 589*7d402666SVladimir Zapolskiy { CCI_REG16(0x0352), 0x0000 }, 590*7d402666SVladimir Zapolskiy 591*7d402666SVladimir Zapolskiy /* Clock settings */ 592*7d402666SVladimir Zapolskiy { CCI_REG16(0x0136), 0x1800 }, 593*7d402666SVladimir Zapolskiy { CCI_REG16(0x013e), 0x0000 }, 594*7d402666SVladimir Zapolskiy { CCI_REG16(0x0300), 0x0008 }, 595*7d402666SVladimir Zapolskiy { CCI_REG16(0x0302), 0x0001 }, 596*7d402666SVladimir Zapolskiy { CCI_REG16(0x0304), 0x0006 }, 597*7d402666SVladimir Zapolskiy { CCI_REG16(0x0306), 0x00f1 }, 598*7d402666SVladimir Zapolskiy { CCI_REG16(0x0308), 0x0008 }, 599*7d402666SVladimir Zapolskiy { CCI_REG16(0x030a), 0x0001 }, 600*7d402666SVladimir Zapolskiy { CCI_REG16(0x030c), 0x0000 }, 601*7d402666SVladimir Zapolskiy { CCI_REG16(0x030e), 0x0003 }, 602*7d402666SVladimir Zapolskiy { CCI_REG16(0x0310), 0x005a }, 603*7d402666SVladimir Zapolskiy { CCI_REG16(0x0312), 0x0000 }, 604*7d402666SVladimir Zapolskiy 605*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b06), 0x0101 }, 606*7d402666SVladimir Zapolskiy { CCI_REG16(0x6028), 0x2000 }, 607*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x1ff6 }, 608*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 609*7d402666SVladimir Zapolskiy { CCI_REG16(0x021e), 0x0000 }, 610*7d402666SVladimir Zapolskiy { CCI_REG16(0x0202), 0x0100 }, 611*7d402666SVladimir Zapolskiy { CCI_REG16(0x0204), 0x0020 }, 612*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d00), 0x0100 }, 613*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d02), 0x0001 }, 614*7d402666SVladimir Zapolskiy { CCI_REG16(0x0114), 0x0301 }, 615*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d06), 0x0208 }, 616*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d08), 0x0300 }, 617*7d402666SVladimir Zapolskiy { CCI_REG16(0x6028), 0x2000 }, 618*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0f10 }, 619*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0003 }, 620*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0f12 }, 621*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0200 }, 622*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x2bc0 }, 623*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0001 }, 624*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b30), 0x0000 }, 625*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b32), 0x0000 }, 626*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b34), 0x0001 }, 627*7d402666SVladimir Zapolskiy { CCI_REG16(0x0804), 0x0200 }, 628*7d402666SVladimir Zapolskiy { CCI_REG16(0x0810), 0x0020 }, 629*7d402666SVladimir Zapolskiy }; 630*7d402666SVladimir Zapolskiy 631*7d402666SVladimir Zapolskiy static const struct cci_reg_sequence s5k3m5_2104x1184_60fps_mode[] = { 632*7d402666SVladimir Zapolskiy { CCI_REG16(0x6214), 0x7971 }, 633*7d402666SVladimir Zapolskiy { CCI_REG16(0x6218), 0x7150 }, 634*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_ADDR_START, 0x0000 }, 635*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_ADDR_START, 0x0180 }, 636*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_ADDR_END, 0x1077 }, 637*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_ADDR_END, 0x0abf }, 638*7d402666SVladimir Zapolskiy { S5K3M5_REG_X_OUTPUT_SIZE, 0x0838 }, 639*7d402666SVladimir Zapolskiy { S5K3M5_REG_Y_OUTPUT_SIZE, 0x04a0 }, 640*7d402666SVladimir Zapolskiy { S5K3M5_REG_VTS, 0x0658 }, 641*7d402666SVladimir Zapolskiy { S5K3M5_REG_HTS, 0x1340 }, 642*7d402666SVladimir Zapolskiy 643*7d402666SVladimir Zapolskiy { CCI_REG16(0x0900), 0x0112 }, 644*7d402666SVladimir Zapolskiy { CCI_REG16(0x0380), 0x0001 }, 645*7d402666SVladimir Zapolskiy { CCI_REG16(0x0382), 0x0001 }, 646*7d402666SVladimir Zapolskiy { CCI_REG16(0x0384), 0x0001 }, 647*7d402666SVladimir Zapolskiy { CCI_REG16(0x0386), 0x0003 }, 648*7d402666SVladimir Zapolskiy { CCI_REG16(0x0402), 0x1010 }, 649*7d402666SVladimir Zapolskiy { CCI_REG16(0x0404), 0x2000 }, 650*7d402666SVladimir Zapolskiy { CCI_REG16(0x0350), 0x0004 }, 651*7d402666SVladimir Zapolskiy { CCI_REG16(0x0352), 0x0000 }, 652*7d402666SVladimir Zapolskiy 653*7d402666SVladimir Zapolskiy /* Clock settings */ 654*7d402666SVladimir Zapolskiy { CCI_REG16(0x0136), 0x1800 }, 655*7d402666SVladimir Zapolskiy { CCI_REG16(0x013e), 0x0000 }, 656*7d402666SVladimir Zapolskiy { CCI_REG16(0x0300), 0x0008 }, 657*7d402666SVladimir Zapolskiy { CCI_REG16(0x0302), 0x0001 }, 658*7d402666SVladimir Zapolskiy { CCI_REG16(0x0304), 0x0006 }, 659*7d402666SVladimir Zapolskiy { CCI_REG16(0x0306), 0x00f1 }, 660*7d402666SVladimir Zapolskiy { CCI_REG16(0x0308), 0x0008 }, 661*7d402666SVladimir Zapolskiy { CCI_REG16(0x030a), 0x0001 }, 662*7d402666SVladimir Zapolskiy { CCI_REG16(0x030c), 0x0000 }, 663*7d402666SVladimir Zapolskiy { CCI_REG16(0x030e), 0x0003 }, 664*7d402666SVladimir Zapolskiy { CCI_REG16(0x0310), 0x0063 }, 665*7d402666SVladimir Zapolskiy { CCI_REG16(0x0312), 0x0001 }, 666*7d402666SVladimir Zapolskiy 667*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b06), 0x0101 }, 668*7d402666SVladimir Zapolskiy { CCI_REG16(0x6028), 0x2000 }, 669*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x1ff6 }, 670*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0000 }, 671*7d402666SVladimir Zapolskiy { CCI_REG16(0x021e), 0x0000 }, 672*7d402666SVladimir Zapolskiy { CCI_REG16(0x0202), 0x0100 }, 673*7d402666SVladimir Zapolskiy { CCI_REG16(0x0204), 0x0020 }, 674*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d00), 0x0101 }, 675*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d02), 0x0101 }, 676*7d402666SVladimir Zapolskiy { CCI_REG16(0x0114), 0x0301 }, 677*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d06), 0x0208 }, 678*7d402666SVladimir Zapolskiy { CCI_REG16(0x0d08), 0x0300 }, 679*7d402666SVladimir Zapolskiy { CCI_REG16(0x6028), 0x2000 }, 680*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0f10 }, 681*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0003 }, 682*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x0f12 }, 683*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0200 }, 684*7d402666SVladimir Zapolskiy { CCI_REG16(0x602a), 0x2bc0 }, 685*7d402666SVladimir Zapolskiy { CCI_REG16(0x6f12), 0x0001 }, 686*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b30), 0x0000 }, 687*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b32), 0x0000 }, 688*7d402666SVladimir Zapolskiy { CCI_REG16(0x0b34), 0x0001 }, 689*7d402666SVladimir Zapolskiy { CCI_REG16(0x0804), 0x0200 }, 690*7d402666SVladimir Zapolskiy { CCI_REG16(0x0810), 0x0020 }, 691*7d402666SVladimir Zapolskiy }; 692*7d402666SVladimir Zapolskiy 693*7d402666SVladimir Zapolskiy static const struct s5k3m5_mode s5k3m5_supported_modes[] = { 694*7d402666SVladimir Zapolskiy { 695*7d402666SVladimir Zapolskiy .width = 4208, 696*7d402666SVladimir Zapolskiy .height = 3120, 697*7d402666SVladimir Zapolskiy .hts = 4848, 698*7d402666SVladimir Zapolskiy .vts = 3314, 699*7d402666SVladimir Zapolskiy .exposure = 256, 700*7d402666SVladimir Zapolskiy .reg_list = { 701*7d402666SVladimir Zapolskiy .regs = s5k3m5_4208x3120_30fps_mode, 702*7d402666SVladimir Zapolskiy .num_regs = ARRAY_SIZE(s5k3m5_4208x3120_30fps_mode), 703*7d402666SVladimir Zapolskiy }, 704*7d402666SVladimir Zapolskiy }, 705*7d402666SVladimir Zapolskiy { 706*7d402666SVladimir Zapolskiy .width = 2104, 707*7d402666SVladimir Zapolskiy .height = 1184, 708*7d402666SVladimir Zapolskiy .hts = 4928, 709*7d402666SVladimir Zapolskiy .vts = 1624, 710*7d402666SVladimir Zapolskiy .exposure = 256, 711*7d402666SVladimir Zapolskiy .reg_list = { 712*7d402666SVladimir Zapolskiy .regs = s5k3m5_2104x1184_60fps_mode, 713*7d402666SVladimir Zapolskiy .num_regs = ARRAY_SIZE(s5k3m5_2104x1184_60fps_mode), 714*7d402666SVladimir Zapolskiy }, 715*7d402666SVladimir Zapolskiy }, 716*7d402666SVladimir Zapolskiy }; 717*7d402666SVladimir Zapolskiy 718*7d402666SVladimir Zapolskiy static int s5k3m5_set_ctrl(struct v4l2_ctrl *ctrl) 719*7d402666SVladimir Zapolskiy { 720*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = container_of(ctrl->handler, struct s5k3m5, 721*7d402666SVladimir Zapolskiy ctrl_handler); 722*7d402666SVladimir Zapolskiy const struct s5k3m5_mode *mode = s5k3m5->mode; 723*7d402666SVladimir Zapolskiy s64 exposure_max; 724*7d402666SVladimir Zapolskiy int ret; 725*7d402666SVladimir Zapolskiy 726*7d402666SVladimir Zapolskiy /* Propagate change of current control to all related controls */ 727*7d402666SVladimir Zapolskiy switch (ctrl->id) { 728*7d402666SVladimir Zapolskiy case V4L2_CID_HFLIP: 729*7d402666SVladimir Zapolskiy case V4L2_CID_VFLIP: 730*7d402666SVladimir Zapolskiy /* The orientation settings are applied along with streaming */ 731*7d402666SVladimir Zapolskiy return 0; 732*7d402666SVladimir Zapolskiy case V4L2_CID_VBLANK: 733*7d402666SVladimir Zapolskiy /* Update max exposure while meeting expected vblanking */ 734*7d402666SVladimir Zapolskiy exposure_max = mode->height + ctrl->val - S5K3M5_EXPOSURE_MARGIN; 735*7d402666SVladimir Zapolskiy __v4l2_ctrl_modify_range(s5k3m5->exposure, 736*7d402666SVladimir Zapolskiy s5k3m5->exposure->minimum, 737*7d402666SVladimir Zapolskiy exposure_max, 738*7d402666SVladimir Zapolskiy s5k3m5->exposure->step, 739*7d402666SVladimir Zapolskiy s5k3m5->exposure->default_value); 740*7d402666SVladimir Zapolskiy break; 741*7d402666SVladimir Zapolskiy } 742*7d402666SVladimir Zapolskiy 743*7d402666SVladimir Zapolskiy /* V4L2 controls are applied, when sensor is powered up for streaming */ 744*7d402666SVladimir Zapolskiy if (!pm_runtime_get_if_active(s5k3m5->dev)) 745*7d402666SVladimir Zapolskiy return 0; 746*7d402666SVladimir Zapolskiy 747*7d402666SVladimir Zapolskiy switch (ctrl->id) { 748*7d402666SVladimir Zapolskiy case V4L2_CID_ANALOGUE_GAIN: 749*7d402666SVladimir Zapolskiy ret = cci_write(s5k3m5->regmap, S5K3M5_REG_AGAIN, 750*7d402666SVladimir Zapolskiy ctrl->val << S5K3M5_AGAIN_SHIFT, NULL); 751*7d402666SVladimir Zapolskiy break; 752*7d402666SVladimir Zapolskiy case V4L2_CID_EXPOSURE: 753*7d402666SVladimir Zapolskiy ret = cci_write(s5k3m5->regmap, S5K3M5_REG_EXPOSURE, 754*7d402666SVladimir Zapolskiy ctrl->val, NULL); 755*7d402666SVladimir Zapolskiy break; 756*7d402666SVladimir Zapolskiy case V4L2_CID_VBLANK: 757*7d402666SVladimir Zapolskiy ret = cci_write(s5k3m5->regmap, S5K3M5_REG_VTS, 758*7d402666SVladimir Zapolskiy ctrl->val + mode->height, NULL); 759*7d402666SVladimir Zapolskiy break; 760*7d402666SVladimir Zapolskiy case V4L2_CID_TEST_PATTERN: 761*7d402666SVladimir Zapolskiy ret = cci_write(s5k3m5->regmap, S5K3M5_REG_TEST_PATTERN, 762*7d402666SVladimir Zapolskiy ctrl->val, NULL); 763*7d402666SVladimir Zapolskiy break; 764*7d402666SVladimir Zapolskiy default: 765*7d402666SVladimir Zapolskiy ret = -EINVAL; 766*7d402666SVladimir Zapolskiy break; 767*7d402666SVladimir Zapolskiy } 768*7d402666SVladimir Zapolskiy 769*7d402666SVladimir Zapolskiy pm_runtime_put(s5k3m5->dev); 770*7d402666SVladimir Zapolskiy 771*7d402666SVladimir Zapolskiy return ret; 772*7d402666SVladimir Zapolskiy } 773*7d402666SVladimir Zapolskiy 774*7d402666SVladimir Zapolskiy static const struct v4l2_ctrl_ops s5k3m5_ctrl_ops = { 775*7d402666SVladimir Zapolskiy .s_ctrl = s5k3m5_set_ctrl, 776*7d402666SVladimir Zapolskiy }; 777*7d402666SVladimir Zapolskiy 778*7d402666SVladimir Zapolskiy static inline u64 s5k3m5_freq_to_pixel_rate(const u64 freq) 779*7d402666SVladimir Zapolskiy { 780*7d402666SVladimir Zapolskiy return div_u64(freq * 2 * S5K3M5_DATA_LANES, 10); 781*7d402666SVladimir Zapolskiy } 782*7d402666SVladimir Zapolskiy 783*7d402666SVladimir Zapolskiy static int s5k3m5_init_controls(struct s5k3m5 *s5k3m5) 784*7d402666SVladimir Zapolskiy { 785*7d402666SVladimir Zapolskiy struct v4l2_ctrl_handler *ctrl_hdlr = &s5k3m5->ctrl_handler; 786*7d402666SVladimir Zapolskiy const struct s5k3m5_mode *mode = s5k3m5->mode; 787*7d402666SVladimir Zapolskiy s64 pixel_rate, hblank, vblank, exposure_max; 788*7d402666SVladimir Zapolskiy struct v4l2_fwnode_device_properties props; 789*7d402666SVladimir Zapolskiy int ret; 790*7d402666SVladimir Zapolskiy 791*7d402666SVladimir Zapolskiy v4l2_ctrl_handler_init(ctrl_hdlr, 9); 792*7d402666SVladimir Zapolskiy 793*7d402666SVladimir Zapolskiy s5k3m5->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &s5k3m5_ctrl_ops, 794*7d402666SVladimir Zapolskiy V4L2_CID_LINK_FREQ, 795*7d402666SVladimir Zapolskiy ARRAY_SIZE(s5k3m5_link_freq_menu) - 1, 796*7d402666SVladimir Zapolskiy 0, s5k3m5_link_freq_menu); 797*7d402666SVladimir Zapolskiy if (s5k3m5->link_freq) 798*7d402666SVladimir Zapolskiy s5k3m5->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 799*7d402666SVladimir Zapolskiy 800*7d402666SVladimir Zapolskiy pixel_rate = s5k3m5_freq_to_pixel_rate(s5k3m5_link_freq_menu[0]); 801*7d402666SVladimir Zapolskiy s5k3m5->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 802*7d402666SVladimir Zapolskiy V4L2_CID_PIXEL_RATE, 803*7d402666SVladimir Zapolskiy 0, pixel_rate, 1, pixel_rate); 804*7d402666SVladimir Zapolskiy 805*7d402666SVladimir Zapolskiy hblank = mode->hts - mode->width; 806*7d402666SVladimir Zapolskiy s5k3m5->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 807*7d402666SVladimir Zapolskiy V4L2_CID_HBLANK, hblank, 808*7d402666SVladimir Zapolskiy hblank, 1, hblank); 809*7d402666SVladimir Zapolskiy if (s5k3m5->hblank) 810*7d402666SVladimir Zapolskiy s5k3m5->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 811*7d402666SVladimir Zapolskiy 812*7d402666SVladimir Zapolskiy vblank = mode->vts - mode->height; 813*7d402666SVladimir Zapolskiy s5k3m5->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 814*7d402666SVladimir Zapolskiy V4L2_CID_VBLANK, vblank, 815*7d402666SVladimir Zapolskiy S5K3M5_VTS_MAX - mode->height, 1, 816*7d402666SVladimir Zapolskiy vblank); 817*7d402666SVladimir Zapolskiy 818*7d402666SVladimir Zapolskiy v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 819*7d402666SVladimir Zapolskiy S5K3M5_AGAIN_MIN, S5K3M5_AGAIN_MAX, 820*7d402666SVladimir Zapolskiy S5K3M5_AGAIN_STEP, S5K3M5_AGAIN_DEFAULT); 821*7d402666SVladimir Zapolskiy 822*7d402666SVladimir Zapolskiy exposure_max = mode->vts - S5K3M5_EXPOSURE_MARGIN; 823*7d402666SVladimir Zapolskiy s5k3m5->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 824*7d402666SVladimir Zapolskiy V4L2_CID_EXPOSURE, 825*7d402666SVladimir Zapolskiy S5K3M5_EXPOSURE_MIN, 826*7d402666SVladimir Zapolskiy exposure_max, 827*7d402666SVladimir Zapolskiy S5K3M5_EXPOSURE_STEP, 828*7d402666SVladimir Zapolskiy mode->exposure); 829*7d402666SVladimir Zapolskiy 830*7d402666SVladimir Zapolskiy v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &s5k3m5_ctrl_ops, 831*7d402666SVladimir Zapolskiy V4L2_CID_TEST_PATTERN, 832*7d402666SVladimir Zapolskiy ARRAY_SIZE(s5k3m5_test_pattern_menu) - 1, 833*7d402666SVladimir Zapolskiy 0, 0, s5k3m5_test_pattern_menu); 834*7d402666SVladimir Zapolskiy 835*7d402666SVladimir Zapolskiy s5k3m5->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 836*7d402666SVladimir Zapolskiy V4L2_CID_HFLIP, 0, 1, 1, 0); 837*7d402666SVladimir Zapolskiy if (s5k3m5->hflip) 838*7d402666SVladimir Zapolskiy s5k3m5->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 839*7d402666SVladimir Zapolskiy 840*7d402666SVladimir Zapolskiy s5k3m5->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, 841*7d402666SVladimir Zapolskiy V4L2_CID_VFLIP, 0, 1, 1, 0); 842*7d402666SVladimir Zapolskiy if (s5k3m5->vflip) 843*7d402666SVladimir Zapolskiy s5k3m5->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 844*7d402666SVladimir Zapolskiy 845*7d402666SVladimir Zapolskiy ret = v4l2_fwnode_device_parse(s5k3m5->dev, &props); 846*7d402666SVladimir Zapolskiy if (ret) 847*7d402666SVladimir Zapolskiy goto error_free_hdlr; 848*7d402666SVladimir Zapolskiy 849*7d402666SVladimir Zapolskiy ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &s5k3m5_ctrl_ops, 850*7d402666SVladimir Zapolskiy &props); 851*7d402666SVladimir Zapolskiy if (ret) 852*7d402666SVladimir Zapolskiy goto error_free_hdlr; 853*7d402666SVladimir Zapolskiy 854*7d402666SVladimir Zapolskiy s5k3m5->sd.ctrl_handler = ctrl_hdlr; 855*7d402666SVladimir Zapolskiy 856*7d402666SVladimir Zapolskiy return 0; 857*7d402666SVladimir Zapolskiy 858*7d402666SVladimir Zapolskiy error_free_hdlr: 859*7d402666SVladimir Zapolskiy v4l2_ctrl_handler_free(ctrl_hdlr); 860*7d402666SVladimir Zapolskiy 861*7d402666SVladimir Zapolskiy return ret; 862*7d402666SVladimir Zapolskiy } 863*7d402666SVladimir Zapolskiy 864*7d402666SVladimir Zapolskiy static int s5k3m5_enable_streams(struct v4l2_subdev *sd, 865*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *state, u32 pad, 866*7d402666SVladimir Zapolskiy u64 streams_mask) 867*7d402666SVladimir Zapolskiy { 868*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 869*7d402666SVladimir Zapolskiy const struct s5k3m5_reg_list *reg_list = &s5k3m5->mode->reg_list; 870*7d402666SVladimir Zapolskiy int ret; 871*7d402666SVladimir Zapolskiy 872*7d402666SVladimir Zapolskiy ret = pm_runtime_resume_and_get(s5k3m5->dev); 873*7d402666SVladimir Zapolskiy if (ret) 874*7d402666SVladimir Zapolskiy return ret; 875*7d402666SVladimir Zapolskiy 876*7d402666SVladimir Zapolskiy /* Page pointer */ 877*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x4000, &ret); 878*7d402666SVladimir Zapolskiy 879*7d402666SVladimir Zapolskiy /* Set version */ 880*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x0000), 0x0006, &ret); 881*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x0000), S5K3M5_CHIP_ID, &ret); 882*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x6214), 0x7971, &ret); 883*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x6218), 0x7150, &ret); 884*7d402666SVladimir Zapolskiy if (ret) 885*7d402666SVladimir Zapolskiy goto error; 886*7d402666SVladimir Zapolskiy 887*7d402666SVladimir Zapolskiy usleep_range(4 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); 888*7d402666SVladimir Zapolskiy 889*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x0a02), 0x7800, &ret); 890*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x2000, &ret); 891*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, CCI_REG16(0x602a), 0x3eac, &ret); 892*7d402666SVladimir Zapolskiy 893*7d402666SVladimir Zapolskiy /* Sensor init settings */ 894*7d402666SVladimir Zapolskiy cci_multi_reg_write(s5k3m5->regmap, burst_array_setting, 895*7d402666SVladimir Zapolskiy ARRAY_SIZE(burst_array_setting), &ret); 896*7d402666SVladimir Zapolskiy cci_multi_reg_write(s5k3m5->regmap, init_array_setting, 897*7d402666SVladimir Zapolskiy ARRAY_SIZE(init_array_setting), &ret); 898*7d402666SVladimir Zapolskiy cci_multi_reg_write(s5k3m5->regmap, reg_list->regs, 899*7d402666SVladimir Zapolskiy reg_list->num_regs, &ret); 900*7d402666SVladimir Zapolskiy if (ret) 901*7d402666SVladimir Zapolskiy goto error; 902*7d402666SVladimir Zapolskiy 903*7d402666SVladimir Zapolskiy ret = __v4l2_ctrl_handler_setup(s5k3m5->sd.ctrl_handler); 904*7d402666SVladimir Zapolskiy 905*7d402666SVladimir Zapolskiy cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE, 906*7d402666SVladimir Zapolskiy S5K3M5_MODE_STREAMING | 907*7d402666SVladimir Zapolskiy (s5k3m5->vflip->val ? S5K3M5_VFLIP : 0) | 908*7d402666SVladimir Zapolskiy (s5k3m5->hflip->val ? S5K3M5_HFLIP : 0), &ret); 909*7d402666SVladimir Zapolskiy if (ret) 910*7d402666SVladimir Zapolskiy goto error; 911*7d402666SVladimir Zapolskiy 912*7d402666SVladimir Zapolskiy return 0; 913*7d402666SVladimir Zapolskiy 914*7d402666SVladimir Zapolskiy error: 915*7d402666SVladimir Zapolskiy dev_err(s5k3m5->dev, "failed to start streaming: %d\n", ret); 916*7d402666SVladimir Zapolskiy pm_runtime_put_autosuspend(s5k3m5->dev); 917*7d402666SVladimir Zapolskiy 918*7d402666SVladimir Zapolskiy return ret; 919*7d402666SVladimir Zapolskiy } 920*7d402666SVladimir Zapolskiy 921*7d402666SVladimir Zapolskiy static int s5k3m5_disable_streams(struct v4l2_subdev *sd, 922*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *state, u32 pad, 923*7d402666SVladimir Zapolskiy u64 streams_mask) 924*7d402666SVladimir Zapolskiy { 925*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 926*7d402666SVladimir Zapolskiy int ret; 927*7d402666SVladimir Zapolskiy 928*7d402666SVladimir Zapolskiy ret = cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE, 0, NULL); 929*7d402666SVladimir Zapolskiy if (ret) 930*7d402666SVladimir Zapolskiy dev_err(s5k3m5->dev, "failed to stop streaming: %d\n", ret); 931*7d402666SVladimir Zapolskiy 932*7d402666SVladimir Zapolskiy pm_runtime_put_autosuspend(s5k3m5->dev); 933*7d402666SVladimir Zapolskiy 934*7d402666SVladimir Zapolskiy return ret; 935*7d402666SVladimir Zapolskiy } 936*7d402666SVladimir Zapolskiy 937*7d402666SVladimir Zapolskiy static u32 s5k3m5_get_format_code(struct s5k3m5 *s5k3m5) 938*7d402666SVladimir Zapolskiy { 939*7d402666SVladimir Zapolskiy unsigned int i; 940*7d402666SVladimir Zapolskiy 941*7d402666SVladimir Zapolskiy i = (s5k3m5->vflip->val ? 2 : 0) | (s5k3m5->hflip->val ? 1 : 0); 942*7d402666SVladimir Zapolskiy 943*7d402666SVladimir Zapolskiy return s5k3m5_mbus_formats[i]; 944*7d402666SVladimir Zapolskiy } 945*7d402666SVladimir Zapolskiy 946*7d402666SVladimir Zapolskiy static void s5k3m5_update_pad_format(struct s5k3m5 *s5k3m5, 947*7d402666SVladimir Zapolskiy const struct s5k3m5_mode *mode, 948*7d402666SVladimir Zapolskiy struct v4l2_mbus_framefmt *fmt) 949*7d402666SVladimir Zapolskiy { 950*7d402666SVladimir Zapolskiy fmt->code = s5k3m5_get_format_code(s5k3m5); 951*7d402666SVladimir Zapolskiy fmt->width = mode->width; 952*7d402666SVladimir Zapolskiy fmt->height = mode->height; 953*7d402666SVladimir Zapolskiy fmt->field = V4L2_FIELD_NONE; 954*7d402666SVladimir Zapolskiy fmt->colorspace = V4L2_COLORSPACE_SRGB; 955*7d402666SVladimir Zapolskiy fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 956*7d402666SVladimir Zapolskiy fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 957*7d402666SVladimir Zapolskiy fmt->xfer_func = V4L2_XFER_FUNC_NONE; 958*7d402666SVladimir Zapolskiy } 959*7d402666SVladimir Zapolskiy 960*7d402666SVladimir Zapolskiy static int s5k3m5_set_pad_format(struct v4l2_subdev *sd, 961*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *state, 962*7d402666SVladimir Zapolskiy struct v4l2_subdev_format *fmt) 963*7d402666SVladimir Zapolskiy { 964*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 965*7d402666SVladimir Zapolskiy s64 hblank, vblank, exposure_max; 966*7d402666SVladimir Zapolskiy const struct s5k3m5_mode *mode; 967*7d402666SVladimir Zapolskiy 968*7d402666SVladimir Zapolskiy mode = v4l2_find_nearest_size(s5k3m5_supported_modes, 969*7d402666SVladimir Zapolskiy ARRAY_SIZE(s5k3m5_supported_modes), 970*7d402666SVladimir Zapolskiy width, height, 971*7d402666SVladimir Zapolskiy fmt->format.width, fmt->format.height); 972*7d402666SVladimir Zapolskiy 973*7d402666SVladimir Zapolskiy s5k3m5_update_pad_format(s5k3m5, mode, &fmt->format); 974*7d402666SVladimir Zapolskiy 975*7d402666SVladimir Zapolskiy /* Format code could be updated with respect to flip controls */ 976*7d402666SVladimir Zapolskiy if (fmt->which == V4L2_SUBDEV_FORMAT_TRY || s5k3m5->mode == mode) 977*7d402666SVladimir Zapolskiy goto set_format; 978*7d402666SVladimir Zapolskiy 979*7d402666SVladimir Zapolskiy /* Update limits and set FPS and exposure to default values */ 980*7d402666SVladimir Zapolskiy hblank = mode->hts - mode->width; 981*7d402666SVladimir Zapolskiy __v4l2_ctrl_modify_range(s5k3m5->hblank, hblank, hblank, 1, hblank); 982*7d402666SVladimir Zapolskiy 983*7d402666SVladimir Zapolskiy vblank = mode->vts - mode->height; 984*7d402666SVladimir Zapolskiy __v4l2_ctrl_modify_range(s5k3m5->vblank, vblank, 985*7d402666SVladimir Zapolskiy S5K3M5_VTS_MAX - mode->height, 1, vblank); 986*7d402666SVladimir Zapolskiy __v4l2_ctrl_s_ctrl(s5k3m5->vblank, vblank); 987*7d402666SVladimir Zapolskiy 988*7d402666SVladimir Zapolskiy exposure_max = mode->vts - S5K3M5_EXPOSURE_MARGIN; 989*7d402666SVladimir Zapolskiy __v4l2_ctrl_modify_range(s5k3m5->exposure, S5K3M5_EXPOSURE_MIN, 990*7d402666SVladimir Zapolskiy exposure_max, S5K3M5_EXPOSURE_STEP, 991*7d402666SVladimir Zapolskiy mode->exposure); 992*7d402666SVladimir Zapolskiy __v4l2_ctrl_s_ctrl(s5k3m5->exposure, mode->exposure); 993*7d402666SVladimir Zapolskiy 994*7d402666SVladimir Zapolskiy if (s5k3m5->sd.ctrl_handler->error) 995*7d402666SVladimir Zapolskiy return s5k3m5->sd.ctrl_handler->error; 996*7d402666SVladimir Zapolskiy 997*7d402666SVladimir Zapolskiy s5k3m5->mode = mode; 998*7d402666SVladimir Zapolskiy 999*7d402666SVladimir Zapolskiy set_format: 1000*7d402666SVladimir Zapolskiy *v4l2_subdev_state_get_format(state, 0) = fmt->format; 1001*7d402666SVladimir Zapolskiy 1002*7d402666SVladimir Zapolskiy return 0; 1003*7d402666SVladimir Zapolskiy } 1004*7d402666SVladimir Zapolskiy 1005*7d402666SVladimir Zapolskiy static int s5k3m5_enum_mbus_code(struct v4l2_subdev *sd, 1006*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *sd_state, 1007*7d402666SVladimir Zapolskiy struct v4l2_subdev_mbus_code_enum *code) 1008*7d402666SVladimir Zapolskiy { 1009*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1010*7d402666SVladimir Zapolskiy 1011*7d402666SVladimir Zapolskiy /* Media bus code index is constant, but code formats are not */ 1012*7d402666SVladimir Zapolskiy if (code->index > 0) 1013*7d402666SVladimir Zapolskiy return -EINVAL; 1014*7d402666SVladimir Zapolskiy 1015*7d402666SVladimir Zapolskiy code->code = s5k3m5_get_format_code(s5k3m5); 1016*7d402666SVladimir Zapolskiy 1017*7d402666SVladimir Zapolskiy return 0; 1018*7d402666SVladimir Zapolskiy } 1019*7d402666SVladimir Zapolskiy 1020*7d402666SVladimir Zapolskiy static int s5k3m5_enum_frame_size(struct v4l2_subdev *sd, 1021*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *sd_state, 1022*7d402666SVladimir Zapolskiy struct v4l2_subdev_frame_size_enum *fse) 1023*7d402666SVladimir Zapolskiy { 1024*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1025*7d402666SVladimir Zapolskiy 1026*7d402666SVladimir Zapolskiy if (fse->index >= ARRAY_SIZE(s5k3m5_supported_modes)) 1027*7d402666SVladimir Zapolskiy return -EINVAL; 1028*7d402666SVladimir Zapolskiy 1029*7d402666SVladimir Zapolskiy if (fse->code != s5k3m5_get_format_code(s5k3m5)) 1030*7d402666SVladimir Zapolskiy return -EINVAL; 1031*7d402666SVladimir Zapolskiy 1032*7d402666SVladimir Zapolskiy fse->min_width = s5k3m5_supported_modes[fse->index].width; 1033*7d402666SVladimir Zapolskiy fse->max_width = fse->min_width; 1034*7d402666SVladimir Zapolskiy fse->min_height = s5k3m5_supported_modes[fse->index].height; 1035*7d402666SVladimir Zapolskiy fse->max_height = fse->min_height; 1036*7d402666SVladimir Zapolskiy 1037*7d402666SVladimir Zapolskiy return 0; 1038*7d402666SVladimir Zapolskiy } 1039*7d402666SVladimir Zapolskiy 1040*7d402666SVladimir Zapolskiy static int s5k3m5_get_selection(struct v4l2_subdev *sd, 1041*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *sd_state, 1042*7d402666SVladimir Zapolskiy struct v4l2_subdev_selection *sel) 1043*7d402666SVladimir Zapolskiy { 1044*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1045*7d402666SVladimir Zapolskiy 1046*7d402666SVladimir Zapolskiy if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 1047*7d402666SVladimir Zapolskiy return -EINVAL; 1048*7d402666SVladimir Zapolskiy 1049*7d402666SVladimir Zapolskiy switch (sel->target) { 1050*7d402666SVladimir Zapolskiy case V4L2_SEL_TGT_CROP: 1051*7d402666SVladimir Zapolskiy case V4L2_SEL_TGT_CROP_BOUNDS: 1052*7d402666SVladimir Zapolskiy sel->r.left = 0; 1053*7d402666SVladimir Zapolskiy sel->r.top = 0; 1054*7d402666SVladimir Zapolskiy sel->r.width = s5k3m5->mode->width; 1055*7d402666SVladimir Zapolskiy sel->r.height = s5k3m5->mode->width; 1056*7d402666SVladimir Zapolskiy return 0; 1057*7d402666SVladimir Zapolskiy default: 1058*7d402666SVladimir Zapolskiy return -EINVAL; 1059*7d402666SVladimir Zapolskiy } 1060*7d402666SVladimir Zapolskiy 1061*7d402666SVladimir Zapolskiy return 0; 1062*7d402666SVladimir Zapolskiy } 1063*7d402666SVladimir Zapolskiy 1064*7d402666SVladimir Zapolskiy static int s5k3m5_init_state(struct v4l2_subdev *sd, 1065*7d402666SVladimir Zapolskiy struct v4l2_subdev_state *state) 1066*7d402666SVladimir Zapolskiy { 1067*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1068*7d402666SVladimir Zapolskiy struct v4l2_subdev_format fmt = { 1069*7d402666SVladimir Zapolskiy .which = V4L2_SUBDEV_FORMAT_TRY, 1070*7d402666SVladimir Zapolskiy .pad = 0, 1071*7d402666SVladimir Zapolskiy .format = { 1072*7d402666SVladimir Zapolskiy /* Media bus code depends on current flip controls */ 1073*7d402666SVladimir Zapolskiy .width = s5k3m5->mode->width, 1074*7d402666SVladimir Zapolskiy .height = s5k3m5->mode->height, 1075*7d402666SVladimir Zapolskiy }, 1076*7d402666SVladimir Zapolskiy }; 1077*7d402666SVladimir Zapolskiy 1078*7d402666SVladimir Zapolskiy s5k3m5_set_pad_format(sd, state, &fmt); 1079*7d402666SVladimir Zapolskiy 1080*7d402666SVladimir Zapolskiy return 0; 1081*7d402666SVladimir Zapolskiy } 1082*7d402666SVladimir Zapolskiy 1083*7d402666SVladimir Zapolskiy static const struct v4l2_subdev_video_ops s5k3m5_video_ops = { 1084*7d402666SVladimir Zapolskiy .s_stream = v4l2_subdev_s_stream_helper, 1085*7d402666SVladimir Zapolskiy }; 1086*7d402666SVladimir Zapolskiy 1087*7d402666SVladimir Zapolskiy static const struct v4l2_subdev_pad_ops s5k3m5_pad_ops = { 1088*7d402666SVladimir Zapolskiy .set_fmt = s5k3m5_set_pad_format, 1089*7d402666SVladimir Zapolskiy .get_fmt = v4l2_subdev_get_fmt, 1090*7d402666SVladimir Zapolskiy .get_selection = s5k3m5_get_selection, 1091*7d402666SVladimir Zapolskiy .enum_mbus_code = s5k3m5_enum_mbus_code, 1092*7d402666SVladimir Zapolskiy .enum_frame_size = s5k3m5_enum_frame_size, 1093*7d402666SVladimir Zapolskiy .enable_streams = s5k3m5_enable_streams, 1094*7d402666SVladimir Zapolskiy .disable_streams = s5k3m5_disable_streams, 1095*7d402666SVladimir Zapolskiy }; 1096*7d402666SVladimir Zapolskiy 1097*7d402666SVladimir Zapolskiy static const struct v4l2_subdev_ops s5k3m5_subdev_ops = { 1098*7d402666SVladimir Zapolskiy .video = &s5k3m5_video_ops, 1099*7d402666SVladimir Zapolskiy .pad = &s5k3m5_pad_ops, 1100*7d402666SVladimir Zapolskiy }; 1101*7d402666SVladimir Zapolskiy 1102*7d402666SVladimir Zapolskiy static const struct v4l2_subdev_internal_ops s5k3m5_internal_ops = { 1103*7d402666SVladimir Zapolskiy .init_state = s5k3m5_init_state, 1104*7d402666SVladimir Zapolskiy }; 1105*7d402666SVladimir Zapolskiy 1106*7d402666SVladimir Zapolskiy static const struct media_entity_operations s5k3m5_subdev_entity_ops = { 1107*7d402666SVladimir Zapolskiy .link_validate = v4l2_subdev_link_validate, 1108*7d402666SVladimir Zapolskiy }; 1109*7d402666SVladimir Zapolskiy 1110*7d402666SVladimir Zapolskiy static int s5k3m5_identify_sensor(struct s5k3m5 *s5k3m5) 1111*7d402666SVladimir Zapolskiy { 1112*7d402666SVladimir Zapolskiy u64 val; 1113*7d402666SVladimir Zapolskiy int ret; 1114*7d402666SVladimir Zapolskiy 1115*7d402666SVladimir Zapolskiy ret = cci_read(s5k3m5->regmap, S5K3M5_REG_CHIP_ID, &val, NULL); 1116*7d402666SVladimir Zapolskiy if (ret) { 1117*7d402666SVladimir Zapolskiy dev_err(s5k3m5->dev, "failed to read chip id: %d\n", ret); 1118*7d402666SVladimir Zapolskiy return ret; 1119*7d402666SVladimir Zapolskiy } 1120*7d402666SVladimir Zapolskiy 1121*7d402666SVladimir Zapolskiy if (val != S5K3M5_CHIP_ID) { 1122*7d402666SVladimir Zapolskiy dev_err(s5k3m5->dev, "chip id mismatch: %x!=%llx\n", 1123*7d402666SVladimir Zapolskiy S5K3M5_CHIP_ID, val); 1124*7d402666SVladimir Zapolskiy return -ENODEV; 1125*7d402666SVladimir Zapolskiy } 1126*7d402666SVladimir Zapolskiy 1127*7d402666SVladimir Zapolskiy return 0; 1128*7d402666SVladimir Zapolskiy } 1129*7d402666SVladimir Zapolskiy 1130*7d402666SVladimir Zapolskiy static int s5k3m5_check_hwcfg(struct s5k3m5 *s5k3m5) 1131*7d402666SVladimir Zapolskiy { 1132*7d402666SVladimir Zapolskiy struct fwnode_handle *fwnode = dev_fwnode(s5k3m5->dev), *ep; 1133*7d402666SVladimir Zapolskiy struct v4l2_fwnode_endpoint bus_cfg = { 1134*7d402666SVladimir Zapolskiy .bus = { 1135*7d402666SVladimir Zapolskiy .mipi_csi2 = { 1136*7d402666SVladimir Zapolskiy .num_data_lanes = S5K3M5_DATA_LANES, 1137*7d402666SVladimir Zapolskiy }, 1138*7d402666SVladimir Zapolskiy }, 1139*7d402666SVladimir Zapolskiy .bus_type = V4L2_MBUS_CSI2_DPHY, 1140*7d402666SVladimir Zapolskiy }; 1141*7d402666SVladimir Zapolskiy unsigned long freq_bitmap; 1142*7d402666SVladimir Zapolskiy int ret; 1143*7d402666SVladimir Zapolskiy 1144*7d402666SVladimir Zapolskiy if (!fwnode) 1145*7d402666SVladimir Zapolskiy return -ENODEV; 1146*7d402666SVladimir Zapolskiy 1147*7d402666SVladimir Zapolskiy ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 1148*7d402666SVladimir Zapolskiy if (!ep) 1149*7d402666SVladimir Zapolskiy return -EINVAL; 1150*7d402666SVladimir Zapolskiy 1151*7d402666SVladimir Zapolskiy ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 1152*7d402666SVladimir Zapolskiy fwnode_handle_put(ep); 1153*7d402666SVladimir Zapolskiy if (ret) 1154*7d402666SVladimir Zapolskiy return ret; 1155*7d402666SVladimir Zapolskiy 1156*7d402666SVladimir Zapolskiy if (bus_cfg.bus.mipi_csi2.num_data_lanes != S5K3M5_DATA_LANES) { 1157*7d402666SVladimir Zapolskiy dev_err(s5k3m5->dev, "Invalid number of data lanes: %u\n", 1158*7d402666SVladimir Zapolskiy bus_cfg.bus.mipi_csi2.num_data_lanes); 1159*7d402666SVladimir Zapolskiy ret = -EINVAL; 1160*7d402666SVladimir Zapolskiy goto endpoint_free; 1161*7d402666SVladimir Zapolskiy } 1162*7d402666SVladimir Zapolskiy 1163*7d402666SVladimir Zapolskiy ret = v4l2_link_freq_to_bitmap(s5k3m5->dev, bus_cfg.link_frequencies, 1164*7d402666SVladimir Zapolskiy bus_cfg.nr_of_link_frequencies, 1165*7d402666SVladimir Zapolskiy s5k3m5_link_freq_menu, 1166*7d402666SVladimir Zapolskiy ARRAY_SIZE(s5k3m5_link_freq_menu), 1167*7d402666SVladimir Zapolskiy &freq_bitmap); 1168*7d402666SVladimir Zapolskiy 1169*7d402666SVladimir Zapolskiy endpoint_free: 1170*7d402666SVladimir Zapolskiy v4l2_fwnode_endpoint_free(&bus_cfg); 1171*7d402666SVladimir Zapolskiy 1172*7d402666SVladimir Zapolskiy return ret; 1173*7d402666SVladimir Zapolskiy } 1174*7d402666SVladimir Zapolskiy 1175*7d402666SVladimir Zapolskiy static int s5k3m5_power_on(struct device *dev) 1176*7d402666SVladimir Zapolskiy { 1177*7d402666SVladimir Zapolskiy struct v4l2_subdev *sd = dev_get_drvdata(dev); 1178*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1179*7d402666SVladimir Zapolskiy int ret; 1180*7d402666SVladimir Zapolskiy 1181*7d402666SVladimir Zapolskiy ret = regulator_bulk_enable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies); 1182*7d402666SVladimir Zapolskiy if (ret) 1183*7d402666SVladimir Zapolskiy return ret; 1184*7d402666SVladimir Zapolskiy 1185*7d402666SVladimir Zapolskiy ret = clk_prepare_enable(s5k3m5->mclk); 1186*7d402666SVladimir Zapolskiy if (ret) 1187*7d402666SVladimir Zapolskiy goto disable_regulators; 1188*7d402666SVladimir Zapolskiy 1189*7d402666SVladimir Zapolskiy gpiod_set_value_cansleep(s5k3m5->reset_gpio, 0); 1190*7d402666SVladimir Zapolskiy usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC); 1191*7d402666SVladimir Zapolskiy 1192*7d402666SVladimir Zapolskiy return 0; 1193*7d402666SVladimir Zapolskiy 1194*7d402666SVladimir Zapolskiy disable_regulators: 1195*7d402666SVladimir Zapolskiy regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies); 1196*7d402666SVladimir Zapolskiy 1197*7d402666SVladimir Zapolskiy return ret; 1198*7d402666SVladimir Zapolskiy } 1199*7d402666SVladimir Zapolskiy 1200*7d402666SVladimir Zapolskiy static int s5k3m5_power_off(struct device *dev) 1201*7d402666SVladimir Zapolskiy { 1202*7d402666SVladimir Zapolskiy struct v4l2_subdev *sd = dev_get_drvdata(dev); 1203*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1204*7d402666SVladimir Zapolskiy 1205*7d402666SVladimir Zapolskiy gpiod_set_value_cansleep(s5k3m5->reset_gpio, 1); 1206*7d402666SVladimir Zapolskiy 1207*7d402666SVladimir Zapolskiy clk_disable_unprepare(s5k3m5->mclk); 1208*7d402666SVladimir Zapolskiy 1209*7d402666SVladimir Zapolskiy regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies); 1210*7d402666SVladimir Zapolskiy 1211*7d402666SVladimir Zapolskiy return 0; 1212*7d402666SVladimir Zapolskiy } 1213*7d402666SVladimir Zapolskiy 1214*7d402666SVladimir Zapolskiy static int s5k3m5_probe(struct i2c_client *client) 1215*7d402666SVladimir Zapolskiy { 1216*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5; 1217*7d402666SVladimir Zapolskiy unsigned long freq; 1218*7d402666SVladimir Zapolskiy unsigned int i; 1219*7d402666SVladimir Zapolskiy int ret; 1220*7d402666SVladimir Zapolskiy 1221*7d402666SVladimir Zapolskiy s5k3m5 = devm_kzalloc(&client->dev, sizeof(*s5k3m5), GFP_KERNEL); 1222*7d402666SVladimir Zapolskiy if (!s5k3m5) 1223*7d402666SVladimir Zapolskiy return -ENOMEM; 1224*7d402666SVladimir Zapolskiy 1225*7d402666SVladimir Zapolskiy s5k3m5->dev = &client->dev; 1226*7d402666SVladimir Zapolskiy v4l2_i2c_subdev_init(&s5k3m5->sd, client, &s5k3m5_subdev_ops); 1227*7d402666SVladimir Zapolskiy 1228*7d402666SVladimir Zapolskiy s5k3m5->regmap = devm_cci_regmap_init_i2c(client, 16); 1229*7d402666SVladimir Zapolskiy if (IS_ERR(s5k3m5->regmap)) 1230*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->regmap), 1231*7d402666SVladimir Zapolskiy "failed to init CCI\n"); 1232*7d402666SVladimir Zapolskiy 1233*7d402666SVladimir Zapolskiy s5k3m5->mclk = devm_v4l2_sensor_clk_get(s5k3m5->dev, NULL); 1234*7d402666SVladimir Zapolskiy if (IS_ERR(s5k3m5->mclk)) 1235*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->mclk), 1236*7d402666SVladimir Zapolskiy "failed to get MCLK clock\n"); 1237*7d402666SVladimir Zapolskiy 1238*7d402666SVladimir Zapolskiy freq = clk_get_rate(s5k3m5->mclk); 1239*7d402666SVladimir Zapolskiy if (freq != S5K3M5_MCLK_FREQ_24MHZ) 1240*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, -EINVAL, 1241*7d402666SVladimir Zapolskiy "MCLK clock frequency %lu is not supported\n", 1242*7d402666SVladimir Zapolskiy freq); 1243*7d402666SVladimir Zapolskiy 1244*7d402666SVladimir Zapolskiy ret = s5k3m5_check_hwcfg(s5k3m5); 1245*7d402666SVladimir Zapolskiy if (ret) 1246*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, ret, 1247*7d402666SVladimir Zapolskiy "failed to check HW configuration\n"); 1248*7d402666SVladimir Zapolskiy 1249*7d402666SVladimir Zapolskiy s5k3m5->reset_gpio = devm_gpiod_get_optional(s5k3m5->dev, "reset", 1250*7d402666SVladimir Zapolskiy GPIOD_OUT_HIGH); 1251*7d402666SVladimir Zapolskiy if (IS_ERR(s5k3m5->reset_gpio)) 1252*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->reset_gpio), 1253*7d402666SVladimir Zapolskiy "cannot get reset GPIO\n"); 1254*7d402666SVladimir Zapolskiy 1255*7d402666SVladimir Zapolskiy for (i = 0; i < S5K3M5_NUM_SUPPLIES; i++) 1256*7d402666SVladimir Zapolskiy s5k3m5->supplies[i].supply = s5k3m5_supply_names[i]; 1257*7d402666SVladimir Zapolskiy 1258*7d402666SVladimir Zapolskiy ret = devm_regulator_bulk_get(s5k3m5->dev, S5K3M5_NUM_SUPPLIES, 1259*7d402666SVladimir Zapolskiy s5k3m5->supplies); 1260*7d402666SVladimir Zapolskiy if (ret) 1261*7d402666SVladimir Zapolskiy return dev_err_probe(s5k3m5->dev, ret, 1262*7d402666SVladimir Zapolskiy "failed to get supply regulators\n"); 1263*7d402666SVladimir Zapolskiy 1264*7d402666SVladimir Zapolskiy /* The sensor must be powered on to read the CHIP_ID register */ 1265*7d402666SVladimir Zapolskiy ret = s5k3m5_power_on(s5k3m5->dev); 1266*7d402666SVladimir Zapolskiy if (ret) 1267*7d402666SVladimir Zapolskiy return ret; 1268*7d402666SVladimir Zapolskiy 1269*7d402666SVladimir Zapolskiy ret = s5k3m5_identify_sensor(s5k3m5); 1270*7d402666SVladimir Zapolskiy if (ret) { 1271*7d402666SVladimir Zapolskiy dev_err_probe(s5k3m5->dev, ret, "failed to find sensor\n"); 1272*7d402666SVladimir Zapolskiy goto power_off; 1273*7d402666SVladimir Zapolskiy } 1274*7d402666SVladimir Zapolskiy 1275*7d402666SVladimir Zapolskiy s5k3m5->mode = &s5k3m5_supported_modes[0]; 1276*7d402666SVladimir Zapolskiy ret = s5k3m5_init_controls(s5k3m5); 1277*7d402666SVladimir Zapolskiy if (ret) { 1278*7d402666SVladimir Zapolskiy dev_err_probe(s5k3m5->dev, ret, "failed to init controls\n"); 1279*7d402666SVladimir Zapolskiy goto power_off; 1280*7d402666SVladimir Zapolskiy } 1281*7d402666SVladimir Zapolskiy 1282*7d402666SVladimir Zapolskiy s5k3m5->sd.state_lock = s5k3m5->ctrl_handler.lock; 1283*7d402666SVladimir Zapolskiy s5k3m5->sd.internal_ops = &s5k3m5_internal_ops; 1284*7d402666SVladimir Zapolskiy s5k3m5->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1285*7d402666SVladimir Zapolskiy s5k3m5->sd.entity.ops = &s5k3m5_subdev_entity_ops; 1286*7d402666SVladimir Zapolskiy s5k3m5->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1287*7d402666SVladimir Zapolskiy s5k3m5->pad.flags = MEDIA_PAD_FL_SOURCE; 1288*7d402666SVladimir Zapolskiy 1289*7d402666SVladimir Zapolskiy ret = media_entity_pads_init(&s5k3m5->sd.entity, 1, &s5k3m5->pad); 1290*7d402666SVladimir Zapolskiy if (ret) { 1291*7d402666SVladimir Zapolskiy dev_err_probe(s5k3m5->dev, ret, 1292*7d402666SVladimir Zapolskiy "failed to init media entity pads\n"); 1293*7d402666SVladimir Zapolskiy goto v4l2_ctrl_handler_free; 1294*7d402666SVladimir Zapolskiy } 1295*7d402666SVladimir Zapolskiy 1296*7d402666SVladimir Zapolskiy ret = v4l2_subdev_init_finalize(&s5k3m5->sd); 1297*7d402666SVladimir Zapolskiy if (ret < 0) { 1298*7d402666SVladimir Zapolskiy dev_err_probe(s5k3m5->dev, ret, 1299*7d402666SVladimir Zapolskiy "failed to init media entity pads\n"); 1300*7d402666SVladimir Zapolskiy goto media_entity_cleanup; 1301*7d402666SVladimir Zapolskiy } 1302*7d402666SVladimir Zapolskiy 1303*7d402666SVladimir Zapolskiy pm_runtime_set_active(s5k3m5->dev); 1304*7d402666SVladimir Zapolskiy pm_runtime_enable(s5k3m5->dev); 1305*7d402666SVladimir Zapolskiy 1306*7d402666SVladimir Zapolskiy ret = v4l2_async_register_subdev_sensor(&s5k3m5->sd); 1307*7d402666SVladimir Zapolskiy if (ret < 0) { 1308*7d402666SVladimir Zapolskiy dev_err_probe(s5k3m5->dev, ret, 1309*7d402666SVladimir Zapolskiy "failed to register V4L2 subdev\n"); 1310*7d402666SVladimir Zapolskiy goto subdev_cleanup; 1311*7d402666SVladimir Zapolskiy } 1312*7d402666SVladimir Zapolskiy 1313*7d402666SVladimir Zapolskiy pm_runtime_set_autosuspend_delay(s5k3m5->dev, 1000); 1314*7d402666SVladimir Zapolskiy pm_runtime_use_autosuspend(s5k3m5->dev); 1315*7d402666SVladimir Zapolskiy pm_runtime_idle(s5k3m5->dev); 1316*7d402666SVladimir Zapolskiy 1317*7d402666SVladimir Zapolskiy return 0; 1318*7d402666SVladimir Zapolskiy 1319*7d402666SVladimir Zapolskiy subdev_cleanup: 1320*7d402666SVladimir Zapolskiy v4l2_subdev_cleanup(&s5k3m5->sd); 1321*7d402666SVladimir Zapolskiy pm_runtime_disable(s5k3m5->dev); 1322*7d402666SVladimir Zapolskiy pm_runtime_set_suspended(s5k3m5->dev); 1323*7d402666SVladimir Zapolskiy 1324*7d402666SVladimir Zapolskiy media_entity_cleanup: 1325*7d402666SVladimir Zapolskiy media_entity_cleanup(&s5k3m5->sd.entity); 1326*7d402666SVladimir Zapolskiy 1327*7d402666SVladimir Zapolskiy v4l2_ctrl_handler_free: 1328*7d402666SVladimir Zapolskiy v4l2_ctrl_handler_free(s5k3m5->sd.ctrl_handler); 1329*7d402666SVladimir Zapolskiy 1330*7d402666SVladimir Zapolskiy power_off: 1331*7d402666SVladimir Zapolskiy s5k3m5_power_off(s5k3m5->dev); 1332*7d402666SVladimir Zapolskiy 1333*7d402666SVladimir Zapolskiy return ret; 1334*7d402666SVladimir Zapolskiy } 1335*7d402666SVladimir Zapolskiy 1336*7d402666SVladimir Zapolskiy static void s5k3m5_remove(struct i2c_client *client) 1337*7d402666SVladimir Zapolskiy { 1338*7d402666SVladimir Zapolskiy struct v4l2_subdev *sd = i2c_get_clientdata(client); 1339*7d402666SVladimir Zapolskiy struct s5k3m5 *s5k3m5 = to_s5k3m5(sd); 1340*7d402666SVladimir Zapolskiy 1341*7d402666SVladimir Zapolskiy v4l2_async_unregister_subdev(sd); 1342*7d402666SVladimir Zapolskiy v4l2_subdev_cleanup(sd); 1343*7d402666SVladimir Zapolskiy media_entity_cleanup(&sd->entity); 1344*7d402666SVladimir Zapolskiy v4l2_ctrl_handler_free(sd->ctrl_handler); 1345*7d402666SVladimir Zapolskiy pm_runtime_disable(s5k3m5->dev); 1346*7d402666SVladimir Zapolskiy 1347*7d402666SVladimir Zapolskiy if (!pm_runtime_status_suspended(s5k3m5->dev)) { 1348*7d402666SVladimir Zapolskiy s5k3m5_power_off(s5k3m5->dev); 1349*7d402666SVladimir Zapolskiy pm_runtime_set_suspended(s5k3m5->dev); 1350*7d402666SVladimir Zapolskiy } 1351*7d402666SVladimir Zapolskiy } 1352*7d402666SVladimir Zapolskiy 1353*7d402666SVladimir Zapolskiy static const struct dev_pm_ops s5k3m5_pm_ops = { 1354*7d402666SVladimir Zapolskiy SET_RUNTIME_PM_OPS(s5k3m5_power_off, s5k3m5_power_on, NULL) 1355*7d402666SVladimir Zapolskiy }; 1356*7d402666SVladimir Zapolskiy 1357*7d402666SVladimir Zapolskiy static const struct of_device_id s5k3m5_of_match[] = { 1358*7d402666SVladimir Zapolskiy { .compatible = "samsung,s5k3m5" }, 1359*7d402666SVladimir Zapolskiy { /* sentinel */ } 1360*7d402666SVladimir Zapolskiy }; 1361*7d402666SVladimir Zapolskiy MODULE_DEVICE_TABLE(of, s5k3m5_of_match); 1362*7d402666SVladimir Zapolskiy 1363*7d402666SVladimir Zapolskiy static struct i2c_driver s5k3m5_i2c_driver = { 1364*7d402666SVladimir Zapolskiy .driver = { 1365*7d402666SVladimir Zapolskiy .name = "s5k3m5", 1366*7d402666SVladimir Zapolskiy .pm = &s5k3m5_pm_ops, 1367*7d402666SVladimir Zapolskiy .of_match_table = s5k3m5_of_match, 1368*7d402666SVladimir Zapolskiy }, 1369*7d402666SVladimir Zapolskiy .probe = s5k3m5_probe, 1370*7d402666SVladimir Zapolskiy .remove = s5k3m5_remove, 1371*7d402666SVladimir Zapolskiy }; 1372*7d402666SVladimir Zapolskiy 1373*7d402666SVladimir Zapolskiy module_i2c_driver(s5k3m5_i2c_driver); 1374*7d402666SVladimir Zapolskiy 1375*7d402666SVladimir Zapolskiy MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); 1376*7d402666SVladimir Zapolskiy MODULE_DESCRIPTION("Samsung S5K3M5 image sensor driver"); 1377*7d402666SVladimir Zapolskiy MODULE_LICENSE("GPL"); 1378