1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * V4L2 Support for the os05b10 4 * 5 * Copyright (C) 2025 Silicon Signals Pvt. Ltd. 6 * 7 * Inspired from imx219, ov2735 camera drivers. 8 */ 9 10 #include <linux/array_size.h> 11 #include <linux/bitops.h> 12 #include <linux/clk.h> 13 #include <linux/container_of.h> 14 #include <linux/delay.h> 15 #include <linux/device/devres.h> 16 #include <linux/err.h> 17 #include <linux/gpio/consumer.h> 18 #include <linux/i2c.h> 19 #include <linux/module.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/regulator/consumer.h> 22 #include <linux/types.h> 23 #include <linux/time.h> 24 #include <linux/units.h> 25 26 #include <media/v4l2-cci.h> 27 #include <media/v4l2-ctrls.h> 28 #include <media/v4l2-device.h> 29 #include <media/v4l2-fwnode.h> 30 #include <media/v4l2-mediabus.h> 31 32 #define OS05B10_XCLK_FREQ (24 * HZ_PER_MHZ) 33 34 #define OS05B10_REG_CHIP_ID CCI_REG24(0x300a) 35 #define OS05B10_CHIP_ID 0x530641 36 37 #define OS05B10_REG_CTRL_MODE CCI_REG8(0x0100) 38 #define OS05B10_MODE_STANDBY 0x00 39 #define OS05B10_MODE_STREAMING 0x01 40 41 #define OS05B10_REG_EXPOSURE CCI_REG24(0x3500) 42 #define OS05B10_EXPOSURE_MIN 2 43 #define OS05B10_EXPOSURE_STEP 1 44 #define OS05B10_EXPOSURE_MARGIN 8 45 46 #define OS05B10_REG_ANALOG_GAIN CCI_REG16(0x3508) 47 #define OS05B10_ANALOG_GAIN_MIN 0x80 48 #define OS05B10_ANALOG_GAIN_MAX 0x7C0 49 #define OS05B10_ANALOG_GAIN_STEP 1 50 #define OS05B10_ANALOG_GAIN_DEFAULT 0x80 51 52 #define OS05B10_REG_HTS CCI_REG16(0x380c) 53 54 #define OS05B10_REG_VTS CCI_REG16(0x380e) 55 #define OS05B10_VTS_MAX 0x7fff 56 57 #define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ) 58 59 static const struct v4l2_rect os05b10_native_area = { 60 .top = 0, 61 .left = 0, 62 .width = 2608, 63 .height = 1960, 64 }; 65 66 static const struct v4l2_rect os05b10_active_area = { 67 .top = 8, 68 .left = 8, 69 .width = 2592, 70 .height = 1944, 71 }; 72 73 static const char * const os05b10_supply_name[] = { 74 "avdd", /* Analog supply */ 75 "dovdd", /* Digital IO */ 76 "dvdd", /* Digital core */ 77 }; 78 79 static const struct cci_reg_sequence os05b10_common_regs[] = { 80 { CCI_REG8(0x0301), 0x44 }, 81 { CCI_REG8(0x0303), 0x02 }, 82 { CCI_REG8(0x0305), 0x32 }, 83 { CCI_REG8(0x0306), 0x00 }, 84 { CCI_REG8(0x0325), 0x3b }, 85 { CCI_REG8(0x3002), 0x21 }, 86 { CCI_REG8(0x3016), 0x72 }, 87 { CCI_REG8(0x301e), 0xb4 }, 88 { CCI_REG8(0x301f), 0xd0 }, 89 { CCI_REG8(0x3021), 0x03 }, 90 { CCI_REG8(0x3022), 0x01 }, 91 { CCI_REG8(0x3107), 0xa1 }, 92 { CCI_REG8(0x3108), 0x7d }, 93 { CCI_REG8(0x3109), 0xfc }, 94 { CCI_REG8(0x3503), 0x88 }, 95 { CCI_REG8(0x350a), 0x04 }, 96 { CCI_REG8(0x350b), 0x00 }, 97 { CCI_REG8(0x350c), 0x00 }, 98 { CCI_REG8(0x350d), 0x80 }, 99 { CCI_REG8(0x350e), 0x04 }, 100 { CCI_REG8(0x350f), 0x00 }, 101 { CCI_REG8(0x3510), 0x00 }, 102 { CCI_REG8(0x3511), 0x00 }, 103 { CCI_REG8(0x3512), 0x20 }, 104 { CCI_REG8(0x3600), 0x4d }, 105 { CCI_REG8(0x3601), 0x08 }, 106 { CCI_REG8(0x3610), 0x87 }, 107 { CCI_REG8(0x3611), 0x24 }, 108 { CCI_REG8(0x3614), 0x4c }, 109 { CCI_REG8(0x3620), 0x0c }, 110 { CCI_REG8(0x3632), 0x80 }, 111 { CCI_REG8(0x3633), 0x00 }, 112 { CCI_REG8(0x3636), 0xcc }, 113 { CCI_REG8(0x3637), 0x27 }, 114 { CCI_REG8(0x3660), 0x00 }, 115 { CCI_REG8(0x3662), 0x10 }, 116 { CCI_REG8(0x3665), 0x00 }, 117 { CCI_REG8(0x3666), 0x00 }, 118 { CCI_REG8(0x366a), 0x14 }, 119 { CCI_REG8(0x3670), 0x0b }, 120 { CCI_REG8(0x3671), 0x0b }, 121 { CCI_REG8(0x3672), 0x0b }, 122 { CCI_REG8(0x3673), 0x0b }, 123 { CCI_REG8(0x3678), 0x2b }, 124 { CCI_REG8(0x367a), 0x11 }, 125 { CCI_REG8(0x367b), 0x11 }, 126 { CCI_REG8(0x367c), 0x11 }, 127 { CCI_REG8(0x367d), 0x11 }, 128 { CCI_REG8(0x3681), 0xff }, 129 { CCI_REG8(0x3682), 0x86 }, 130 { CCI_REG8(0x3683), 0x44 }, 131 { CCI_REG8(0x3684), 0x24 }, 132 { CCI_REG8(0x3685), 0x00 }, 133 { CCI_REG8(0x368a), 0x00 }, 134 { CCI_REG8(0x368d), 0x2b }, 135 { CCI_REG8(0x368e), 0x2b }, 136 { CCI_REG8(0x3690), 0x00 }, 137 { CCI_REG8(0x3691), 0x0b }, 138 { CCI_REG8(0x3692), 0x0b }, 139 { CCI_REG8(0x3693), 0x0b }, 140 { CCI_REG8(0x3694), 0x0b }, 141 { CCI_REG8(0x369d), 0x68 }, 142 { CCI_REG8(0x369e), 0x34 }, 143 { CCI_REG8(0x369f), 0x1b }, 144 { CCI_REG8(0x36a0), 0x0f }, 145 { CCI_REG8(0x36a1), 0x77 }, 146 { CCI_REG8(0x36b0), 0x30 }, 147 { CCI_REG8(0x36b2), 0x00 }, 148 { CCI_REG8(0x36b3), 0x00 }, 149 { CCI_REG8(0x36b4), 0x00 }, 150 { CCI_REG8(0x36b5), 0x00 }, 151 { CCI_REG8(0x36b6), 0x00 }, 152 { CCI_REG8(0x36b7), 0x00 }, 153 { CCI_REG8(0x36b8), 0x00 }, 154 { CCI_REG8(0x36b9), 0x00 }, 155 { CCI_REG8(0x36ba), 0x00 }, 156 { CCI_REG8(0x36bb), 0x00 }, 157 { CCI_REG8(0x36bc), 0x00 }, 158 { CCI_REG8(0x36bd), 0x00 }, 159 { CCI_REG8(0x36be), 0x00 }, 160 { CCI_REG8(0x36bf), 0x00 }, 161 { CCI_REG8(0x36c0), 0x01 }, 162 { CCI_REG8(0x36c1), 0x00 }, 163 { CCI_REG8(0x36c2), 0x00 }, 164 { CCI_REG8(0x36c3), 0x00 }, 165 { CCI_REG8(0x36c4), 0x00 }, 166 { CCI_REG8(0x36c5), 0x00 }, 167 { CCI_REG8(0x36c6), 0x00 }, 168 { CCI_REG8(0x36c7), 0x00 }, 169 { CCI_REG8(0x36c8), 0x00 }, 170 { CCI_REG8(0x36c9), 0x00 }, 171 { CCI_REG8(0x36ca), 0x0e }, 172 { CCI_REG8(0x36cb), 0x0e }, 173 { CCI_REG8(0x36cc), 0x0e }, 174 { CCI_REG8(0x36cd), 0x0e }, 175 { CCI_REG8(0x36ce), 0x0c }, 176 { CCI_REG8(0x36cf), 0x0c }, 177 { CCI_REG8(0x36d0), 0x0c }, 178 { CCI_REG8(0x36d1), 0x0c }, 179 { CCI_REG8(0x36d2), 0x00 }, 180 { CCI_REG8(0x36d3), 0x08 }, 181 { CCI_REG8(0x36d4), 0x10 }, 182 { CCI_REG8(0x36d5), 0x10 }, 183 { CCI_REG8(0x36d6), 0x00 }, 184 { CCI_REG8(0x36d7), 0x08 }, 185 { CCI_REG8(0x36d8), 0x10 }, 186 { CCI_REG8(0x36d9), 0x10 }, 187 { CCI_REG8(0x3701), 0x1d }, 188 { CCI_REG8(0x3703), 0x2a }, 189 { CCI_REG8(0x3704), 0x05 }, 190 { CCI_REG8(0x3709), 0x57 }, 191 { CCI_REG8(0x370b), 0x63 }, 192 { CCI_REG8(0x3706), 0x28 }, 193 { CCI_REG8(0x370a), 0x00 }, 194 { CCI_REG8(0x370b), 0x63 }, 195 { CCI_REG8(0x370e), 0x0c }, 196 { CCI_REG8(0x370f), 0x1c }, 197 { CCI_REG8(0x3710), 0x00 }, 198 { CCI_REG8(0x3713), 0x00 }, 199 { CCI_REG8(0x3714), 0x24 }, 200 { CCI_REG8(0x3716), 0x24 }, 201 { CCI_REG8(0x371a), 0x1e }, 202 { CCI_REG8(0x3724), 0x09 }, 203 { CCI_REG8(0x3725), 0xb2 }, 204 { CCI_REG8(0x372b), 0x54 }, 205 { CCI_REG8(0x3730), 0xe1 }, 206 { CCI_REG8(0x3735), 0x80 }, 207 { CCI_REG8(0x3739), 0x10 }, 208 { CCI_REG8(0x373f), 0xb0 }, 209 { CCI_REG8(0x3740), 0x28 }, 210 { CCI_REG8(0x3741), 0x21 }, 211 { CCI_REG8(0x3742), 0x21 }, 212 { CCI_REG8(0x3743), 0x21 }, 213 { CCI_REG8(0x3744), 0x63 }, 214 { CCI_REG8(0x3745), 0x5a }, 215 { CCI_REG8(0x3746), 0x5a }, 216 { CCI_REG8(0x3747), 0x5a }, 217 { CCI_REG8(0x3748), 0x00 }, 218 { CCI_REG8(0x3749), 0x00 }, 219 { CCI_REG8(0x374a), 0x00 }, 220 { CCI_REG8(0x374b), 0x00 }, 221 { CCI_REG8(0x3756), 0x00 }, 222 { CCI_REG8(0x3757), 0x0e }, 223 { CCI_REG8(0x375d), 0x84 }, 224 { CCI_REG8(0x3760), 0x11 }, 225 { CCI_REG8(0x3767), 0x08 }, 226 { CCI_REG8(0x376f), 0x42 }, 227 { CCI_REG8(0x3771), 0x00 }, 228 { CCI_REG8(0x3773), 0x01 }, 229 { CCI_REG8(0x3774), 0x02 }, 230 { CCI_REG8(0x3775), 0x12 }, 231 { CCI_REG8(0x3776), 0x02 }, 232 { CCI_REG8(0x377b), 0x40 }, 233 { CCI_REG8(0x377c), 0x00 }, 234 { CCI_REG8(0x377d), 0x0c }, 235 { CCI_REG8(0x3782), 0x02 }, 236 { CCI_REG8(0x3787), 0x24 }, 237 { CCI_REG8(0x378a), 0x01 }, 238 { CCI_REG8(0x378d), 0x00 }, 239 { CCI_REG8(0x3790), 0x1f }, 240 { CCI_REG8(0x3791), 0x58 }, 241 { CCI_REG8(0x3795), 0x24 }, 242 { CCI_REG8(0x3796), 0x01 }, 243 { CCI_REG8(0x3798), 0x40 }, 244 { CCI_REG8(0x379c), 0x00 }, 245 { CCI_REG8(0x379d), 0x00 }, 246 { CCI_REG8(0x379e), 0x00 }, 247 { CCI_REG8(0x379f), 0x01 }, 248 { CCI_REG8(0x37a1), 0x10 }, 249 { CCI_REG8(0x37a6), 0x00 }, 250 { CCI_REG8(0x37ab), 0x0e }, 251 { CCI_REG8(0x37ac), 0xa0 }, 252 { CCI_REG8(0x37be), 0x0a }, 253 { CCI_REG8(0x37bf), 0x05 }, 254 { CCI_REG8(0x37bb), 0x02 }, 255 { CCI_REG8(0x37bf), 0x05 }, 256 { CCI_REG8(0x37c2), 0x04 }, 257 { CCI_REG8(0x37c4), 0x11 }, 258 { CCI_REG8(0x37c5), 0x80 }, 259 { CCI_REG8(0x37c6), 0x14 }, 260 { CCI_REG8(0x37c7), 0x08 }, 261 { CCI_REG8(0x37c8), 0x42 }, 262 { CCI_REG8(0x37cd), 0x17 }, 263 { CCI_REG8(0x37ce), 0x01 }, 264 { CCI_REG8(0x37d8), 0x02 }, 265 { CCI_REG8(0x37d9), 0x08 }, 266 { CCI_REG8(0x37dc), 0x01 }, 267 { CCI_REG8(0x37e0), 0x0c }, 268 { CCI_REG8(0x37e1), 0x20 }, 269 { CCI_REG8(0x37e2), 0x10 }, 270 { CCI_REG8(0x37e3), 0x04 }, 271 { CCI_REG8(0x37e4), 0x28 }, 272 { CCI_REG8(0x37e5), 0x02 }, 273 { CCI_REG8(0x37ef), 0x00 }, 274 { CCI_REG8(0x37f4), 0x00 }, 275 { CCI_REG8(0x37f5), 0x00 }, 276 { CCI_REG8(0x37f6), 0x00 }, 277 { CCI_REG8(0x37f7), 0x00 }, 278 { CCI_REG8(0x3800), 0x01 }, 279 { CCI_REG8(0x3801), 0x30 }, 280 { CCI_REG8(0x3802), 0x00 }, 281 { CCI_REG8(0x3803), 0x00 }, 282 { CCI_REG8(0x3804), 0x0b }, 283 { CCI_REG8(0x3805), 0x5f }, 284 { CCI_REG8(0x3806), 0x07 }, 285 { CCI_REG8(0x3807), 0xa7 }, 286 { CCI_REG8(0x3808), 0x0a }, 287 { CCI_REG8(0x3809), 0x20 }, 288 { CCI_REG8(0x380a), 0x07 }, 289 { CCI_REG8(0x380b), 0x98 }, 290 { CCI_REG8(0x380c), 0x06 }, 291 { CCI_REG8(0x380d), 0xd0 }, 292 { CCI_REG8(0x3810), 0x00 }, 293 { CCI_REG8(0x3811), 0x08 }, 294 { CCI_REG8(0x3812), 0x00 }, 295 { CCI_REG8(0x3813), 0x08 }, 296 { CCI_REG8(0x3814), 0x01 }, 297 { CCI_REG8(0x3815), 0x01 }, 298 { CCI_REG8(0x3816), 0x01 }, 299 { CCI_REG8(0x3817), 0x01 }, 300 { CCI_REG8(0x3818), 0x00 }, 301 { CCI_REG8(0x3819), 0x00 }, 302 { CCI_REG8(0x381a), 0x00 }, 303 { CCI_REG8(0x381b), 0x01 }, 304 { CCI_REG8(0x3820), 0x88 }, 305 { CCI_REG8(0x3821), 0x00 }, 306 { CCI_REG8(0x3822), 0x12 }, 307 { CCI_REG8(0x3823), 0x08 }, 308 { CCI_REG8(0x3824), 0x00 }, 309 { CCI_REG8(0x3825), 0x20 }, 310 { CCI_REG8(0x3826), 0x00 }, 311 { CCI_REG8(0x3827), 0x08 }, 312 { CCI_REG8(0x3829), 0x03 }, 313 { CCI_REG8(0x382a), 0x00 }, 314 { CCI_REG8(0x382b), 0x00 }, 315 { CCI_REG8(0x3832), 0x08 }, 316 { CCI_REG8(0x3838), 0x00 }, 317 { CCI_REG8(0x3839), 0x00 }, 318 { CCI_REG8(0x383a), 0x00 }, 319 { CCI_REG8(0x383b), 0x00 }, 320 { CCI_REG8(0x383d), 0x01 }, 321 { CCI_REG8(0x383e), 0x00 }, 322 { CCI_REG8(0x383f), 0x00 }, 323 { CCI_REG8(0x3843), 0x00 }, 324 { CCI_REG8(0x3880), 0x16 }, 325 { CCI_REG8(0x3881), 0x00 }, 326 { CCI_REG8(0x3882), 0x08 }, 327 { CCI_REG8(0x389a), 0x00 }, 328 { CCI_REG8(0x389b), 0x00 }, 329 { CCI_REG8(0x38a2), 0x02 }, 330 { CCI_REG8(0x38a3), 0x02 }, 331 { CCI_REG8(0x38a4), 0x02 }, 332 { CCI_REG8(0x38a5), 0x02 }, 333 { CCI_REG8(0x38a7), 0x04 }, 334 { CCI_REG8(0x38b8), 0x02 }, 335 { CCI_REG8(0x3c80), 0x3e }, 336 { CCI_REG8(0x3c86), 0x01 }, 337 { CCI_REG8(0x3c87), 0x02 }, 338 { CCI_REG8(0x389c), 0x00 }, 339 { CCI_REG8(0x3ca2), 0x0c }, 340 { CCI_REG8(0x3d85), 0x1b }, 341 { CCI_REG8(0x3d8c), 0x01 }, 342 { CCI_REG8(0x3d8d), 0xe2 }, 343 { CCI_REG8(0x3f00), 0xcb }, 344 { CCI_REG8(0x3f03), 0x08 }, 345 { CCI_REG8(0x3f9e), 0x07 }, 346 { CCI_REG8(0x3f9f), 0x04 }, 347 { CCI_REG8(0x4000), 0xf3 }, 348 { CCI_REG8(0x4002), 0x00 }, 349 { CCI_REG8(0x4003), 0x40 }, 350 { CCI_REG8(0x4008), 0x02 }, 351 { CCI_REG8(0x4009), 0x0d }, 352 { CCI_REG8(0x400a), 0x01 }, 353 { CCI_REG8(0x400b), 0x00 }, 354 { CCI_REG8(0x4040), 0x00 }, 355 { CCI_REG8(0x4041), 0x07 }, 356 { CCI_REG8(0x4090), 0x14 }, 357 { CCI_REG8(0x40b0), 0x01 }, 358 { CCI_REG8(0x40b1), 0x01 }, 359 { CCI_REG8(0x40b2), 0x30 }, 360 { CCI_REG8(0x40b3), 0x04 }, 361 { CCI_REG8(0x40b4), 0xe8 }, 362 { CCI_REG8(0x40b5), 0x01 }, 363 { CCI_REG8(0x40b7), 0x07 }, 364 { CCI_REG8(0x40b8), 0xff }, 365 { CCI_REG8(0x40b9), 0x00 }, 366 { CCI_REG8(0x40ba), 0x00 }, 367 { CCI_REG8(0x4300), 0xff }, 368 { CCI_REG8(0x4301), 0x00 }, 369 { CCI_REG8(0x4302), 0x0f }, 370 { CCI_REG8(0x4303), 0x20 }, 371 { CCI_REG8(0x4304), 0x20 }, 372 { CCI_REG8(0x4305), 0x83 }, 373 { CCI_REG8(0x4306), 0x21 }, 374 { CCI_REG8(0x430d), 0x00 }, 375 { CCI_REG8(0x4505), 0xc4 }, 376 { CCI_REG8(0x4506), 0x00 }, 377 { CCI_REG8(0x4507), 0x60 }, 378 { CCI_REG8(0x4803), 0x00 }, 379 { CCI_REG8(0x4809), 0x8e }, 380 { CCI_REG8(0x480e), 0x00 }, 381 { CCI_REG8(0x4813), 0x00 }, 382 { CCI_REG8(0x4814), 0x2a }, 383 { CCI_REG8(0x481b), 0x40 }, 384 { CCI_REG8(0x481f), 0x30 }, 385 { CCI_REG8(0x4825), 0x34 }, 386 { CCI_REG8(0x4829), 0x64 }, 387 { CCI_REG8(0x4837), 0x12 }, 388 { CCI_REG8(0x484b), 0x07 }, 389 { CCI_REG8(0x4883), 0x36 }, 390 { CCI_REG8(0x4885), 0x03 }, 391 { CCI_REG8(0x488b), 0x00 }, 392 { CCI_REG8(0x4d06), 0x01 }, 393 { CCI_REG8(0x4e00), 0x2a }, 394 { CCI_REG8(0x4e0d), 0x00 }, 395 { CCI_REG8(0x5000), 0xf9 }, 396 { CCI_REG8(0x5001), 0x09 }, 397 { CCI_REG8(0x5004), 0x00 }, 398 { CCI_REG8(0x5005), 0x0e }, 399 { CCI_REG8(0x5036), 0x00 }, 400 { CCI_REG8(0x5080), 0x04 }, 401 { CCI_REG8(0x5082), 0x00 }, 402 { CCI_REG8(0x5180), 0x00 }, 403 { CCI_REG8(0x5181), 0x10 }, 404 { CCI_REG8(0x5182), 0x01 }, 405 { CCI_REG8(0x5183), 0xdf }, 406 { CCI_REG8(0x5184), 0x02 }, 407 { CCI_REG8(0x5185), 0x6c }, 408 { CCI_REG8(0x5189), 0x48 }, 409 { CCI_REG8(0x520a), 0x03 }, 410 { CCI_REG8(0x520b), 0x0f }, 411 { CCI_REG8(0x520c), 0x3f }, 412 { CCI_REG8(0x580b), 0x03 }, 413 { CCI_REG8(0x580d), 0x00 }, 414 { CCI_REG8(0x580f), 0x00 }, 415 { CCI_REG8(0x5820), 0x00 }, 416 { CCI_REG8(0x5821), 0x00 }, 417 { CCI_REG8(0x3222), 0x03 }, 418 { CCI_REG8(0x3208), 0x06 }, 419 { CCI_REG8(0x3701), 0x1d }, 420 { CCI_REG8(0x37ab), 0x01 }, 421 { CCI_REG8(0x3790), 0x21 }, 422 { CCI_REG8(0x38be), 0x00 }, 423 { CCI_REG8(0x3791), 0x5a }, 424 { CCI_REG8(0x37bf), 0x1c }, 425 { CCI_REG8(0x3610), 0x37 }, 426 { CCI_REG8(0x3208), 0x16 }, 427 { CCI_REG8(0x3208), 0x07 }, 428 { CCI_REG8(0x3701), 0x1d }, 429 { CCI_REG8(0x37ab), 0x0e }, 430 { CCI_REG8(0x3790), 0x21 }, 431 { CCI_REG8(0x38be), 0x00 }, 432 { CCI_REG8(0x3791), 0x5a }, 433 { CCI_REG8(0x37bf), 0x0a }, 434 { CCI_REG8(0x3610), 0x87 }, 435 { CCI_REG8(0x3208), 0x17 }, 436 { CCI_REG8(0x3208), 0x08 }, 437 { CCI_REG8(0x3701), 0x1d }, 438 { CCI_REG8(0x37ab), 0x0e }, 439 { CCI_REG8(0x3790), 0x21 }, 440 { CCI_REG8(0x38be), 0x00 }, 441 { CCI_REG8(0x3791), 0x5a }, 442 { CCI_REG8(0x37bf), 0x0a }, 443 { CCI_REG8(0x3610), 0x87 }, 444 { CCI_REG8(0x3208), 0x18 }, 445 { CCI_REG8(0x3208), 0x09 }, 446 { CCI_REG8(0x3701), 0x1d }, 447 { CCI_REG8(0x37ab), 0x0e }, 448 { CCI_REG8(0x3790), 0x28 }, 449 { CCI_REG8(0x38be), 0x00 }, 450 { CCI_REG8(0x3791), 0x63 }, 451 { CCI_REG8(0x37bf), 0x0a }, 452 { CCI_REG8(0x3610), 0x87 }, 453 { CCI_REG8(0x3208), 0x19 }, 454 }; 455 456 struct os05b10 { 457 struct device *dev; 458 struct regmap *cci; 459 struct v4l2_subdev sd; 460 struct media_pad pad; 461 struct clk *xclk; 462 struct i2c_client *client; 463 struct gpio_desc *reset_gpio; 464 struct regulator_bulk_data supplies[ARRAY_SIZE(os05b10_supply_name)]; 465 466 /* V4L2 Controls */ 467 struct v4l2_ctrl_handler handler; 468 struct v4l2_ctrl *link_freq; 469 struct v4l2_ctrl *hblank; 470 struct v4l2_ctrl *vblank; 471 struct v4l2_ctrl *gain; 472 struct v4l2_ctrl *exposure; 473 474 u32 link_freq_index; 475 u32 data_lanes; 476 }; 477 478 struct os05b10_mode { 479 u32 width; 480 u32 height; 481 u32 vts; 482 u32 hts; 483 u32 exp; 484 u8 bpp; 485 }; 486 487 static const struct os05b10_mode supported_modes_10bit[] = { 488 { 489 .width = 2592, 490 .height = 1944, 491 .vts = 2006, 492 .hts = 1744, 493 .exp = 1944, 494 .bpp = 10, 495 }, 496 }; 497 498 static const s64 link_frequencies[] = { 499 OS05B10_LINK_FREQ_600MHZ, 500 }; 501 502 static const u32 os05b10_mbus_codes[] = { 503 MEDIA_BUS_FMT_SBGGR10_1X10, 504 }; 505 506 static inline struct os05b10 *to_os05b10(struct v4l2_subdev *sd) 507 { 508 return container_of_const(sd, struct os05b10, sd); 509 }; 510 511 static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl) 512 { 513 struct os05b10 *os05b10 = container_of_const(ctrl->handler, 514 struct os05b10, handler); 515 struct v4l2_subdev_state *state; 516 struct v4l2_mbus_framefmt *fmt; 517 int vmax, ret; 518 519 state = v4l2_subdev_get_locked_active_state(&os05b10->sd); 520 fmt = v4l2_subdev_state_get_format(state, 0); 521 522 if (ctrl->id == V4L2_CID_VBLANK) { 523 /* Honour the VBLANK limits when setting exposure. */ 524 s64 max = fmt->height + ctrl->val - OS05B10_EXPOSURE_MARGIN; 525 526 ret = __v4l2_ctrl_modify_range(os05b10->exposure, 527 os05b10->exposure->minimum, max, 528 os05b10->exposure->step, 529 os05b10->exposure->default_value); 530 if (ret) 531 return ret; 532 } 533 534 if (pm_runtime_get_if_in_use(os05b10->dev) == 0) 535 return 0; 536 537 switch (ctrl->id) { 538 case V4L2_CID_VBLANK: 539 vmax = fmt->height + ctrl->val; 540 ret = cci_write(os05b10->cci, OS05B10_REG_VTS, vmax, NULL); 541 break; 542 case V4L2_CID_ANALOGUE_GAIN: 543 ret = cci_write(os05b10->cci, OS05B10_REG_ANALOG_GAIN, 544 ctrl->val, NULL); 545 break; 546 case V4L2_CID_EXPOSURE: 547 ret = cci_write(os05b10->cci, OS05B10_REG_EXPOSURE, 548 ctrl->val, NULL); 549 break; 550 default: 551 ret = -EINVAL; 552 break; 553 } 554 555 pm_runtime_put(os05b10->dev); 556 557 return ret; 558 } 559 560 static int os05b10_enum_mbus_code(struct v4l2_subdev *sd, 561 struct v4l2_subdev_state *sd_state, 562 struct v4l2_subdev_mbus_code_enum *code) 563 { 564 if (code->index >= ARRAY_SIZE(os05b10_mbus_codes)) 565 return -EINVAL; 566 567 code->code = os05b10_mbus_codes[code->index]; 568 569 return 0; 570 } 571 572 static int os05b10_set_framing_limits(struct os05b10 *os05b10, 573 const struct os05b10_mode *mode) 574 { 575 u32 hblank, vblank, vblank_max, max_exp; 576 int ret; 577 578 hblank = mode->hts - mode->width; 579 ret = __v4l2_ctrl_modify_range(os05b10->hblank, hblank, hblank, 1, 580 hblank); 581 if (ret) 582 return ret; 583 584 vblank = mode->vts - mode->height; 585 vblank_max = OS05B10_VTS_MAX - mode->height; 586 ret = __v4l2_ctrl_modify_range(os05b10->vblank, 0, vblank_max, 1, 587 vblank); 588 if (ret) 589 return ret; 590 591 max_exp = mode->vts - OS05B10_EXPOSURE_MARGIN; 592 return __v4l2_ctrl_modify_range(os05b10->exposure, 593 OS05B10_EXPOSURE_MIN, max_exp, 594 OS05B10_EXPOSURE_STEP, mode->exp); 595 } 596 597 static int os05b10_set_pad_format(struct v4l2_subdev *sd, 598 struct v4l2_subdev_state *sd_state, 599 struct v4l2_subdev_format *fmt) 600 { 601 const struct os05b10_mode *mode = &supported_modes_10bit[0]; 602 struct os05b10 *os05b10 = to_os05b10(sd); 603 struct v4l2_mbus_framefmt *format; 604 int ret; 605 606 fmt->format.width = mode->width; 607 fmt->format.height = mode->height; 608 fmt->format.field = V4L2_FIELD_NONE; 609 fmt->format.colorspace = V4L2_COLORSPACE_RAW; 610 fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; 611 fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; 612 613 format = v4l2_subdev_state_get_format(sd_state, 0); 614 615 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 616 ret = os05b10_set_framing_limits(os05b10, mode); 617 if (ret) 618 return ret; 619 } 620 621 *format = fmt->format; 622 623 return 0; 624 } 625 626 static int os05b10_get_selection(struct v4l2_subdev *sd, 627 struct v4l2_subdev_state *sd_state, 628 struct v4l2_subdev_selection *sel) 629 { 630 switch (sel->target) { 631 case V4L2_SEL_TGT_NATIVE_SIZE: 632 case V4L2_SEL_TGT_CROP_BOUNDS: 633 sel->r = os05b10_native_area; 634 return 0; 635 case V4L2_SEL_TGT_CROP: 636 case V4L2_SEL_TGT_CROP_DEFAULT: 637 sel->r = os05b10_active_area; 638 return 0; 639 default: 640 return -EINVAL; 641 } 642 } 643 644 static int os05b10_enum_frame_size(struct v4l2_subdev *sd, 645 struct v4l2_subdev_state *sd_state, 646 struct v4l2_subdev_frame_size_enum *fse) 647 { 648 if (fse->index >= ARRAY_SIZE(supported_modes_10bit)) 649 return -EINVAL; 650 651 fse->min_width = supported_modes_10bit[fse->index].width; 652 fse->max_width = fse->min_width; 653 fse->min_height = supported_modes_10bit[fse->index].height; 654 fse->max_height = fse->min_height; 655 656 return 0; 657 } 658 659 static int os05b10_enable_streams(struct v4l2_subdev *sd, 660 struct v4l2_subdev_state *state, 661 u32 pad, u64 streams_mask) 662 { 663 struct os05b10 *os05b10 = to_os05b10(sd); 664 int ret; 665 666 ret = pm_runtime_resume_and_get(os05b10->dev); 667 if (ret < 0) 668 return ret; 669 670 /* Write common registers */ 671 ret = cci_multi_reg_write(os05b10->cci, os05b10_common_regs, 672 ARRAY_SIZE(os05b10_common_regs), NULL); 673 if (ret) { 674 dev_err(os05b10->dev, "failed to write common registers\n"); 675 goto err_rpm_put; 676 } 677 678 /* Apply customized user controls */ 679 ret = __v4l2_ctrl_handler_setup(os05b10->sd.ctrl_handler); 680 if (ret) 681 goto err_rpm_put; 682 683 /* Stream ON */ 684 ret = cci_write(os05b10->cci, OS05B10_REG_CTRL_MODE, 685 OS05B10_MODE_STREAMING, NULL); 686 if (ret) 687 goto err_rpm_put; 688 689 return 0; 690 691 err_rpm_put: 692 pm_runtime_put(os05b10->dev); 693 694 return ret; 695 } 696 697 static int os05b10_disable_streams(struct v4l2_subdev *sd, 698 struct v4l2_subdev_state *state, 699 u32 pad, u64 streams_mask) 700 { 701 struct os05b10 *os05b10 = to_os05b10(sd); 702 int ret; 703 704 ret = cci_write(os05b10->cci, OS05B10_REG_CTRL_MODE, 705 OS05B10_MODE_STANDBY, NULL); 706 if (ret) 707 dev_err(os05b10->dev, "failed to set stream off\n"); 708 709 pm_runtime_put(os05b10->dev); 710 711 return 0; 712 } 713 714 static int os05b10_init_state(struct v4l2_subdev *sd, 715 struct v4l2_subdev_state *state) 716 { 717 struct v4l2_mbus_framefmt *format; 718 const struct os05b10_mode *mode; 719 720 /* Initialize try_fmt */ 721 format = v4l2_subdev_state_get_format(state, 0); 722 723 mode = &supported_modes_10bit[0]; 724 format->code = MEDIA_BUS_FMT_SBGGR10_1X10; 725 726 /* Update image pad formate */ 727 format->width = mode->width; 728 format->height = mode->height; 729 format->field = V4L2_FIELD_NONE; 730 format->colorspace = V4L2_COLORSPACE_RAW; 731 format->quantization = V4L2_QUANTIZATION_FULL_RANGE; 732 format->xfer_func = V4L2_XFER_FUNC_NONE; 733 734 return 0; 735 } 736 737 static const struct v4l2_subdev_video_ops os05b10_video_ops = { 738 .s_stream = v4l2_subdev_s_stream_helper, 739 }; 740 741 static const struct v4l2_subdev_pad_ops os05b10_pad_ops = { 742 .enum_mbus_code = os05b10_enum_mbus_code, 743 .get_fmt = v4l2_subdev_get_fmt, 744 .set_fmt = os05b10_set_pad_format, 745 .get_selection = os05b10_get_selection, 746 .enum_frame_size = os05b10_enum_frame_size, 747 .enable_streams = os05b10_enable_streams, 748 .disable_streams = os05b10_disable_streams, 749 }; 750 751 static const struct v4l2_subdev_internal_ops os05b10_internal_ops = { 752 .init_state = os05b10_init_state, 753 }; 754 755 static const struct v4l2_subdev_ops os05b10_subdev_ops = { 756 .video = &os05b10_video_ops, 757 .pad = &os05b10_pad_ops, 758 }; 759 760 static const struct v4l2_ctrl_ops os05b10_ctrl_ops = { 761 .s_ctrl = os05b10_set_ctrl, 762 }; 763 764 static int os05b10_identify_module(struct os05b10 *os05b10) 765 { 766 int ret; 767 u64 val; 768 769 ret = cci_read(os05b10->cci, OS05B10_REG_CHIP_ID, &val, NULL); 770 if (ret) 771 return dev_err_probe(os05b10->dev, ret, 772 "failed to read chip id %x\n", 773 OS05B10_CHIP_ID); 774 775 if (val != OS05B10_CHIP_ID) 776 return dev_err_probe(os05b10->dev, -ENODEV, 777 "chip id mismatch: %x!=%llx\n", 778 OS05B10_CHIP_ID, val); 779 780 return 0; 781 } 782 783 static int os05b10_power_on(struct device *dev) 784 { 785 struct v4l2_subdev *sd = dev_get_drvdata(dev); 786 struct os05b10 *os05b10 = to_os05b10(sd); 787 unsigned long delay_us; 788 int ret; 789 790 /* Enable power rails */ 791 ret = regulator_bulk_enable(ARRAY_SIZE(os05b10_supply_name), 792 os05b10->supplies); 793 if (ret) { 794 dev_err(os05b10->dev, "failed to enable regulators\n"); 795 return ret; 796 } 797 798 /* Enable xclk */ 799 ret = clk_prepare_enable(os05b10->xclk); 800 if (ret) { 801 dev_err(os05b10->dev, "failed to enable clock\n"); 802 goto err_regulator_off; 803 } 804 805 gpiod_set_value_cansleep(os05b10->reset_gpio, 0); 806 807 /* Delay T1 */ 808 fsleep(5 * USEC_PER_MSEC); 809 810 /* Delay T2 (8192 cycles before SCCB/I2C access) */ 811 delay_us = DIV_ROUND_UP(8192, OS05B10_XCLK_FREQ / 1000 / 1000); 812 usleep_range(delay_us, delay_us * 2); 813 814 return 0; 815 816 err_regulator_off: 817 regulator_bulk_disable(ARRAY_SIZE(os05b10_supply_name), 818 os05b10->supplies); 819 820 return ret; 821 } 822 823 static int os05b10_power_off(struct device *dev) 824 { 825 struct v4l2_subdev *sd = dev_get_drvdata(dev); 826 struct os05b10 *os05b10 = to_os05b10(sd); 827 828 gpiod_set_value_cansleep(os05b10->reset_gpio, 1); 829 830 regulator_bulk_disable(ARRAY_SIZE(os05b10_supply_name), 831 os05b10->supplies); 832 clk_disable_unprepare(os05b10->xclk); 833 834 return 0; 835 } 836 837 static int os05b10_parse_endpoint(struct os05b10 *os05b10) 838 { 839 struct v4l2_fwnode_endpoint bus_cfg = { 840 .bus_type = V4L2_MBUS_CSI2_DPHY 841 }; 842 unsigned long link_freq_bitmap; 843 struct fwnode_handle *ep; 844 int ret; 845 846 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(os05b10->dev), 0, 0, 0); 847 if (!ep) { 848 dev_err(os05b10->dev, "Failed to get next endpoint\n"); 849 return -EINVAL; 850 } 851 852 ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 853 fwnode_handle_put(ep); 854 if (ret) 855 return ret; 856 857 if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { 858 ret = dev_err_probe(os05b10->dev, -EINVAL, 859 "only 4 data lanes are supported\n"); 860 goto error_out; 861 } 862 863 os05b10->data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; 864 865 ret = v4l2_link_freq_to_bitmap(os05b10->dev, bus_cfg.link_frequencies, 866 bus_cfg.nr_of_link_frequencies, 867 link_frequencies, 868 ARRAY_SIZE(link_frequencies), 869 &link_freq_bitmap); 870 if (ret) { 871 dev_err(os05b10->dev, "only 600MHz frequency is available\n"); 872 goto error_out; 873 } 874 875 os05b10->link_freq_index = __ffs(link_freq_bitmap); 876 877 error_out: 878 v4l2_fwnode_endpoint_free(&bus_cfg); 879 880 return ret; 881 } 882 883 static u64 os05b10_pixel_rate(struct os05b10 *os05b10, 884 const struct os05b10_mode *mode) 885 { 886 u64 link_freq = link_frequencies[os05b10->link_freq_index]; 887 u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp); 888 889 dev_dbg(os05b10->dev, 890 "link_freq=%llu bpp=%u lanes=%u pixel_rate=%llu\n", 891 link_freq, mode->bpp, os05b10->data_lanes, pixel_rate); 892 893 return pixel_rate; 894 } 895 896 static int os05b10_init_controls(struct os05b10 *os05b10) 897 { 898 const struct os05b10_mode *mode = &supported_modes_10bit[0]; 899 u64 hblank_def, vblank_def, exp_max, pixel_rate; 900 struct v4l2_fwnode_device_properties props; 901 struct v4l2_ctrl_handler *ctrl_hdlr; 902 int ret; 903 904 ctrl_hdlr = &os05b10->handler; 905 v4l2_ctrl_handler_init(ctrl_hdlr, 8); 906 907 pixel_rate = os05b10_pixel_rate(os05b10, mode); 908 v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE, 909 pixel_rate, pixel_rate, 1, pixel_rate); 910 911 os05b10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &os05b10_ctrl_ops, 912 V4L2_CID_LINK_FREQ, 913 ARRAY_SIZE(link_frequencies) - 1, 914 os05b10->link_freq_index, 915 link_frequencies); 916 917 if (os05b10->link_freq) 918 os05b10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 919 920 hblank_def = mode->hts - mode->width; 921 os05b10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, 922 hblank_def, hblank_def, 923 1, hblank_def); 924 if (os05b10->hblank) 925 os05b10->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 926 927 vblank_def = mode->vts - mode->height; 928 os05b10->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, 929 V4L2_CID_VBLANK, vblank_def, 930 OS05B10_VTS_MAX - mode->height, 931 1, vblank_def); 932 933 exp_max = mode->vts - OS05B10_EXPOSURE_MARGIN; 934 os05b10->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, 935 V4L2_CID_EXPOSURE, 936 OS05B10_EXPOSURE_MIN, 937 exp_max, OS05B10_EXPOSURE_STEP, 938 mode->exp); 939 940 os05b10->gain = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, 941 V4L2_CID_ANALOGUE_GAIN, 942 OS05B10_ANALOG_GAIN_MIN, 943 OS05B10_ANALOG_GAIN_MAX, 944 OS05B10_ANALOG_GAIN_STEP, 945 OS05B10_ANALOG_GAIN_DEFAULT); 946 947 if (ctrl_hdlr->error) { 948 ret = ctrl_hdlr->error; 949 dev_err(os05b10->dev, "control init failed (%d)\n", ret); 950 goto error; 951 } 952 953 ret = v4l2_fwnode_device_parse(os05b10->dev, &props); 954 if (ret) 955 goto error; 956 957 ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &os05b10_ctrl_ops, 958 &props); 959 if (ret) 960 goto error; 961 962 os05b10->sd.ctrl_handler = ctrl_hdlr; 963 964 return 0; 965 966 error: 967 v4l2_ctrl_handler_free(ctrl_hdlr); 968 969 return ret; 970 } 971 972 static int os05b10_probe(struct i2c_client *client) 973 { 974 struct os05b10 *os05b10; 975 unsigned int xclk_freq; 976 int ret; 977 978 os05b10 = devm_kzalloc(&client->dev, sizeof(*os05b10), GFP_KERNEL); 979 if (!os05b10) 980 return -ENOMEM; 981 982 os05b10->client = client; 983 os05b10->dev = &client->dev; 984 985 v4l2_i2c_subdev_init(&os05b10->sd, client, &os05b10_subdev_ops); 986 987 os05b10->cci = devm_cci_regmap_init_i2c(client, 16); 988 if (IS_ERR(os05b10->cci)) 989 return dev_err_probe(os05b10->dev, PTR_ERR(os05b10->cci), 990 "failed to initialize CCI\n"); 991 992 os05b10->xclk = devm_v4l2_sensor_clk_get(os05b10->dev, NULL); 993 if (IS_ERR(os05b10->xclk)) 994 return dev_err_probe(os05b10->dev, PTR_ERR(os05b10->xclk), 995 "failed to get xclk\n"); 996 997 xclk_freq = clk_get_rate(os05b10->xclk); 998 if (xclk_freq != OS05B10_XCLK_FREQ) 999 return dev_err_probe(os05b10->dev, -EINVAL, 1000 "xclk frequency not supported: %d Hz\n", 1001 xclk_freq); 1002 1003 for (unsigned int i = 0; i < ARRAY_SIZE(os05b10_supply_name); i++) 1004 os05b10->supplies[i].supply = os05b10_supply_name[i]; 1005 1006 ret = devm_regulator_bulk_get(os05b10->dev, 1007 ARRAY_SIZE(os05b10_supply_name), 1008 os05b10->supplies); 1009 if (ret) 1010 return dev_err_probe(os05b10->dev, ret, 1011 "failed to get regulators\n"); 1012 1013 ret = os05b10_parse_endpoint(os05b10); 1014 if (ret) 1015 return dev_err_probe(os05b10->dev, ret, 1016 "failed to parse endpoint configuration\n"); 1017 1018 os05b10->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", 1019 GPIOD_OUT_HIGH); 1020 if (IS_ERR(os05b10->reset_gpio)) 1021 return dev_err_probe(os05b10->dev, PTR_ERR(os05b10->reset_gpio), 1022 "failed to get reset GPIO\n"); 1023 1024 ret = os05b10_power_on(os05b10->dev); 1025 if (ret) 1026 return ret; 1027 1028 ret = os05b10_identify_module(os05b10); 1029 if (ret) 1030 goto error_power_off; 1031 1032 /* This needs the pm runtime to be registered. */ 1033 ret = os05b10_init_controls(os05b10); 1034 if (ret) 1035 goto error_power_off; 1036 1037 /* Initialize subdev */ 1038 os05b10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1039 os05b10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1040 os05b10->sd.internal_ops = &os05b10_internal_ops; 1041 os05b10->pad.flags = MEDIA_PAD_FL_SOURCE; 1042 1043 ret = media_entity_pads_init(&os05b10->sd.entity, 1, &os05b10->pad); 1044 if (ret) { 1045 dev_err_probe(os05b10->dev, ret, 1046 "failed to init entity pads\n"); 1047 goto error_handler_free; 1048 } 1049 1050 os05b10->sd.state_lock = os05b10->handler.lock; 1051 ret = v4l2_subdev_init_finalize(&os05b10->sd); 1052 if (ret < 0) { 1053 dev_err_probe(os05b10->dev, ret, "subdev init error\n"); 1054 goto error_media_entity; 1055 } 1056 1057 pm_runtime_set_active(os05b10->dev); 1058 pm_runtime_enable(os05b10->dev); 1059 1060 ret = v4l2_async_register_subdev_sensor(&os05b10->sd); 1061 if (ret < 0) { 1062 dev_err_probe(os05b10->dev, ret, 1063 "failed to register os05b10 sub-device\n"); 1064 goto error_subdev_cleanup; 1065 } 1066 1067 pm_runtime_idle(os05b10->dev); 1068 1069 return 0; 1070 1071 error_subdev_cleanup: 1072 v4l2_subdev_cleanup(&os05b10->sd); 1073 pm_runtime_disable(os05b10->dev); 1074 pm_runtime_set_suspended(os05b10->dev); 1075 1076 error_media_entity: 1077 media_entity_cleanup(&os05b10->sd.entity); 1078 1079 error_handler_free: 1080 v4l2_ctrl_handler_free(os05b10->sd.ctrl_handler); 1081 1082 error_power_off: 1083 os05b10_power_off(os05b10->dev); 1084 1085 return ret; 1086 } 1087 1088 static void os05b10_remove(struct i2c_client *client) 1089 { 1090 struct v4l2_subdev *sd = i2c_get_clientdata(client); 1091 struct os05b10 *os05b10 = to_os05b10(sd); 1092 1093 v4l2_async_unregister_subdev(sd); 1094 v4l2_subdev_cleanup(&os05b10->sd); 1095 media_entity_cleanup(&sd->entity); 1096 v4l2_ctrl_handler_free(os05b10->sd.ctrl_handler); 1097 1098 pm_runtime_disable(&client->dev); 1099 if (!pm_runtime_status_suspended(&client->dev)) { 1100 os05b10_power_off(&client->dev); 1101 pm_runtime_set_suspended(&client->dev); 1102 } 1103 } 1104 1105 static DEFINE_RUNTIME_DEV_PM_OPS(os05b10_pm_ops, os05b10_power_off, 1106 os05b10_power_on, NULL); 1107 1108 static const struct of_device_id os05b10_id[] = { 1109 { .compatible = "ovti,os05b10" }, 1110 { /* sentinel */ } 1111 }; 1112 1113 MODULE_DEVICE_TABLE(of, os05b10_id); 1114 1115 static struct i2c_driver os05b10_driver = { 1116 .driver = { 1117 .name = "os05b10", 1118 .pm = pm_ptr(&os05b10_pm_ops), 1119 .of_match_table = os05b10_id, 1120 }, 1121 .probe = os05b10_probe, 1122 .remove = os05b10_remove, 1123 }; 1124 1125 module_i2c_driver(os05b10_driver); 1126 1127 MODULE_DESCRIPTION("OS05B10 Camera Sensor Driver"); 1128 MODULE_AUTHOR("Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>"); 1129 MODULE_AUTHOR("Elgin Perumbilly <elgin.perumbilly@siliconsignals.io>"); 1130 MODULE_LICENSE("GPL"); 1131