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