124169a5aSJacopo Mondi // SPDX-License-Identifier: GPL-2.0 23c2472a3SRamiro Oliveira /* 33c2472a3SRamiro Oliveira * A V4L2 driver for OmniVision OV5647 cameras. 43c2472a3SRamiro Oliveira * 53c2472a3SRamiro Oliveira * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver 63c2472a3SRamiro Oliveira * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com> 73c2472a3SRamiro Oliveira * 83c2472a3SRamiro Oliveira * Based on Omnivision OV7670 Camera Driver 93c2472a3SRamiro Oliveira * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net> 103c2472a3SRamiro Oliveira * 113c2472a3SRamiro Oliveira * Copyright (C) 2016, Synopsys, Inc. 123c2472a3SRamiro Oliveira */ 133c2472a3SRamiro Oliveira 143c2472a3SRamiro Oliveira #include <linux/clk.h> 153c2472a3SRamiro Oliveira #include <linux/delay.h> 16b050791dSDave Stevenson #include <linux/gpio/consumer.h> 173c2472a3SRamiro Oliveira #include <linux/i2c.h> 183c2472a3SRamiro Oliveira #include <linux/init.h> 193c2472a3SRamiro Oliveira #include <linux/io.h> 203c2472a3SRamiro Oliveira #include <linux/module.h> 21859969b3SSakari Ailus #include <linux/of_graph.h> 22089b7c70SJacopo Mondi #include <linux/pm_runtime.h> 233c2472a3SRamiro Oliveira #include <linux/slab.h> 243c2472a3SRamiro Oliveira #include <linux/videodev2.h> 254974c2f1SDavid Plowman #include <media/v4l2-ctrls.h> 263c2472a3SRamiro Oliveira #include <media/v4l2-device.h> 27dc337308SJacopo Mondi #include <media/v4l2-event.h> 28859969b3SSakari Ailus #include <media/v4l2-fwnode.h> 293c2472a3SRamiro Oliveira #include <media/v4l2-image-sizes.h> 303c2472a3SRamiro Oliveira #include <media/v4l2-mediabus.h> 313c2472a3SRamiro Oliveira 32b050791dSDave Stevenson /* 33b050791dSDave Stevenson * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes 34b050791dSDave Stevenson * high if reset is inserted after PWDN goes high, host can access sensor's 35b050791dSDave Stevenson * SCCB to initialize sensor." 36b050791dSDave Stevenson */ 37b050791dSDave Stevenson #define PWDN_ACTIVE_DELAY_MS 20 38b050791dSDave Stevenson 39cef66734SJacob Chen #define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) 40dea4fcfeSDave Stevenson #define MIPI_CTRL00_LINE_SYNC_ENABLE BIT(4) 41cef66734SJacob Chen #define MIPI_CTRL00_BUS_IDLE BIT(2) 42cef66734SJacob Chen #define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) 43cef66734SJacob Chen 44cef66734SJacob Chen #define OV5647_SW_STANDBY 0x0100 453c2472a3SRamiro Oliveira #define OV5647_SW_RESET 0x0103 46c9a05cecSJacopo Mondi #define OV5647_REG_CHIPID_H 0x300a 47c9a05cecSJacopo Mondi #define OV5647_REG_CHIPID_L 0x300b 48c9a05cecSJacopo Mondi #define OV5640_REG_PAD_OUT 0x300d 494974c2f1SDavid Plowman #define OV5647_REG_EXP_HI 0x3500 504974c2f1SDavid Plowman #define OV5647_REG_EXP_MID 0x3501 514974c2f1SDavid Plowman #define OV5647_REG_EXP_LO 0x3502 524974c2f1SDavid Plowman #define OV5647_REG_AEC_AGC 0x3503 534974c2f1SDavid Plowman #define OV5647_REG_GAIN_HI 0x350a 544974c2f1SDavid Plowman #define OV5647_REG_GAIN_LO 0x350b 552512c064SDave Stevenson #define OV5647_REG_VTS_HI 0x380e 562512c064SDave Stevenson #define OV5647_REG_VTS_LO 0x380f 57cef66734SJacob Chen #define OV5647_REG_FRAME_OFF_NUMBER 0x4202 58cef66734SJacob Chen #define OV5647_REG_MIPI_CTRL00 0x4800 59cef66734SJacob Chen #define OV5647_REG_MIPI_CTRL14 0x4814 604974c2f1SDavid Plowman #define OV5647_REG_AWB 0x5001 613c2472a3SRamiro Oliveira 623c2472a3SRamiro Oliveira #define REG_TERM 0xfffe 633c2472a3SRamiro Oliveira #define VAL_TERM 0xfe 643c2472a3SRamiro Oliveira #define REG_DLY 0xffff 653c2472a3SRamiro Oliveira 6614f70a32SDave Stevenson /* OV5647 native and active pixel array size */ 6714f70a32SDave Stevenson #define OV5647_NATIVE_WIDTH 2624U 6814f70a32SDave Stevenson #define OV5647_NATIVE_HEIGHT 1956U 693c2472a3SRamiro Oliveira 7014f70a32SDave Stevenson #define OV5647_PIXEL_ARRAY_LEFT 16U 7114f70a32SDave Stevenson #define OV5647_PIXEL_ARRAY_TOP 16U 7214f70a32SDave Stevenson #define OV5647_PIXEL_ARRAY_WIDTH 2592U 7314f70a32SDave Stevenson #define OV5647_PIXEL_ARRAY_HEIGHT 1944U 743c2472a3SRamiro Oliveira 752512c064SDave Stevenson #define OV5647_VBLANK_MIN 4 762512c064SDave Stevenson #define OV5647_VTS_MAX 32767 772512c064SDave Stevenson 78646a0249SDave Stevenson #define OV5647_EXPOSURE_MIN 4 79646a0249SDave Stevenson #define OV5647_EXPOSURE_STEP 1 80646a0249SDave Stevenson #define OV5647_EXPOSURE_DEFAULT 1000 81646a0249SDave Stevenson #define OV5647_EXPOSURE_MAX 65535 82646a0249SDave Stevenson 833c2472a3SRamiro Oliveira struct regval_list { 843c2472a3SRamiro Oliveira u16 addr; 853c2472a3SRamiro Oliveira u8 data; 863c2472a3SRamiro Oliveira }; 873c2472a3SRamiro Oliveira 88d7d6074eSJacopo Mondi struct ov5647_mode { 89d7d6074eSJacopo Mondi struct v4l2_mbus_framefmt format; 9014f70a32SDave Stevenson struct v4l2_rect crop; 91911f4516SDave Stevenson u64 pixel_rate; 92c6da1ae4SJacopo Mondi int hts; 932512c064SDave Stevenson int vts; 94d7d6074eSJacopo Mondi const struct regval_list *reg_list; 95d7d6074eSJacopo Mondi unsigned int num_regs; 96d7d6074eSJacopo Mondi }; 97d7d6074eSJacopo Mondi 983c2472a3SRamiro Oliveira struct ov5647 { 993c2472a3SRamiro Oliveira struct v4l2_subdev sd; 1003c2472a3SRamiro Oliveira struct media_pad pad; 1013c2472a3SRamiro Oliveira struct mutex lock; 1023c2472a3SRamiro Oliveira struct clk *xclk; 103b050791dSDave Stevenson struct gpio_desc *pwdn; 104dea4fcfeSDave Stevenson bool clock_ncont; 1054974c2f1SDavid Plowman struct v4l2_ctrl_handler ctrls; 106d7d6074eSJacopo Mondi const struct ov5647_mode *mode; 107911f4516SDave Stevenson struct v4l2_ctrl *pixel_rate; 108c6da1ae4SJacopo Mondi struct v4l2_ctrl *hblank; 1092512c064SDave Stevenson struct v4l2_ctrl *vblank; 110646a0249SDave Stevenson struct v4l2_ctrl *exposure; 1112f038c97SJacopo Mondi bool streaming; 1123c2472a3SRamiro Oliveira }; 1133c2472a3SRamiro Oliveira 1145bc5ca71SJacopo Mondi static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd) 1153c2472a3SRamiro Oliveira { 1163c2472a3SRamiro Oliveira return container_of(sd, struct ov5647, sd); 1173c2472a3SRamiro Oliveira } 1183c2472a3SRamiro Oliveira 119d0744070SJacopo Mondi static const struct regval_list sensor_oe_disable_regs[] = { 1203c2472a3SRamiro Oliveira {0x3000, 0x00}, 1213c2472a3SRamiro Oliveira {0x3001, 0x00}, 1223c2472a3SRamiro Oliveira {0x3002, 0x00}, 1233c2472a3SRamiro Oliveira }; 1243c2472a3SRamiro Oliveira 125d0744070SJacopo Mondi static const struct regval_list sensor_oe_enable_regs[] = { 1263c2472a3SRamiro Oliveira {0x3000, 0x0f}, 1273c2472a3SRamiro Oliveira {0x3001, 0xff}, 1283c2472a3SRamiro Oliveira {0x3002, 0xe4}, 1293c2472a3SRamiro Oliveira }; 1303c2472a3SRamiro Oliveira 131a8df5af6SJacopo Mondi static struct regval_list ov5647_2592x1944_10bpp[] = { 132a8df5af6SJacopo Mondi {0x0100, 0x00}, 133a8df5af6SJacopo Mondi {0x0103, 0x01}, 134a8df5af6SJacopo Mondi {0x3034, 0x1a}, 135a8df5af6SJacopo Mondi {0x3035, 0x21}, 136a8df5af6SJacopo Mondi {0x3036, 0x69}, 137a8df5af6SJacopo Mondi {0x303c, 0x11}, 138a8df5af6SJacopo Mondi {0x3106, 0xf5}, 139a8df5af6SJacopo Mondi {0x3821, 0x06}, 140a8df5af6SJacopo Mondi {0x3820, 0x00}, 141a8df5af6SJacopo Mondi {0x3827, 0xec}, 142a8df5af6SJacopo Mondi {0x370c, 0x03}, 143a8df5af6SJacopo Mondi {0x3612, 0x5b}, 144a8df5af6SJacopo Mondi {0x3618, 0x04}, 145a8df5af6SJacopo Mondi {0x5000, 0x06}, 146a8df5af6SJacopo Mondi {0x5002, 0x41}, 147a8df5af6SJacopo Mondi {0x5003, 0x08}, 148a8df5af6SJacopo Mondi {0x5a00, 0x08}, 149a8df5af6SJacopo Mondi {0x3000, 0x00}, 150a8df5af6SJacopo Mondi {0x3001, 0x00}, 151a8df5af6SJacopo Mondi {0x3002, 0x00}, 152a8df5af6SJacopo Mondi {0x3016, 0x08}, 153a8df5af6SJacopo Mondi {0x3017, 0xe0}, 154a8df5af6SJacopo Mondi {0x3018, 0x44}, 155a8df5af6SJacopo Mondi {0x301c, 0xf8}, 156a8df5af6SJacopo Mondi {0x301d, 0xf0}, 157a8df5af6SJacopo Mondi {0x3a18, 0x00}, 158a8df5af6SJacopo Mondi {0x3a19, 0xf8}, 159a8df5af6SJacopo Mondi {0x3c01, 0x80}, 160a8df5af6SJacopo Mondi {0x3b07, 0x0c}, 161a8df5af6SJacopo Mondi {0x380c, 0x0b}, 162a8df5af6SJacopo Mondi {0x380d, 0x1c}, 163a8df5af6SJacopo Mondi {0x3814, 0x11}, 164a8df5af6SJacopo Mondi {0x3815, 0x11}, 165a8df5af6SJacopo Mondi {0x3708, 0x64}, 166a8df5af6SJacopo Mondi {0x3709, 0x12}, 167a8df5af6SJacopo Mondi {0x3808, 0x0a}, 168a8df5af6SJacopo Mondi {0x3809, 0x20}, 169a8df5af6SJacopo Mondi {0x380a, 0x07}, 170a8df5af6SJacopo Mondi {0x380b, 0x98}, 171a8df5af6SJacopo Mondi {0x3800, 0x00}, 172a8df5af6SJacopo Mondi {0x3801, 0x00}, 173a8df5af6SJacopo Mondi {0x3802, 0x00}, 174a8df5af6SJacopo Mondi {0x3803, 0x00}, 175a8df5af6SJacopo Mondi {0x3804, 0x0a}, 176a8df5af6SJacopo Mondi {0x3805, 0x3f}, 177a8df5af6SJacopo Mondi {0x3806, 0x07}, 178a8df5af6SJacopo Mondi {0x3807, 0xa3}, 179a8df5af6SJacopo Mondi {0x3811, 0x10}, 180a8df5af6SJacopo Mondi {0x3813, 0x06}, 181a8df5af6SJacopo Mondi {0x3630, 0x2e}, 182a8df5af6SJacopo Mondi {0x3632, 0xe2}, 183a8df5af6SJacopo Mondi {0x3633, 0x23}, 184a8df5af6SJacopo Mondi {0x3634, 0x44}, 185a8df5af6SJacopo Mondi {0x3636, 0x06}, 186a8df5af6SJacopo Mondi {0x3620, 0x64}, 187a8df5af6SJacopo Mondi {0x3621, 0xe0}, 188a8df5af6SJacopo Mondi {0x3600, 0x37}, 189a8df5af6SJacopo Mondi {0x3704, 0xa0}, 190a8df5af6SJacopo Mondi {0x3703, 0x5a}, 191a8df5af6SJacopo Mondi {0x3715, 0x78}, 192a8df5af6SJacopo Mondi {0x3717, 0x01}, 193a8df5af6SJacopo Mondi {0x3731, 0x02}, 194a8df5af6SJacopo Mondi {0x370b, 0x60}, 195a8df5af6SJacopo Mondi {0x3705, 0x1a}, 196a8df5af6SJacopo Mondi {0x3f05, 0x02}, 197a8df5af6SJacopo Mondi {0x3f06, 0x10}, 198a8df5af6SJacopo Mondi {0x3f01, 0x0a}, 199a8df5af6SJacopo Mondi {0x3a08, 0x01}, 200a8df5af6SJacopo Mondi {0x3a09, 0x28}, 201a8df5af6SJacopo Mondi {0x3a0a, 0x00}, 202a8df5af6SJacopo Mondi {0x3a0b, 0xf6}, 203a8df5af6SJacopo Mondi {0x3a0d, 0x08}, 204a8df5af6SJacopo Mondi {0x3a0e, 0x06}, 205a8df5af6SJacopo Mondi {0x3a0f, 0x58}, 206a8df5af6SJacopo Mondi {0x3a10, 0x50}, 207a8df5af6SJacopo Mondi {0x3a1b, 0x58}, 208a8df5af6SJacopo Mondi {0x3a1e, 0x50}, 209a8df5af6SJacopo Mondi {0x3a11, 0x60}, 210a8df5af6SJacopo Mondi {0x3a1f, 0x28}, 211a8df5af6SJacopo Mondi {0x4001, 0x02}, 212a8df5af6SJacopo Mondi {0x4004, 0x04}, 213a8df5af6SJacopo Mondi {0x4000, 0x09}, 214a8df5af6SJacopo Mondi {0x4837, 0x19}, 215a8df5af6SJacopo Mondi {0x4800, 0x24}, 216a8df5af6SJacopo Mondi {0x3503, 0x03}, 217a8df5af6SJacopo Mondi {0x0100, 0x01}, 218a8df5af6SJacopo Mondi }; 219a8df5af6SJacopo Mondi 220a8df5af6SJacopo Mondi static struct regval_list ov5647_1080p30_10bpp[] = { 221a8df5af6SJacopo Mondi {0x0100, 0x00}, 222a8df5af6SJacopo Mondi {0x0103, 0x01}, 223a8df5af6SJacopo Mondi {0x3034, 0x1a}, 224a8df5af6SJacopo Mondi {0x3035, 0x21}, 225a8df5af6SJacopo Mondi {0x3036, 0x62}, 226a8df5af6SJacopo Mondi {0x303c, 0x11}, 227a8df5af6SJacopo Mondi {0x3106, 0xf5}, 228a8df5af6SJacopo Mondi {0x3821, 0x06}, 229a8df5af6SJacopo Mondi {0x3820, 0x00}, 230a8df5af6SJacopo Mondi {0x3827, 0xec}, 231a8df5af6SJacopo Mondi {0x370c, 0x03}, 232a8df5af6SJacopo Mondi {0x3612, 0x5b}, 233a8df5af6SJacopo Mondi {0x3618, 0x04}, 234a8df5af6SJacopo Mondi {0x5000, 0x06}, 235a8df5af6SJacopo Mondi {0x5002, 0x41}, 236a8df5af6SJacopo Mondi {0x5003, 0x08}, 237a8df5af6SJacopo Mondi {0x5a00, 0x08}, 238a8df5af6SJacopo Mondi {0x3000, 0x00}, 239a8df5af6SJacopo Mondi {0x3001, 0x00}, 240a8df5af6SJacopo Mondi {0x3002, 0x00}, 241a8df5af6SJacopo Mondi {0x3016, 0x08}, 242a8df5af6SJacopo Mondi {0x3017, 0xe0}, 243a8df5af6SJacopo Mondi {0x3018, 0x44}, 244a8df5af6SJacopo Mondi {0x301c, 0xf8}, 245a8df5af6SJacopo Mondi {0x301d, 0xf0}, 246a8df5af6SJacopo Mondi {0x3a18, 0x00}, 247a8df5af6SJacopo Mondi {0x3a19, 0xf8}, 248a8df5af6SJacopo Mondi {0x3c01, 0x80}, 249a8df5af6SJacopo Mondi {0x3b07, 0x0c}, 250a8df5af6SJacopo Mondi {0x380c, 0x09}, 251a8df5af6SJacopo Mondi {0x380d, 0x70}, 252a8df5af6SJacopo Mondi {0x3814, 0x11}, 253a8df5af6SJacopo Mondi {0x3815, 0x11}, 254a8df5af6SJacopo Mondi {0x3708, 0x64}, 255a8df5af6SJacopo Mondi {0x3709, 0x12}, 256a8df5af6SJacopo Mondi {0x3808, 0x07}, 257a8df5af6SJacopo Mondi {0x3809, 0x80}, 258a8df5af6SJacopo Mondi {0x380a, 0x04}, 259a8df5af6SJacopo Mondi {0x380b, 0x38}, 260a8df5af6SJacopo Mondi {0x3800, 0x01}, 261a8df5af6SJacopo Mondi {0x3801, 0x5c}, 262a8df5af6SJacopo Mondi {0x3802, 0x01}, 263a8df5af6SJacopo Mondi {0x3803, 0xb2}, 264a8df5af6SJacopo Mondi {0x3804, 0x08}, 265a8df5af6SJacopo Mondi {0x3805, 0xe3}, 266a8df5af6SJacopo Mondi {0x3806, 0x05}, 267a8df5af6SJacopo Mondi {0x3807, 0xf1}, 268a8df5af6SJacopo Mondi {0x3811, 0x04}, 269a8df5af6SJacopo Mondi {0x3813, 0x02}, 270a8df5af6SJacopo Mondi {0x3630, 0x2e}, 271a8df5af6SJacopo Mondi {0x3632, 0xe2}, 272a8df5af6SJacopo Mondi {0x3633, 0x23}, 273a8df5af6SJacopo Mondi {0x3634, 0x44}, 274a8df5af6SJacopo Mondi {0x3636, 0x06}, 275a8df5af6SJacopo Mondi {0x3620, 0x64}, 276a8df5af6SJacopo Mondi {0x3621, 0xe0}, 277a8df5af6SJacopo Mondi {0x3600, 0x37}, 278a8df5af6SJacopo Mondi {0x3704, 0xa0}, 279a8df5af6SJacopo Mondi {0x3703, 0x5a}, 280a8df5af6SJacopo Mondi {0x3715, 0x78}, 281a8df5af6SJacopo Mondi {0x3717, 0x01}, 282a8df5af6SJacopo Mondi {0x3731, 0x02}, 283a8df5af6SJacopo Mondi {0x370b, 0x60}, 284a8df5af6SJacopo Mondi {0x3705, 0x1a}, 285a8df5af6SJacopo Mondi {0x3f05, 0x02}, 286a8df5af6SJacopo Mondi {0x3f06, 0x10}, 287a8df5af6SJacopo Mondi {0x3f01, 0x0a}, 288a8df5af6SJacopo Mondi {0x3a08, 0x01}, 289a8df5af6SJacopo Mondi {0x3a09, 0x4b}, 290a8df5af6SJacopo Mondi {0x3a0a, 0x01}, 291a8df5af6SJacopo Mondi {0x3a0b, 0x13}, 292a8df5af6SJacopo Mondi {0x3a0d, 0x04}, 293a8df5af6SJacopo Mondi {0x3a0e, 0x03}, 294a8df5af6SJacopo Mondi {0x3a0f, 0x58}, 295a8df5af6SJacopo Mondi {0x3a10, 0x50}, 296a8df5af6SJacopo Mondi {0x3a1b, 0x58}, 297a8df5af6SJacopo Mondi {0x3a1e, 0x50}, 298a8df5af6SJacopo Mondi {0x3a11, 0x60}, 299a8df5af6SJacopo Mondi {0x3a1f, 0x28}, 300a8df5af6SJacopo Mondi {0x4001, 0x02}, 301a8df5af6SJacopo Mondi {0x4004, 0x04}, 302a8df5af6SJacopo Mondi {0x4000, 0x09}, 303a8df5af6SJacopo Mondi {0x4837, 0x19}, 304a8df5af6SJacopo Mondi {0x4800, 0x34}, 305a8df5af6SJacopo Mondi {0x3503, 0x03}, 306a8df5af6SJacopo Mondi {0x0100, 0x01}, 307a8df5af6SJacopo Mondi }; 308a8df5af6SJacopo Mondi 309a8df5af6SJacopo Mondi static struct regval_list ov5647_2x2binned_10bpp[] = { 310a8df5af6SJacopo Mondi {0x0100, 0x00}, 311a8df5af6SJacopo Mondi {0x0103, 0x01}, 312a8df5af6SJacopo Mondi {0x3034, 0x1a}, 313a8df5af6SJacopo Mondi {0x3035, 0x21}, 314a8df5af6SJacopo Mondi {0x3036, 0x62}, 315a8df5af6SJacopo Mondi {0x303c, 0x11}, 316a8df5af6SJacopo Mondi {0x3106, 0xf5}, 317a8df5af6SJacopo Mondi {0x3827, 0xec}, 318a8df5af6SJacopo Mondi {0x370c, 0x03}, 319a8df5af6SJacopo Mondi {0x3612, 0x59}, 320a8df5af6SJacopo Mondi {0x3618, 0x00}, 321a8df5af6SJacopo Mondi {0x5000, 0x06}, 322a8df5af6SJacopo Mondi {0x5002, 0x41}, 323a8df5af6SJacopo Mondi {0x5003, 0x08}, 324a8df5af6SJacopo Mondi {0x5a00, 0x08}, 325a8df5af6SJacopo Mondi {0x3000, 0x00}, 326a8df5af6SJacopo Mondi {0x3001, 0x00}, 327a8df5af6SJacopo Mondi {0x3002, 0x00}, 328a8df5af6SJacopo Mondi {0x3016, 0x08}, 329a8df5af6SJacopo Mondi {0x3017, 0xe0}, 330a8df5af6SJacopo Mondi {0x3018, 0x44}, 331a8df5af6SJacopo Mondi {0x301c, 0xf8}, 332a8df5af6SJacopo Mondi {0x301d, 0xf0}, 333a8df5af6SJacopo Mondi {0x3a18, 0x00}, 334a8df5af6SJacopo Mondi {0x3a19, 0xf8}, 335a8df5af6SJacopo Mondi {0x3c01, 0x80}, 336a8df5af6SJacopo Mondi {0x3b07, 0x0c}, 337a8df5af6SJacopo Mondi {0x3800, 0x00}, 338a8df5af6SJacopo Mondi {0x3801, 0x00}, 339a8df5af6SJacopo Mondi {0x3802, 0x00}, 340a8df5af6SJacopo Mondi {0x3803, 0x00}, 341a8df5af6SJacopo Mondi {0x3804, 0x0a}, 342a8df5af6SJacopo Mondi {0x3805, 0x3f}, 343a8df5af6SJacopo Mondi {0x3806, 0x07}, 344a8df5af6SJacopo Mondi {0x3807, 0xa3}, 345a8df5af6SJacopo Mondi {0x3808, 0x05}, 346a8df5af6SJacopo Mondi {0x3809, 0x10}, 347a8df5af6SJacopo Mondi {0x380a, 0x03}, 348a8df5af6SJacopo Mondi {0x380b, 0xcc}, 349a8df5af6SJacopo Mondi {0x380c, 0x07}, 350a8df5af6SJacopo Mondi {0x380d, 0x68}, 351a8df5af6SJacopo Mondi {0x3811, 0x0c}, 352a8df5af6SJacopo Mondi {0x3813, 0x06}, 353a8df5af6SJacopo Mondi {0x3814, 0x31}, 354a8df5af6SJacopo Mondi {0x3815, 0x31}, 355a8df5af6SJacopo Mondi {0x3630, 0x2e}, 356a8df5af6SJacopo Mondi {0x3632, 0xe2}, 357a8df5af6SJacopo Mondi {0x3633, 0x23}, 358a8df5af6SJacopo Mondi {0x3634, 0x44}, 359a8df5af6SJacopo Mondi {0x3636, 0x06}, 360a8df5af6SJacopo Mondi {0x3620, 0x64}, 361a8df5af6SJacopo Mondi {0x3621, 0xe0}, 362a8df5af6SJacopo Mondi {0x3600, 0x37}, 363a8df5af6SJacopo Mondi {0x3704, 0xa0}, 364a8df5af6SJacopo Mondi {0x3703, 0x5a}, 365a8df5af6SJacopo Mondi {0x3715, 0x78}, 366a8df5af6SJacopo Mondi {0x3717, 0x01}, 367a8df5af6SJacopo Mondi {0x3731, 0x02}, 368a8df5af6SJacopo Mondi {0x370b, 0x60}, 369a8df5af6SJacopo Mondi {0x3705, 0x1a}, 370a8df5af6SJacopo Mondi {0x3f05, 0x02}, 371a8df5af6SJacopo Mondi {0x3f06, 0x10}, 372a8df5af6SJacopo Mondi {0x3f01, 0x0a}, 373a8df5af6SJacopo Mondi {0x3a08, 0x01}, 374a8df5af6SJacopo Mondi {0x3a09, 0x28}, 375a8df5af6SJacopo Mondi {0x3a0a, 0x00}, 376a8df5af6SJacopo Mondi {0x3a0b, 0xf6}, 377a8df5af6SJacopo Mondi {0x3a0d, 0x08}, 378a8df5af6SJacopo Mondi {0x3a0e, 0x06}, 379a8df5af6SJacopo Mondi {0x3a0f, 0x58}, 380a8df5af6SJacopo Mondi {0x3a10, 0x50}, 381a8df5af6SJacopo Mondi {0x3a1b, 0x58}, 382a8df5af6SJacopo Mondi {0x3a1e, 0x50}, 383a8df5af6SJacopo Mondi {0x3a11, 0x60}, 384a8df5af6SJacopo Mondi {0x3a1f, 0x28}, 385a8df5af6SJacopo Mondi {0x4001, 0x02}, 386a8df5af6SJacopo Mondi {0x4004, 0x04}, 387a8df5af6SJacopo Mondi {0x4000, 0x09}, 388a8df5af6SJacopo Mondi {0x4837, 0x16}, 389a8df5af6SJacopo Mondi {0x4800, 0x24}, 390a8df5af6SJacopo Mondi {0x3503, 0x03}, 391a8df5af6SJacopo Mondi {0x3820, 0x41}, 392a8df5af6SJacopo Mondi {0x3821, 0x07}, 393a8df5af6SJacopo Mondi {0x350a, 0x00}, 394a8df5af6SJacopo Mondi {0x350b, 0x10}, 395a8df5af6SJacopo Mondi {0x3500, 0x00}, 396a8df5af6SJacopo Mondi {0x3501, 0x1a}, 397a8df5af6SJacopo Mondi {0x3502, 0xf0}, 398a8df5af6SJacopo Mondi {0x3212, 0xa0}, 399a8df5af6SJacopo Mondi {0x0100, 0x01}, 400a8df5af6SJacopo Mondi }; 401a8df5af6SJacopo Mondi 402a8df5af6SJacopo Mondi static struct regval_list ov5647_640x480_10bpp[] = { 403a8df5af6SJacopo Mondi {0x0100, 0x00}, 404a8df5af6SJacopo Mondi {0x0103, 0x01}, 405a8df5af6SJacopo Mondi {0x3035, 0x11}, 406a8df5af6SJacopo Mondi {0x3036, 0x46}, 407a8df5af6SJacopo Mondi {0x303c, 0x11}, 408a8df5af6SJacopo Mondi {0x3821, 0x07}, 409a8df5af6SJacopo Mondi {0x3820, 0x41}, 410a8df5af6SJacopo Mondi {0x370c, 0x03}, 411a8df5af6SJacopo Mondi {0x3612, 0x59}, 412a8df5af6SJacopo Mondi {0x3618, 0x00}, 413a8df5af6SJacopo Mondi {0x5000, 0x06}, 414a8df5af6SJacopo Mondi {0x5003, 0x08}, 415a8df5af6SJacopo Mondi {0x5a00, 0x08}, 416a8df5af6SJacopo Mondi {0x3000, 0xff}, 417a8df5af6SJacopo Mondi {0x3001, 0xff}, 418a8df5af6SJacopo Mondi {0x3002, 0xff}, 419a8df5af6SJacopo Mondi {0x301d, 0xf0}, 420a8df5af6SJacopo Mondi {0x3a18, 0x00}, 421a8df5af6SJacopo Mondi {0x3a19, 0xf8}, 422a8df5af6SJacopo Mondi {0x3c01, 0x80}, 423a8df5af6SJacopo Mondi {0x3b07, 0x0c}, 424a8df5af6SJacopo Mondi {0x380c, 0x07}, 425a8df5af6SJacopo Mondi {0x380d, 0x3c}, 426a8df5af6SJacopo Mondi {0x3814, 0x35}, 427a8df5af6SJacopo Mondi {0x3815, 0x35}, 428a8df5af6SJacopo Mondi {0x3708, 0x64}, 429a8df5af6SJacopo Mondi {0x3709, 0x52}, 430a8df5af6SJacopo Mondi {0x3808, 0x02}, 431a8df5af6SJacopo Mondi {0x3809, 0x80}, 432a8df5af6SJacopo Mondi {0x380a, 0x01}, 433a8df5af6SJacopo Mondi {0x380b, 0xe0}, 434a8df5af6SJacopo Mondi {0x3800, 0x00}, 435a8df5af6SJacopo Mondi {0x3801, 0x10}, 436a8df5af6SJacopo Mondi {0x3802, 0x00}, 437a8df5af6SJacopo Mondi {0x3803, 0x00}, 438a8df5af6SJacopo Mondi {0x3804, 0x0a}, 439a8df5af6SJacopo Mondi {0x3805, 0x2f}, 440a8df5af6SJacopo Mondi {0x3806, 0x07}, 441a8df5af6SJacopo Mondi {0x3807, 0x9f}, 442a8df5af6SJacopo Mondi {0x3630, 0x2e}, 443a8df5af6SJacopo Mondi {0x3632, 0xe2}, 444a8df5af6SJacopo Mondi {0x3633, 0x23}, 445a8df5af6SJacopo Mondi {0x3634, 0x44}, 446a8df5af6SJacopo Mondi {0x3620, 0x64}, 447a8df5af6SJacopo Mondi {0x3621, 0xe0}, 448a8df5af6SJacopo Mondi {0x3600, 0x37}, 449a8df5af6SJacopo Mondi {0x3704, 0xa0}, 450a8df5af6SJacopo Mondi {0x3703, 0x5a}, 451a8df5af6SJacopo Mondi {0x3715, 0x78}, 452a8df5af6SJacopo Mondi {0x3717, 0x01}, 453a8df5af6SJacopo Mondi {0x3731, 0x02}, 454a8df5af6SJacopo Mondi {0x370b, 0x60}, 455a8df5af6SJacopo Mondi {0x3705, 0x1a}, 456a8df5af6SJacopo Mondi {0x3f05, 0x02}, 457a8df5af6SJacopo Mondi {0x3f06, 0x10}, 458a8df5af6SJacopo Mondi {0x3f01, 0x0a}, 459a8df5af6SJacopo Mondi {0x3a08, 0x01}, 460a8df5af6SJacopo Mondi {0x3a09, 0x2e}, 461a8df5af6SJacopo Mondi {0x3a0a, 0x00}, 462a8df5af6SJacopo Mondi {0x3a0b, 0xfb}, 463a8df5af6SJacopo Mondi {0x3a0d, 0x02}, 464a8df5af6SJacopo Mondi {0x3a0e, 0x01}, 465a8df5af6SJacopo Mondi {0x3a0f, 0x58}, 466a8df5af6SJacopo Mondi {0x3a10, 0x50}, 467a8df5af6SJacopo Mondi {0x3a1b, 0x58}, 468a8df5af6SJacopo Mondi {0x3a1e, 0x50}, 469a8df5af6SJacopo Mondi {0x3a11, 0x60}, 470a8df5af6SJacopo Mondi {0x3a1f, 0x28}, 471a8df5af6SJacopo Mondi {0x4001, 0x02}, 472a8df5af6SJacopo Mondi {0x4004, 0x02}, 473a8df5af6SJacopo Mondi {0x4000, 0x09}, 474a8df5af6SJacopo Mondi {0x3000, 0x00}, 475a8df5af6SJacopo Mondi {0x3001, 0x00}, 476a8df5af6SJacopo Mondi {0x3002, 0x00}, 477a8df5af6SJacopo Mondi {0x3017, 0xe0}, 478a8df5af6SJacopo Mondi {0x301c, 0xfc}, 479a8df5af6SJacopo Mondi {0x3636, 0x06}, 480a8df5af6SJacopo Mondi {0x3016, 0x08}, 481a8df5af6SJacopo Mondi {0x3827, 0xec}, 482a8df5af6SJacopo Mondi {0x3018, 0x44}, 483a8df5af6SJacopo Mondi {0x3035, 0x21}, 484a8df5af6SJacopo Mondi {0x3106, 0xf5}, 485a8df5af6SJacopo Mondi {0x3034, 0x1a}, 486a8df5af6SJacopo Mondi {0x301c, 0xf8}, 487a8df5af6SJacopo Mondi {0x4800, 0x34}, 488a8df5af6SJacopo Mondi {0x3503, 0x03}, 489a8df5af6SJacopo Mondi {0x0100, 0x01}, 490a8df5af6SJacopo Mondi }; 491a8df5af6SJacopo Mondi 492*38c22308SJacopo Mondi static const struct ov5647_mode ov5647_modes[] = { 493a8df5af6SJacopo Mondi /* 2592x1944 full resolution full FOV 10-bit mode. */ 494a8df5af6SJacopo Mondi { 495a8df5af6SJacopo Mondi .format = { 496a8df5af6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR10_1X10, 497a8df5af6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 498a8df5af6SJacopo Mondi .field = V4L2_FIELD_NONE, 499a8df5af6SJacopo Mondi .width = 2592, 500a8df5af6SJacopo Mondi .height = 1944 501a8df5af6SJacopo Mondi }, 502a8df5af6SJacopo Mondi .crop = { 503a8df5af6SJacopo Mondi .left = OV5647_PIXEL_ARRAY_LEFT, 504a8df5af6SJacopo Mondi .top = OV5647_PIXEL_ARRAY_TOP, 505a8df5af6SJacopo Mondi .width = 2592, 506a8df5af6SJacopo Mondi .height = 1944 507a8df5af6SJacopo Mondi }, 508911f4516SDave Stevenson .pixel_rate = 87500000, 509c6da1ae4SJacopo Mondi .hts = 2844, 5102512c064SDave Stevenson .vts = 0x7b0, 511a8df5af6SJacopo Mondi .reg_list = ov5647_2592x1944_10bpp, 512a8df5af6SJacopo Mondi .num_regs = ARRAY_SIZE(ov5647_2592x1944_10bpp) 513a8df5af6SJacopo Mondi }, 514a8df5af6SJacopo Mondi /* 1080p30 10-bit mode. Full resolution centre-cropped down to 1080p. */ 515a8df5af6SJacopo Mondi { 516a8df5af6SJacopo Mondi .format = { 517a8df5af6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR10_1X10, 518a8df5af6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 519a8df5af6SJacopo Mondi .field = V4L2_FIELD_NONE, 520a8df5af6SJacopo Mondi .width = 1920, 521a8df5af6SJacopo Mondi .height = 1080 522a8df5af6SJacopo Mondi }, 523a8df5af6SJacopo Mondi .crop = { 524a8df5af6SJacopo Mondi .left = 348 + OV5647_PIXEL_ARRAY_LEFT, 525a8df5af6SJacopo Mondi .top = 434 + OV5647_PIXEL_ARRAY_TOP, 526a8df5af6SJacopo Mondi .width = 1928, 527a8df5af6SJacopo Mondi .height = 1080, 528a8df5af6SJacopo Mondi }, 529911f4516SDave Stevenson .pixel_rate = 81666700, 530c6da1ae4SJacopo Mondi .hts = 2416, 5312512c064SDave Stevenson .vts = 0x450, 532a8df5af6SJacopo Mondi .reg_list = ov5647_1080p30_10bpp, 533a8df5af6SJacopo Mondi .num_regs = ARRAY_SIZE(ov5647_1080p30_10bpp) 534a8df5af6SJacopo Mondi }, 535a8df5af6SJacopo Mondi /* 2x2 binned full FOV 10-bit mode. */ 536a8df5af6SJacopo Mondi { 537a8df5af6SJacopo Mondi .format = { 538a8df5af6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR10_1X10, 539a8df5af6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 540a8df5af6SJacopo Mondi .field = V4L2_FIELD_NONE, 541a8df5af6SJacopo Mondi .width = 1296, 542a8df5af6SJacopo Mondi .height = 972 543a8df5af6SJacopo Mondi }, 544a8df5af6SJacopo Mondi .crop = { 545a8df5af6SJacopo Mondi .left = OV5647_PIXEL_ARRAY_LEFT, 546a8df5af6SJacopo Mondi .top = OV5647_PIXEL_ARRAY_TOP, 547a8df5af6SJacopo Mondi .width = 2592, 548a8df5af6SJacopo Mondi .height = 1944, 549a8df5af6SJacopo Mondi }, 550911f4516SDave Stevenson .pixel_rate = 81666700, 551c6da1ae4SJacopo Mondi .hts = 1896, 5522512c064SDave Stevenson .vts = 0x59b, 553a8df5af6SJacopo Mondi .reg_list = ov5647_2x2binned_10bpp, 554a8df5af6SJacopo Mondi .num_regs = ARRAY_SIZE(ov5647_2x2binned_10bpp) 555a8df5af6SJacopo Mondi }, 556a8df5af6SJacopo Mondi /* 10-bit VGA full FOV 60fps. 2x2 binned and subsampled down to VGA. */ 557a8df5af6SJacopo Mondi { 558a8df5af6SJacopo Mondi .format = { 559a8df5af6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR10_1X10, 560a8df5af6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 561a8df5af6SJacopo Mondi .field = V4L2_FIELD_NONE, 562a8df5af6SJacopo Mondi .width = 640, 563a8df5af6SJacopo Mondi .height = 480 564a8df5af6SJacopo Mondi }, 565a8df5af6SJacopo Mondi .crop = { 566a8df5af6SJacopo Mondi .left = 16 + OV5647_PIXEL_ARRAY_LEFT, 567a8df5af6SJacopo Mondi .top = OV5647_PIXEL_ARRAY_TOP, 568a8df5af6SJacopo Mondi .width = 2560, 569a8df5af6SJacopo Mondi .height = 1920, 570a8df5af6SJacopo Mondi }, 571911f4516SDave Stevenson .pixel_rate = 55000000, 572c6da1ae4SJacopo Mondi .hts = 1852, 5732512c064SDave Stevenson .vts = 0x1f8, 574a8df5af6SJacopo Mondi .reg_list = ov5647_640x480_10bpp, 575a8df5af6SJacopo Mondi .num_regs = ARRAY_SIZE(ov5647_640x480_10bpp) 576a8df5af6SJacopo Mondi }, 577a8df5af6SJacopo Mondi }; 578a8df5af6SJacopo Mondi 57987576ac6SJacopo Mondi /* Default sensor mode is 2x2 binned 640x480 SBGGR10_1X10. */ 580*38c22308SJacopo Mondi #define OV5647_DEFAULT_MODE (&ov5647_modes[3]) 581*38c22308SJacopo Mondi #define OV5647_DEFAULT_FORMAT (ov5647_modes[3].format) 582d7d6074eSJacopo Mondi 5832512c064SDave Stevenson static int ov5647_write16(struct v4l2_subdev *sd, u16 reg, u16 val) 5842512c064SDave Stevenson { 5852512c064SDave Stevenson unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff}; 5862512c064SDave Stevenson struct i2c_client *client = v4l2_get_subdevdata(sd); 5872512c064SDave Stevenson int ret; 5882512c064SDave Stevenson 5892512c064SDave Stevenson ret = i2c_master_send(client, data, 4); 5902512c064SDave Stevenson if (ret < 0) { 5912512c064SDave Stevenson dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", 5922512c064SDave Stevenson __func__, reg); 5932512c064SDave Stevenson return ret; 5942512c064SDave Stevenson } 5952512c064SDave Stevenson 5962512c064SDave Stevenson return 0; 5972512c064SDave Stevenson } 5982512c064SDave Stevenson 5993c2472a3SRamiro Oliveira static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) 6003c2472a3SRamiro Oliveira { 6013c2472a3SRamiro Oliveira unsigned char data[3] = { reg >> 8, reg & 0xff, val}; 6023c2472a3SRamiro Oliveira struct i2c_client *client = v4l2_get_subdevdata(sd); 603c9a05cecSJacopo Mondi int ret; 6043c2472a3SRamiro Oliveira 6053c2472a3SRamiro Oliveira ret = i2c_master_send(client, data, 3); 6062b18cbcfSJacopo Mondi if (ret < 0) { 6073c2472a3SRamiro Oliveira dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", 6083c2472a3SRamiro Oliveira __func__, reg); 6093c2472a3SRamiro Oliveira return ret; 6103c2472a3SRamiro Oliveira } 6113c2472a3SRamiro Oliveira 6122b18cbcfSJacopo Mondi return 0; 6132b18cbcfSJacopo Mondi } 6142b18cbcfSJacopo Mondi 6153c2472a3SRamiro Oliveira static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val) 6163c2472a3SRamiro Oliveira { 6173c2472a3SRamiro Oliveira unsigned char data_w[2] = { reg >> 8, reg & 0xff }; 6183c2472a3SRamiro Oliveira struct i2c_client *client = v4l2_get_subdevdata(sd); 619c9a05cecSJacopo Mondi int ret; 6203c2472a3SRamiro Oliveira 6213c2472a3SRamiro Oliveira ret = i2c_master_send(client, data_w, 2); 6223c2472a3SRamiro Oliveira if (ret < 0) { 6233c2472a3SRamiro Oliveira dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", 6243c2472a3SRamiro Oliveira __func__, reg); 6253c2472a3SRamiro Oliveira return ret; 6263c2472a3SRamiro Oliveira } 6273c2472a3SRamiro Oliveira 6283c2472a3SRamiro Oliveira ret = i2c_master_recv(client, val, 1); 6292b18cbcfSJacopo Mondi if (ret < 0) { 6303c2472a3SRamiro Oliveira dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n", 6313c2472a3SRamiro Oliveira __func__, reg); 6323c2472a3SRamiro Oliveira return ret; 6333c2472a3SRamiro Oliveira } 6343c2472a3SRamiro Oliveira 6352b18cbcfSJacopo Mondi return 0; 6362b18cbcfSJacopo Mondi } 6372b18cbcfSJacopo Mondi 6383c2472a3SRamiro Oliveira static int ov5647_write_array(struct v4l2_subdev *sd, 639d7d6074eSJacopo Mondi const struct regval_list *regs, int array_size) 6403c2472a3SRamiro Oliveira { 6413c2472a3SRamiro Oliveira int i, ret; 6423c2472a3SRamiro Oliveira 6433c2472a3SRamiro Oliveira for (i = 0; i < array_size; i++) { 6443c2472a3SRamiro Oliveira ret = ov5647_write(sd, regs[i].addr, regs[i].data); 6453c2472a3SRamiro Oliveira if (ret < 0) 6463c2472a3SRamiro Oliveira return ret; 6473c2472a3SRamiro Oliveira } 6483c2472a3SRamiro Oliveira 6493c2472a3SRamiro Oliveira return 0; 6503c2472a3SRamiro Oliveira } 6513c2472a3SRamiro Oliveira 6523c2472a3SRamiro Oliveira static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel) 6533c2472a3SRamiro Oliveira { 6543c2472a3SRamiro Oliveira u8 channel_id; 6553c2472a3SRamiro Oliveira int ret; 6563c2472a3SRamiro Oliveira 657cef66734SJacob Chen ret = ov5647_read(sd, OV5647_REG_MIPI_CTRL14, &channel_id); 6583c2472a3SRamiro Oliveira if (ret < 0) 6593c2472a3SRamiro Oliveira return ret; 6603c2472a3SRamiro Oliveira 6613c2472a3SRamiro Oliveira channel_id &= ~(3 << 6); 662c9a05cecSJacopo Mondi 663c9a05cecSJacopo Mondi return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, 664c9a05cecSJacopo Mondi channel_id | (channel << 6)); 6653c2472a3SRamiro Oliveira } 6663c2472a3SRamiro Oliveira 667f7a70f9aSJacopo Mondi static int ov5647_set_mode(struct v4l2_subdev *sd) 668f7a70f9aSJacopo Mondi { 669f7a70f9aSJacopo Mondi struct i2c_client *client = v4l2_get_subdevdata(sd); 670d7d6074eSJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 671f7a70f9aSJacopo Mondi u8 resetval, rdval; 672f7a70f9aSJacopo Mondi int ret; 673f7a70f9aSJacopo Mondi 674f7a70f9aSJacopo Mondi ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval); 675f7a70f9aSJacopo Mondi if (ret < 0) 676f7a70f9aSJacopo Mondi return ret; 677f7a70f9aSJacopo Mondi 678d7d6074eSJacopo Mondi ret = ov5647_write_array(sd, sensor->mode->reg_list, 679d7d6074eSJacopo Mondi sensor->mode->num_regs); 680f7a70f9aSJacopo Mondi if (ret < 0) { 681f7a70f9aSJacopo Mondi dev_err(&client->dev, "write sensor default regs error\n"); 682f7a70f9aSJacopo Mondi return ret; 683f7a70f9aSJacopo Mondi } 684f7a70f9aSJacopo Mondi 685f7a70f9aSJacopo Mondi ret = ov5647_set_virtual_channel(sd, 0); 686f7a70f9aSJacopo Mondi if (ret < 0) 687f7a70f9aSJacopo Mondi return ret; 688f7a70f9aSJacopo Mondi 689f7a70f9aSJacopo Mondi ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval); 690f7a70f9aSJacopo Mondi if (ret < 0) 691f7a70f9aSJacopo Mondi return ret; 692f7a70f9aSJacopo Mondi 693f7a70f9aSJacopo Mondi if (!(resetval & 0x01)) { 694f7a70f9aSJacopo Mondi dev_err(&client->dev, "Device was in SW standby"); 695f7a70f9aSJacopo Mondi ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01); 696f7a70f9aSJacopo Mondi if (ret < 0) 697f7a70f9aSJacopo Mondi return ret; 698f7a70f9aSJacopo Mondi } 699f7a70f9aSJacopo Mondi 700f7a70f9aSJacopo Mondi return 0; 701f7a70f9aSJacopo Mondi } 702f7a70f9aSJacopo Mondi 7033c2472a3SRamiro Oliveira static int ov5647_stream_on(struct v4l2_subdev *sd) 7043c2472a3SRamiro Oliveira { 705f7a70f9aSJacopo Mondi struct i2c_client *client = v4l2_get_subdevdata(sd); 7065bc5ca71SJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 707dea4fcfeSDave Stevenson u8 val = MIPI_CTRL00_BUS_IDLE; 7083c2472a3SRamiro Oliveira int ret; 7093c2472a3SRamiro Oliveira 710f7a70f9aSJacopo Mondi ret = ov5647_set_mode(sd); 711f7a70f9aSJacopo Mondi if (ret) { 712f7a70f9aSJacopo Mondi dev_err(&client->dev, "Failed to program sensor mode: %d\n", ret); 713f7a70f9aSJacopo Mondi return ret; 714f7a70f9aSJacopo Mondi } 715f7a70f9aSJacopo Mondi 7164974c2f1SDavid Plowman /* Apply customized values from user when stream starts. */ 7174974c2f1SDavid Plowman ret = __v4l2_ctrl_handler_setup(sd->ctrl_handler); 7184974c2f1SDavid Plowman if (ret) 7194974c2f1SDavid Plowman return ret; 7204974c2f1SDavid Plowman 7215bc5ca71SJacopo Mondi if (sensor->clock_ncont) 722dea4fcfeSDave Stevenson val |= MIPI_CTRL00_CLOCK_LANE_GATE | 723dea4fcfeSDave Stevenson MIPI_CTRL00_LINE_SYNC_ENABLE; 724dea4fcfeSDave Stevenson 725dea4fcfeSDave Stevenson ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val); 7267bc9f038SJacob Chen if (ret < 0) 7277bc9f038SJacob Chen return ret; 7287bc9f038SJacob Chen 729cef66734SJacob Chen ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x00); 7303c2472a3SRamiro Oliveira if (ret < 0) 7313c2472a3SRamiro Oliveira return ret; 7323c2472a3SRamiro Oliveira 733cef66734SJacob Chen return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x00); 7343c2472a3SRamiro Oliveira } 7353c2472a3SRamiro Oliveira 7363c2472a3SRamiro Oliveira static int ov5647_stream_off(struct v4l2_subdev *sd) 7373c2472a3SRamiro Oliveira { 7383c2472a3SRamiro Oliveira int ret; 7393c2472a3SRamiro Oliveira 740c9a05cecSJacopo Mondi ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, 741c9a05cecSJacopo Mondi MIPI_CTRL00_CLOCK_LANE_GATE | MIPI_CTRL00_BUS_IDLE | 742c9a05cecSJacopo Mondi MIPI_CTRL00_CLOCK_LANE_DISABLE); 7437bc9f038SJacob Chen if (ret < 0) 7447bc9f038SJacob Chen return ret; 7457bc9f038SJacob Chen 746cef66734SJacob Chen ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x0f); 7473c2472a3SRamiro Oliveira if (ret < 0) 7483c2472a3SRamiro Oliveira return ret; 7493c2472a3SRamiro Oliveira 750cef66734SJacob Chen return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01); 7513c2472a3SRamiro Oliveira } 7523c2472a3SRamiro Oliveira 753089b7c70SJacopo Mondi static int ov5647_power_on(struct device *dev) 7543c2472a3SRamiro Oliveira { 755089b7c70SJacopo Mondi struct ov5647 *sensor = dev_get_drvdata(dev); 7563c2472a3SRamiro Oliveira int ret; 7573c2472a3SRamiro Oliveira 758089b7c70SJacopo Mondi dev_dbg(dev, "OV5647 power on\n"); 7593c2472a3SRamiro Oliveira 7605bc5ca71SJacopo Mondi if (sensor->pwdn) { 7615bc5ca71SJacopo Mondi gpiod_set_value_cansleep(sensor->pwdn, 0); 762b050791dSDave Stevenson msleep(PWDN_ACTIVE_DELAY_MS); 763b050791dSDave Stevenson } 764b050791dSDave Stevenson 7655bc5ca71SJacopo Mondi ret = clk_prepare_enable(sensor->xclk); 7663c2472a3SRamiro Oliveira if (ret < 0) { 767089b7c70SJacopo Mondi dev_err(dev, "clk prepare enable failed\n"); 768089b7c70SJacopo Mondi goto error_pwdn; 7693c2472a3SRamiro Oliveira } 7703c2472a3SRamiro Oliveira 771089b7c70SJacopo Mondi ret = ov5647_write_array(&sensor->sd, sensor_oe_enable_regs, 7723c2472a3SRamiro Oliveira ARRAY_SIZE(sensor_oe_enable_regs)); 7733c2472a3SRamiro Oliveira if (ret < 0) { 774089b7c70SJacopo Mondi dev_err(dev, "write sensor_oe_enable_regs error\n"); 775089b7c70SJacopo Mondi goto error_clk_disable; 7763c2472a3SRamiro Oliveira } 7773c2472a3SRamiro Oliveira 778f7a70f9aSJacopo Mondi /* Stream off to coax lanes into LP-11 state. */ 779089b7c70SJacopo Mondi ret = ov5647_stream_off(&sensor->sd); 7803c2472a3SRamiro Oliveira if (ret < 0) { 781089b7c70SJacopo Mondi dev_err(dev, "camera not available, check power\n"); 782089b7c70SJacopo Mondi goto error_clk_disable; 7833c2472a3SRamiro Oliveira } 7843c2472a3SRamiro Oliveira 785089b7c70SJacopo Mondi return 0; 786089b7c70SJacopo Mondi 787089b7c70SJacopo Mondi error_clk_disable: 788089b7c70SJacopo Mondi clk_disable_unprepare(sensor->xclk); 789089b7c70SJacopo Mondi error_pwdn: 790089b7c70SJacopo Mondi gpiod_set_value_cansleep(sensor->pwdn, 1); 791089b7c70SJacopo Mondi 792089b7c70SJacopo Mondi return ret; 793089b7c70SJacopo Mondi } 794089b7c70SJacopo Mondi 795089b7c70SJacopo Mondi static int ov5647_power_off(struct device *dev) 796089b7c70SJacopo Mondi { 797089b7c70SJacopo Mondi struct ov5647 *sensor = dev_get_drvdata(dev); 798089b7c70SJacopo Mondi u8 rdval; 799089b7c70SJacopo Mondi int ret; 800089b7c70SJacopo Mondi 801089b7c70SJacopo Mondi dev_dbg(dev, "OV5647 power off\n"); 802089b7c70SJacopo Mondi 803089b7c70SJacopo Mondi ret = ov5647_write_array(&sensor->sd, sensor_oe_disable_regs, 8043c2472a3SRamiro Oliveira ARRAY_SIZE(sensor_oe_disable_regs)); 8053c2472a3SRamiro Oliveira if (ret < 0) 806089b7c70SJacopo Mondi dev_dbg(dev, "disable oe failed\n"); 8073c2472a3SRamiro Oliveira 808089b7c70SJacopo Mondi /* Enter software standby */ 809089b7c70SJacopo Mondi ret = ov5647_read(&sensor->sd, OV5647_SW_STANDBY, &rdval); 8103c2472a3SRamiro Oliveira if (ret < 0) 811089b7c70SJacopo Mondi dev_dbg(dev, "software standby failed\n"); 812089b7c70SJacopo Mondi 813089b7c70SJacopo Mondi rdval &= ~0x01; 814089b7c70SJacopo Mondi ret = ov5647_write(&sensor->sd, OV5647_SW_STANDBY, rdval); 815089b7c70SJacopo Mondi if (ret < 0) 816089b7c70SJacopo Mondi dev_dbg(dev, "software standby failed\n"); 8173c2472a3SRamiro Oliveira 8185bc5ca71SJacopo Mondi clk_disable_unprepare(sensor->xclk); 8195bc5ca71SJacopo Mondi gpiod_set_value_cansleep(sensor->pwdn, 1); 8203c2472a3SRamiro Oliveira 821089b7c70SJacopo Mondi return 0; 8223c2472a3SRamiro Oliveira } 8233c2472a3SRamiro Oliveira 8243c2472a3SRamiro Oliveira #ifdef CONFIG_VIDEO_ADV_DEBUG 8253c2472a3SRamiro Oliveira static int ov5647_sensor_get_register(struct v4l2_subdev *sd, 8263c2472a3SRamiro Oliveira struct v4l2_dbg_register *reg) 8273c2472a3SRamiro Oliveira { 8283c2472a3SRamiro Oliveira int ret; 829c9a05cecSJacopo Mondi u8 val; 8303c2472a3SRamiro Oliveira 8313c2472a3SRamiro Oliveira ret = ov5647_read(sd, reg->reg & 0xff, &val); 8323c2472a3SRamiro Oliveira if (ret < 0) 8333c2472a3SRamiro Oliveira return ret; 8343c2472a3SRamiro Oliveira 8353c2472a3SRamiro Oliveira reg->val = val; 8363c2472a3SRamiro Oliveira reg->size = 1; 8373c2472a3SRamiro Oliveira 8383c2472a3SRamiro Oliveira return 0; 8393c2472a3SRamiro Oliveira } 8403c2472a3SRamiro Oliveira 8413c2472a3SRamiro Oliveira static int ov5647_sensor_set_register(struct v4l2_subdev *sd, 8423c2472a3SRamiro Oliveira const struct v4l2_dbg_register *reg) 8433c2472a3SRamiro Oliveira { 8443c2472a3SRamiro Oliveira return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff); 8453c2472a3SRamiro Oliveira } 8463c2472a3SRamiro Oliveira #endif 8473c2472a3SRamiro Oliveira 848c9a05cecSJacopo Mondi /* Subdev core operations registration */ 8493c2472a3SRamiro Oliveira static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { 850dc337308SJacopo Mondi .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 851dc337308SJacopo Mondi .unsubscribe_event = v4l2_event_subdev_unsubscribe, 8523c2472a3SRamiro Oliveira #ifdef CONFIG_VIDEO_ADV_DEBUG 8533c2472a3SRamiro Oliveira .g_register = ov5647_sensor_get_register, 8543c2472a3SRamiro Oliveira .s_register = ov5647_sensor_set_register, 8553c2472a3SRamiro Oliveira #endif 8563c2472a3SRamiro Oliveira }; 8573c2472a3SRamiro Oliveira 85814f70a32SDave Stevenson static const struct v4l2_rect * 85914f70a32SDave Stevenson __ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg, 86014f70a32SDave Stevenson unsigned int pad, enum v4l2_subdev_format_whence which) 86114f70a32SDave Stevenson { 86214f70a32SDave Stevenson switch (which) { 86314f70a32SDave Stevenson case V4L2_SUBDEV_FORMAT_TRY: 86414f70a32SDave Stevenson return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad); 86514f70a32SDave Stevenson case V4L2_SUBDEV_FORMAT_ACTIVE: 86614f70a32SDave Stevenson return &ov5647->mode->crop; 86714f70a32SDave Stevenson } 86814f70a32SDave Stevenson 86914f70a32SDave Stevenson return NULL; 87014f70a32SDave Stevenson } 87114f70a32SDave Stevenson 8723c2472a3SRamiro Oliveira static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) 8733c2472a3SRamiro Oliveira { 8742f038c97SJacopo Mondi struct i2c_client *client = v4l2_get_subdevdata(sd); 8755bc5ca71SJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 876ab614f27SJacopo Mondi int ret; 877ab614f27SJacopo Mondi 878ab614f27SJacopo Mondi mutex_lock(&sensor->lock); 8792f038c97SJacopo Mondi if (sensor->streaming == enable) { 8802f038c97SJacopo Mondi mutex_unlock(&sensor->lock); 8812f038c97SJacopo Mondi return 0; 8822f038c97SJacopo Mondi } 8832f038c97SJacopo Mondi 8842f038c97SJacopo Mondi if (enable) { 8852f038c97SJacopo Mondi ret = pm_runtime_get_sync(&client->dev); 8862f038c97SJacopo Mondi if (ret < 0) 8872f038c97SJacopo Mondi goto error_unlock; 8882f038c97SJacopo Mondi 889ab614f27SJacopo Mondi ret = ov5647_stream_on(sd); 8902f038c97SJacopo Mondi if (ret < 0) { 8912f038c97SJacopo Mondi dev_err(&client->dev, "stream start failed: %d\n", ret); 8922f038c97SJacopo Mondi goto error_unlock; 8932f038c97SJacopo Mondi } 8942f038c97SJacopo Mondi } else { 895ab614f27SJacopo Mondi ret = ov5647_stream_off(sd); 8962f038c97SJacopo Mondi if (ret < 0) { 8972f038c97SJacopo Mondi dev_err(&client->dev, "stream stop failed: %d\n", ret); 8982f038c97SJacopo Mondi goto error_unlock; 8992f038c97SJacopo Mondi } 9002f038c97SJacopo Mondi pm_runtime_put(&client->dev); 9012f038c97SJacopo Mondi } 9022f038c97SJacopo Mondi 9032f038c97SJacopo Mondi sensor->streaming = enable; 9042f038c97SJacopo Mondi mutex_unlock(&sensor->lock); 9052f038c97SJacopo Mondi 9062f038c97SJacopo Mondi return 0; 9072f038c97SJacopo Mondi 9082f038c97SJacopo Mondi error_unlock: 9092f038c97SJacopo Mondi pm_runtime_put(&client->dev); 910ab614f27SJacopo Mondi mutex_unlock(&sensor->lock); 911ab614f27SJacopo Mondi 912ab614f27SJacopo Mondi return ret; 9133c2472a3SRamiro Oliveira } 9143c2472a3SRamiro Oliveira 9153c2472a3SRamiro Oliveira static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { 9163c2472a3SRamiro Oliveira .s_stream = ov5647_s_stream, 9173c2472a3SRamiro Oliveira }; 9183c2472a3SRamiro Oliveira 9193c2472a3SRamiro Oliveira static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, 9203c2472a3SRamiro Oliveira struct v4l2_subdev_pad_config *cfg, 9213c2472a3SRamiro Oliveira struct v4l2_subdev_mbus_code_enum *code) 9223c2472a3SRamiro Oliveira { 923*38c22308SJacopo Mondi if (code->index > 0) 9243c2472a3SRamiro Oliveira return -EINVAL; 9253c2472a3SRamiro Oliveira 926*38c22308SJacopo Mondi code->code = MEDIA_BUS_FMT_SBGGR10_1X10; 9273c2472a3SRamiro Oliveira 9283c2472a3SRamiro Oliveira return 0; 9293c2472a3SRamiro Oliveira } 9303c2472a3SRamiro Oliveira 931464090c0SJacopo Mondi static int ov5647_enum_frame_size(struct v4l2_subdev *sd, 932464090c0SJacopo Mondi struct v4l2_subdev_pad_config *cfg, 933464090c0SJacopo Mondi struct v4l2_subdev_frame_size_enum *fse) 934464090c0SJacopo Mondi { 935d7d6074eSJacopo Mondi const struct v4l2_mbus_framefmt *fmt; 936d7d6074eSJacopo Mondi 937*38c22308SJacopo Mondi if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10 || 938*38c22308SJacopo Mondi fse->index >= ARRAY_SIZE(ov5647_modes)) 939464090c0SJacopo Mondi return -EINVAL; 940464090c0SJacopo Mondi 941*38c22308SJacopo Mondi fmt = &ov5647_modes[fse->index].format; 942d7d6074eSJacopo Mondi fse->min_width = fmt->width; 943d7d6074eSJacopo Mondi fse->max_width = fmt->width; 944d7d6074eSJacopo Mondi fse->min_height = fmt->height; 945d7d6074eSJacopo Mondi fse->max_height = fmt->height; 946464090c0SJacopo Mondi 947464090c0SJacopo Mondi return 0; 948464090c0SJacopo Mondi } 949464090c0SJacopo Mondi 9506869e971SJacopo Mondi static int ov5647_get_pad_fmt(struct v4l2_subdev *sd, 9510f87233aSDave Stevenson struct v4l2_subdev_pad_config *cfg, 9520f87233aSDave Stevenson struct v4l2_subdev_format *format) 9530f87233aSDave Stevenson { 9540f87233aSDave Stevenson struct v4l2_mbus_framefmt *fmt = &format->format; 9556869e971SJacopo Mondi const struct v4l2_mbus_framefmt *sensor_format; 9566869e971SJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 9570f87233aSDave Stevenson 9586869e971SJacopo Mondi mutex_lock(&sensor->lock); 9596869e971SJacopo Mondi switch (format->which) { 9606869e971SJacopo Mondi case V4L2_SUBDEV_FORMAT_TRY: 9616869e971SJacopo Mondi sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad); 9626869e971SJacopo Mondi break; 9636869e971SJacopo Mondi default: 9646869e971SJacopo Mondi sensor_format = &sensor->mode->format; 9656869e971SJacopo Mondi break; 9666869e971SJacopo Mondi } 9676869e971SJacopo Mondi 9686869e971SJacopo Mondi *fmt = *sensor_format; 9696869e971SJacopo Mondi mutex_unlock(&sensor->lock); 9706869e971SJacopo Mondi 9716869e971SJacopo Mondi return 0; 9726869e971SJacopo Mondi } 9736869e971SJacopo Mondi 9746869e971SJacopo Mondi static int ov5647_set_pad_fmt(struct v4l2_subdev *sd, 9756869e971SJacopo Mondi struct v4l2_subdev_pad_config *cfg, 9766869e971SJacopo Mondi struct v4l2_subdev_format *format) 9776869e971SJacopo Mondi { 9786869e971SJacopo Mondi struct v4l2_mbus_framefmt *fmt = &format->format; 9796869e971SJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 9806869e971SJacopo Mondi const struct ov5647_mode *mode; 9816869e971SJacopo Mondi 982*38c22308SJacopo Mondi mode = v4l2_find_nearest_size(ov5647_modes, ARRAY_SIZE(ov5647_modes), 9836869e971SJacopo Mondi format.width, format.height, 9846869e971SJacopo Mondi fmt->width, fmt->height); 9856869e971SJacopo Mondi 9866869e971SJacopo Mondi /* Update the sensor mode and apply at it at streamon time. */ 9876869e971SJacopo Mondi mutex_lock(&sensor->lock); 988911f4516SDave Stevenson if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 9896869e971SJacopo Mondi *v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format; 990911f4516SDave Stevenson } else { 991646a0249SDave Stevenson int exposure_max, exposure_def; 9922512c064SDave Stevenson int hblank, vblank; 993c6da1ae4SJacopo Mondi 9946869e971SJacopo Mondi sensor->mode = mode; 995911f4516SDave Stevenson __v4l2_ctrl_modify_range(sensor->pixel_rate, mode->pixel_rate, 996911f4516SDave Stevenson mode->pixel_rate, 1, mode->pixel_rate); 997c6da1ae4SJacopo Mondi 998c6da1ae4SJacopo Mondi hblank = mode->hts - mode->format.width; 999c6da1ae4SJacopo Mondi __v4l2_ctrl_modify_range(sensor->hblank, hblank, hblank, 1, 1000c6da1ae4SJacopo Mondi hblank); 10012512c064SDave Stevenson 10022512c064SDave Stevenson vblank = mode->vts - mode->format.height; 10032512c064SDave Stevenson __v4l2_ctrl_modify_range(sensor->vblank, OV5647_VBLANK_MIN, 10042512c064SDave Stevenson OV5647_VTS_MAX - mode->format.height, 10052512c064SDave Stevenson 1, vblank); 10062512c064SDave Stevenson __v4l2_ctrl_s_ctrl(sensor->vblank, vblank); 1007646a0249SDave Stevenson 1008646a0249SDave Stevenson exposure_max = mode->vts - 4; 1009646a0249SDave Stevenson exposure_def = min(exposure_max, OV5647_EXPOSURE_DEFAULT); 1010646a0249SDave Stevenson __v4l2_ctrl_modify_range(sensor->exposure, 1011646a0249SDave Stevenson sensor->exposure->minimum, 1012646a0249SDave Stevenson exposure_max, sensor->exposure->step, 1013646a0249SDave Stevenson exposure_def); 1014911f4516SDave Stevenson } 10156869e971SJacopo Mondi *fmt = mode->format; 10166869e971SJacopo Mondi mutex_unlock(&sensor->lock); 10170f87233aSDave Stevenson 10180f87233aSDave Stevenson return 0; 10190f87233aSDave Stevenson } 10200f87233aSDave Stevenson 102114f70a32SDave Stevenson static int ov5647_get_selection(struct v4l2_subdev *sd, 102214f70a32SDave Stevenson struct v4l2_subdev_pad_config *cfg, 102314f70a32SDave Stevenson struct v4l2_subdev_selection *sel) 102414f70a32SDave Stevenson { 102514f70a32SDave Stevenson switch (sel->target) { 102614f70a32SDave Stevenson case V4L2_SEL_TGT_CROP: { 102714f70a32SDave Stevenson struct ov5647 *sensor = to_sensor(sd); 102814f70a32SDave Stevenson 102914f70a32SDave Stevenson mutex_lock(&sensor->lock); 103014f70a32SDave Stevenson sel->r = *__ov5647_get_pad_crop(sensor, cfg, sel->pad, 103114f70a32SDave Stevenson sel->which); 103214f70a32SDave Stevenson mutex_unlock(&sensor->lock); 103314f70a32SDave Stevenson 103414f70a32SDave Stevenson return 0; 103514f70a32SDave Stevenson } 103614f70a32SDave Stevenson 103714f70a32SDave Stevenson case V4L2_SEL_TGT_NATIVE_SIZE: 103814f70a32SDave Stevenson sel->r.top = 0; 103914f70a32SDave Stevenson sel->r.left = 0; 104014f70a32SDave Stevenson sel->r.width = OV5647_NATIVE_WIDTH; 104114f70a32SDave Stevenson sel->r.height = OV5647_NATIVE_HEIGHT; 104214f70a32SDave Stevenson 104314f70a32SDave Stevenson return 0; 104414f70a32SDave Stevenson 104514f70a32SDave Stevenson case V4L2_SEL_TGT_CROP_DEFAULT: 104614f70a32SDave Stevenson case V4L2_SEL_TGT_CROP_BOUNDS: 104714f70a32SDave Stevenson sel->r.top = OV5647_PIXEL_ARRAY_TOP; 104814f70a32SDave Stevenson sel->r.left = OV5647_PIXEL_ARRAY_LEFT; 104914f70a32SDave Stevenson sel->r.width = OV5647_PIXEL_ARRAY_WIDTH; 105014f70a32SDave Stevenson sel->r.height = OV5647_PIXEL_ARRAY_HEIGHT; 105114f70a32SDave Stevenson 105214f70a32SDave Stevenson return 0; 105314f70a32SDave Stevenson } 105414f70a32SDave Stevenson 105514f70a32SDave Stevenson return -EINVAL; 105614f70a32SDave Stevenson } 105714f70a32SDave Stevenson 10583c2472a3SRamiro Oliveira static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { 10593c2472a3SRamiro Oliveira .enum_mbus_code = ov5647_enum_mbus_code, 1060464090c0SJacopo Mondi .enum_frame_size = ov5647_enum_frame_size, 10616869e971SJacopo Mondi .set_fmt = ov5647_set_pad_fmt, 10626869e971SJacopo Mondi .get_fmt = ov5647_get_pad_fmt, 106314f70a32SDave Stevenson .get_selection = ov5647_get_selection, 10643c2472a3SRamiro Oliveira }; 10653c2472a3SRamiro Oliveira 10663c2472a3SRamiro Oliveira static const struct v4l2_subdev_ops ov5647_subdev_ops = { 10673c2472a3SRamiro Oliveira .core = &ov5647_subdev_core_ops, 10683c2472a3SRamiro Oliveira .video = &ov5647_subdev_video_ops, 10693c2472a3SRamiro Oliveira .pad = &ov5647_subdev_pad_ops, 10703c2472a3SRamiro Oliveira }; 10713c2472a3SRamiro Oliveira 10723c2472a3SRamiro Oliveira static int ov5647_detect(struct v4l2_subdev *sd) 10733c2472a3SRamiro Oliveira { 1074c9a05cecSJacopo Mondi struct i2c_client *client = v4l2_get_subdevdata(sd); 10753c2472a3SRamiro Oliveira u8 read; 10763c2472a3SRamiro Oliveira int ret; 10773c2472a3SRamiro Oliveira 10783c2472a3SRamiro Oliveira ret = ov5647_write(sd, OV5647_SW_RESET, 0x01); 10793c2472a3SRamiro Oliveira if (ret < 0) 10803c2472a3SRamiro Oliveira return ret; 10813c2472a3SRamiro Oliveira 10823c2472a3SRamiro Oliveira ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &read); 10833c2472a3SRamiro Oliveira if (ret < 0) 10843c2472a3SRamiro Oliveira return ret; 10853c2472a3SRamiro Oliveira 10863c2472a3SRamiro Oliveira if (read != 0x56) { 10873c2472a3SRamiro Oliveira dev_err(&client->dev, "ID High expected 0x56 got %x", read); 10883c2472a3SRamiro Oliveira return -ENODEV; 10893c2472a3SRamiro Oliveira } 10903c2472a3SRamiro Oliveira 10913c2472a3SRamiro Oliveira ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &read); 10923c2472a3SRamiro Oliveira if (ret < 0) 10933c2472a3SRamiro Oliveira return ret; 10943c2472a3SRamiro Oliveira 10953c2472a3SRamiro Oliveira if (read != 0x47) { 10963c2472a3SRamiro Oliveira dev_err(&client->dev, "ID Low expected 0x47 got %x", read); 10973c2472a3SRamiro Oliveira return -ENODEV; 10983c2472a3SRamiro Oliveira } 10993c2472a3SRamiro Oliveira 11003c2472a3SRamiro Oliveira return ov5647_write(sd, OV5647_SW_RESET, 0x00); 11013c2472a3SRamiro Oliveira } 11023c2472a3SRamiro Oliveira 11033c2472a3SRamiro Oliveira static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 11043c2472a3SRamiro Oliveira { 11053c2472a3SRamiro Oliveira struct v4l2_mbus_framefmt *format = 11063c2472a3SRamiro Oliveira v4l2_subdev_get_try_format(sd, fh->pad, 0); 1107c9a05cecSJacopo Mondi struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0); 11083c2472a3SRamiro Oliveira 110914f70a32SDave Stevenson crop->left = OV5647_PIXEL_ARRAY_LEFT; 111014f70a32SDave Stevenson crop->top = OV5647_PIXEL_ARRAY_TOP; 111114f70a32SDave Stevenson crop->width = OV5647_PIXEL_ARRAY_WIDTH; 111214f70a32SDave Stevenson crop->height = OV5647_PIXEL_ARRAY_HEIGHT; 11133c2472a3SRamiro Oliveira 1114d7d6074eSJacopo Mondi *format = OV5647_DEFAULT_FORMAT; 11153c2472a3SRamiro Oliveira 11163c2472a3SRamiro Oliveira return 0; 11173c2472a3SRamiro Oliveira } 11183c2472a3SRamiro Oliveira 11193c2472a3SRamiro Oliveira static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = { 11203c2472a3SRamiro Oliveira .open = ov5647_open, 11213c2472a3SRamiro Oliveira }; 11223c2472a3SRamiro Oliveira 11234974c2f1SDavid Plowman static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val) 11244974c2f1SDavid Plowman { 11254974c2f1SDavid Plowman return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0); 11264974c2f1SDavid Plowman } 11274974c2f1SDavid Plowman 11284974c2f1SDavid Plowman static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val) 11294974c2f1SDavid Plowman { 11304974c2f1SDavid Plowman int ret; 11314974c2f1SDavid Plowman u8 reg; 11324974c2f1SDavid Plowman 11334974c2f1SDavid Plowman /* Non-zero turns on AGC by clearing bit 1.*/ 11344974c2f1SDavid Plowman ret = ov5647_read(sd, OV5647_REG_AEC_AGC, ®); 11354974c2f1SDavid Plowman if (ret) 11364974c2f1SDavid Plowman return ret; 11374974c2f1SDavid Plowman 11384974c2f1SDavid Plowman return ov5647_write(sd, OV5647_REG_AEC_AGC, val ? reg & ~BIT(1) 11394974c2f1SDavid Plowman : reg | BIT(1)); 11404974c2f1SDavid Plowman } 11414974c2f1SDavid Plowman 11424974c2f1SDavid Plowman static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val) 11434974c2f1SDavid Plowman { 11444974c2f1SDavid Plowman int ret; 11454974c2f1SDavid Plowman u8 reg; 11464974c2f1SDavid Plowman 11474974c2f1SDavid Plowman /* 11484974c2f1SDavid Plowman * Everything except V4L2_EXPOSURE_MANUAL turns on AEC by 11494974c2f1SDavid Plowman * clearing bit 0. 11504974c2f1SDavid Plowman */ 11514974c2f1SDavid Plowman ret = ov5647_read(sd, OV5647_REG_AEC_AGC, ®); 11524974c2f1SDavid Plowman if (ret) 11534974c2f1SDavid Plowman return ret; 11544974c2f1SDavid Plowman 11554974c2f1SDavid Plowman return ov5647_write(sd, OV5647_REG_AEC_AGC, 11564974c2f1SDavid Plowman val == V4L2_EXPOSURE_MANUAL ? reg | BIT(0) 11574974c2f1SDavid Plowman : reg & ~BIT(0)); 11584974c2f1SDavid Plowman } 11594974c2f1SDavid Plowman 11604974c2f1SDavid Plowman static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val) 11614974c2f1SDavid Plowman { 11624974c2f1SDavid Plowman int ret; 11634974c2f1SDavid Plowman 11644974c2f1SDavid Plowman /* 10 bits of gain, 2 in the high register. */ 11654974c2f1SDavid Plowman ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3); 11664974c2f1SDavid Plowman if (ret) 11674974c2f1SDavid Plowman return ret; 11684974c2f1SDavid Plowman 11694974c2f1SDavid Plowman return ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff); 11704974c2f1SDavid Plowman } 11714974c2f1SDavid Plowman 11724974c2f1SDavid Plowman static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) 11734974c2f1SDavid Plowman { 11744974c2f1SDavid Plowman int ret; 11754974c2f1SDavid Plowman 11764974c2f1SDavid Plowman /* 11774974c2f1SDavid Plowman * Sensor has 20 bits, but the bottom 4 bits are fractions of a line 11784974c2f1SDavid Plowman * which we leave as zero (and don't receive in "val"). 11794974c2f1SDavid Plowman */ 11804974c2f1SDavid Plowman ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf); 11814974c2f1SDavid Plowman if (ret) 11824974c2f1SDavid Plowman return ret; 11834974c2f1SDavid Plowman 11844974c2f1SDavid Plowman ret = ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff); 11854974c2f1SDavid Plowman if (ret) 11864974c2f1SDavid Plowman return ret; 11874974c2f1SDavid Plowman 11884974c2f1SDavid Plowman return ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4); 11894974c2f1SDavid Plowman } 11904974c2f1SDavid Plowman 11914974c2f1SDavid Plowman static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) 11924974c2f1SDavid Plowman { 11934974c2f1SDavid Plowman struct ov5647 *sensor = container_of(ctrl->handler, 11944974c2f1SDavid Plowman struct ov5647, ctrls); 11954974c2f1SDavid Plowman struct v4l2_subdev *sd = &sensor->sd; 11964974c2f1SDavid Plowman struct i2c_client *client = v4l2_get_subdevdata(sd); 11974eec1919SJacopo Mondi int ret = 0; 11984eec1919SJacopo Mondi 11994974c2f1SDavid Plowman 12004974c2f1SDavid Plowman /* v4l2_ctrl_lock() locks our own mutex */ 12014974c2f1SDavid Plowman 1202646a0249SDave Stevenson if (ctrl->id == V4L2_CID_VBLANK) { 1203646a0249SDave Stevenson int exposure_max, exposure_def; 1204646a0249SDave Stevenson 1205646a0249SDave Stevenson /* Update max exposure while meeting expected vblanking */ 1206646a0249SDave Stevenson exposure_max = sensor->mode->format.height + ctrl->val - 4; 1207646a0249SDave Stevenson exposure_def = min(exposure_max, OV5647_EXPOSURE_DEFAULT); 1208646a0249SDave Stevenson __v4l2_ctrl_modify_range(sensor->exposure, 1209646a0249SDave Stevenson sensor->exposure->minimum, 1210646a0249SDave Stevenson exposure_max, sensor->exposure->step, 1211646a0249SDave Stevenson exposure_def); 1212646a0249SDave Stevenson } 1213646a0249SDave Stevenson 12144974c2f1SDavid Plowman /* 12154eec1919SJacopo Mondi * If the device is not powered up do not apply any controls 12164eec1919SJacopo Mondi * to H/W at this time. Instead the controls will be restored 12174eec1919SJacopo Mondi * at s_stream(1) time. 12184974c2f1SDavid Plowman */ 12194eec1919SJacopo Mondi if (pm_runtime_get_if_in_use(&client->dev) == 0) 12204974c2f1SDavid Plowman return 0; 12214974c2f1SDavid Plowman 12224974c2f1SDavid Plowman switch (ctrl->id) { 12234974c2f1SDavid Plowman case V4L2_CID_AUTO_WHITE_BALANCE: 12244eec1919SJacopo Mondi ret = ov5647_s_auto_white_balance(sd, ctrl->val); 12254eec1919SJacopo Mondi break; 12264974c2f1SDavid Plowman case V4L2_CID_AUTOGAIN: 12274eec1919SJacopo Mondi ret = ov5647_s_autogain(sd, ctrl->val); 12284eec1919SJacopo Mondi break; 12294974c2f1SDavid Plowman case V4L2_CID_EXPOSURE_AUTO: 12304eec1919SJacopo Mondi ret = ov5647_s_exposure_auto(sd, ctrl->val); 12314eec1919SJacopo Mondi break; 12324974c2f1SDavid Plowman case V4L2_CID_ANALOGUE_GAIN: 12334eec1919SJacopo Mondi ret = ov5647_s_analogue_gain(sd, ctrl->val); 12344eec1919SJacopo Mondi break; 12354974c2f1SDavid Plowman case V4L2_CID_EXPOSURE: 12364eec1919SJacopo Mondi ret = ov5647_s_exposure(sd, ctrl->val); 12374eec1919SJacopo Mondi break; 12384eec1919SJacopo Mondi case V4L2_CID_VBLANK: 12394eec1919SJacopo Mondi ret = ov5647_write16(sd, OV5647_REG_VTS_HI, 12404eec1919SJacopo Mondi sensor->mode->format.height + ctrl->val); 12414eec1919SJacopo Mondi break; 12424eec1919SJacopo Mondi 1243911f4516SDave Stevenson /* Read-only, but we adjust it based on mode. */ 12444eec1919SJacopo Mondi case V4L2_CID_PIXEL_RATE: 1245c6da1ae4SJacopo Mondi case V4L2_CID_HBLANK: 1246c6da1ae4SJacopo Mondi /* Read-only, but we adjust it based on mode. */ 12474eec1919SJacopo Mondi break; 12484eec1919SJacopo Mondi 12494974c2f1SDavid Plowman default: 12504974c2f1SDavid Plowman dev_info(&client->dev, 12514974c2f1SDavid Plowman "Control (id:0x%x, val:0x%x) not supported\n", 12524974c2f1SDavid Plowman ctrl->id, ctrl->val); 12534974c2f1SDavid Plowman return -EINVAL; 12544974c2f1SDavid Plowman } 12554974c2f1SDavid Plowman 12564eec1919SJacopo Mondi pm_runtime_put(&client->dev); 12574eec1919SJacopo Mondi 12584eec1919SJacopo Mondi return ret; 12594974c2f1SDavid Plowman } 12604974c2f1SDavid Plowman 12614974c2f1SDavid Plowman static const struct v4l2_ctrl_ops ov5647_ctrl_ops = { 12624974c2f1SDavid Plowman .s_ctrl = ov5647_s_ctrl, 12634974c2f1SDavid Plowman }; 12644974c2f1SDavid Plowman 12654974c2f1SDavid Plowman static int ov5647_init_controls(struct ov5647 *sensor) 12664974c2f1SDavid Plowman { 12674974c2f1SDavid Plowman struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); 1268646a0249SDave Stevenson int hblank, exposure_max, exposure_def; 12694974c2f1SDavid Plowman 12702512c064SDave Stevenson v4l2_ctrl_handler_init(&sensor->ctrls, 8); 12714974c2f1SDavid Plowman 12724974c2f1SDavid Plowman v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 12734974c2f1SDavid Plowman V4L2_CID_AUTOGAIN, 0, 1, 1, 0); 12744974c2f1SDavid Plowman 12754974c2f1SDavid Plowman v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 12764974c2f1SDavid Plowman V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 0); 12774974c2f1SDavid Plowman 12784974c2f1SDavid Plowman v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops, 12794974c2f1SDavid Plowman V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 12804974c2f1SDavid Plowman 0, V4L2_EXPOSURE_MANUAL); 12814974c2f1SDavid Plowman 1282646a0249SDave Stevenson exposure_max = sensor->mode->vts - 4; 1283646a0249SDave Stevenson exposure_def = min(exposure_max, OV5647_EXPOSURE_DEFAULT); 1284646a0249SDave Stevenson sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 1285646a0249SDave Stevenson V4L2_CID_EXPOSURE, 1286646a0249SDave Stevenson OV5647_EXPOSURE_MIN, 1287646a0249SDave Stevenson exposure_max, OV5647_EXPOSURE_STEP, 1288646a0249SDave Stevenson exposure_def); 12894974c2f1SDavid Plowman 12904974c2f1SDavid Plowman /* min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x. */ 12914974c2f1SDavid Plowman v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 12924974c2f1SDavid Plowman V4L2_CID_ANALOGUE_GAIN, 16, 1023, 1, 32); 12934974c2f1SDavid Plowman 1294911f4516SDave Stevenson /* By default, PIXEL_RATE is read only, but it does change per mode */ 1295911f4516SDave Stevenson sensor->pixel_rate = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 1296911f4516SDave Stevenson V4L2_CID_PIXEL_RATE, 1297911f4516SDave Stevenson sensor->mode->pixel_rate, 1298911f4516SDave Stevenson sensor->mode->pixel_rate, 1, 1299911f4516SDave Stevenson sensor->mode->pixel_rate); 1300c6da1ae4SJacopo Mondi 1301c6da1ae4SJacopo Mondi /* By default, HBLANK is read only, but it does change per mode. */ 1302c6da1ae4SJacopo Mondi hblank = sensor->mode->hts - sensor->mode->format.width; 1303c6da1ae4SJacopo Mondi sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 1304c6da1ae4SJacopo Mondi V4L2_CID_HBLANK, hblank, hblank, 1, 1305c6da1ae4SJacopo Mondi hblank); 1306c6da1ae4SJacopo Mondi 13072512c064SDave Stevenson sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, 13082512c064SDave Stevenson V4L2_CID_VBLANK, OV5647_VBLANK_MIN, 13092512c064SDave Stevenson OV5647_VTS_MAX - 13102512c064SDave Stevenson sensor->mode->format.height, 1, 13112512c064SDave Stevenson sensor->mode->vts - 13122512c064SDave Stevenson sensor->mode->format.height); 13132512c064SDave Stevenson 1314911f4516SDave Stevenson if (sensor->ctrls.error) 1315911f4516SDave Stevenson goto handler_free; 1316911f4516SDave Stevenson 1317911f4516SDave Stevenson sensor->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 1318c6da1ae4SJacopo Mondi sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 1319911f4516SDave Stevenson sensor->sd.ctrl_handler = &sensor->ctrls; 1320911f4516SDave Stevenson 1321911f4516SDave Stevenson return 0; 1322911f4516SDave Stevenson 1323911f4516SDave Stevenson handler_free: 1324911f4516SDave Stevenson dev_err(&client->dev, "%s Controls initialization failed (%d)\n", 13254974c2f1SDavid Plowman __func__, sensor->ctrls.error); 13264974c2f1SDavid Plowman v4l2_ctrl_handler_free(&sensor->ctrls); 13274974c2f1SDavid Plowman 13284974c2f1SDavid Plowman return sensor->ctrls.error; 13294974c2f1SDavid Plowman } 13304974c2f1SDavid Plowman 1331dea4fcfeSDave Stevenson static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np) 13323c2472a3SRamiro Oliveira { 1333dea4fcfeSDave Stevenson struct v4l2_fwnode_endpoint bus_cfg = { 1334dea4fcfeSDave Stevenson .bus_type = V4L2_MBUS_CSI2_DPHY, 1335dea4fcfeSDave Stevenson }; 13363c2472a3SRamiro Oliveira struct device_node *ep; 13373c2472a3SRamiro Oliveira int ret; 13383c2472a3SRamiro Oliveira 13393c2472a3SRamiro Oliveira ep = of_graph_get_next_endpoint(np, NULL); 13403c2472a3SRamiro Oliveira if (!ep) 13413c2472a3SRamiro Oliveira return -EINVAL; 13423c2472a3SRamiro Oliveira 1343859969b3SSakari Ailus ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); 1344dea4fcfeSDave Stevenson if (ret) 1345dea4fcfeSDave Stevenson goto out; 13463c2472a3SRamiro Oliveira 1347dea4fcfeSDave Stevenson sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags & 1348dea4fcfeSDave Stevenson V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; 1349dea4fcfeSDave Stevenson 1350dea4fcfeSDave Stevenson out: 13513c2472a3SRamiro Oliveira of_node_put(ep); 1352c9a05cecSJacopo Mondi 13533c2472a3SRamiro Oliveira return ret; 13543c2472a3SRamiro Oliveira } 13553c2472a3SRamiro Oliveira 1356e6714993SKieran Bingham static int ov5647_probe(struct i2c_client *client) 13573c2472a3SRamiro Oliveira { 1358c9a05cecSJacopo Mondi struct device_node *np = client->dev.of_node; 13593c2472a3SRamiro Oliveira struct device *dev = &client->dev; 13603c2472a3SRamiro Oliveira struct ov5647 *sensor; 13613c2472a3SRamiro Oliveira struct v4l2_subdev *sd; 13623c2472a3SRamiro Oliveira u32 xclk_freq; 1363c9a05cecSJacopo Mondi int ret; 13643c2472a3SRamiro Oliveira 13653c2472a3SRamiro Oliveira sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 13663c2472a3SRamiro Oliveira if (!sensor) 13673c2472a3SRamiro Oliveira return -ENOMEM; 13683c2472a3SRamiro Oliveira 13693c2472a3SRamiro Oliveira if (IS_ENABLED(CONFIG_OF) && np) { 1370dea4fcfeSDave Stevenson ret = ov5647_parse_dt(sensor, np); 13713c2472a3SRamiro Oliveira if (ret) { 13723c2472a3SRamiro Oliveira dev_err(dev, "DT parsing error: %d\n", ret); 13733c2472a3SRamiro Oliveira return ret; 13743c2472a3SRamiro Oliveira } 13753c2472a3SRamiro Oliveira } 13763c2472a3SRamiro Oliveira 13773c2472a3SRamiro Oliveira sensor->xclk = devm_clk_get(dev, NULL); 13783c2472a3SRamiro Oliveira if (IS_ERR(sensor->xclk)) { 13793c2472a3SRamiro Oliveira dev_err(dev, "could not get xclk"); 13803c2472a3SRamiro Oliveira return PTR_ERR(sensor->xclk); 13813c2472a3SRamiro Oliveira } 13823c2472a3SRamiro Oliveira 13833c2472a3SRamiro Oliveira xclk_freq = clk_get_rate(sensor->xclk); 13843c2472a3SRamiro Oliveira if (xclk_freq != 25000000) { 13853c2472a3SRamiro Oliveira dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq); 13863c2472a3SRamiro Oliveira return -EINVAL; 13873c2472a3SRamiro Oliveira } 13883c2472a3SRamiro Oliveira 1389c9a05cecSJacopo Mondi /* Request the power down GPIO asserted. */ 1390c9a05cecSJacopo Mondi sensor->pwdn = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_HIGH); 1391b050791dSDave Stevenson if (IS_ERR(sensor->pwdn)) { 1392b050791dSDave Stevenson dev_err(dev, "Failed to get 'pwdn' gpio\n"); 1393b050791dSDave Stevenson return -EINVAL; 1394b050791dSDave Stevenson } 1395b050791dSDave Stevenson 13963c2472a3SRamiro Oliveira mutex_init(&sensor->lock); 13973c2472a3SRamiro Oliveira 1398d7d6074eSJacopo Mondi sensor->mode = OV5647_DEFAULT_MODE; 1399d7d6074eSJacopo Mondi 14004974c2f1SDavid Plowman ret = ov5647_init_controls(sensor); 14014974c2f1SDavid Plowman if (ret) 14024974c2f1SDavid Plowman goto mutex_destroy; 14034974c2f1SDavid Plowman 14043c2472a3SRamiro Oliveira sd = &sensor->sd; 14053c2472a3SRamiro Oliveira v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops); 1406c9a05cecSJacopo Mondi sd->internal_ops = &ov5647_subdev_internal_ops; 14077ef761a0SDave Stevenson sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 14083c2472a3SRamiro Oliveira 14093c2472a3SRamiro Oliveira sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 14103c2472a3SRamiro Oliveira sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; 14113c2472a3SRamiro Oliveira ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad); 14123c2472a3SRamiro Oliveira if (ret < 0) 14134974c2f1SDavid Plowman goto ctrl_handler_free; 14143c2472a3SRamiro Oliveira 1415089b7c70SJacopo Mondi ret = ov5647_power_on(dev); 1416089b7c70SJacopo Mondi if (ret) 1417089b7c70SJacopo Mondi goto entity_cleanup; 1418b050791dSDave Stevenson 14193c2472a3SRamiro Oliveira ret = ov5647_detect(sd); 14203c2472a3SRamiro Oliveira if (ret < 0) 1421089b7c70SJacopo Mondi goto power_off; 14223c2472a3SRamiro Oliveira 14233c2472a3SRamiro Oliveira ret = v4l2_async_register_subdev(sd); 14243c2472a3SRamiro Oliveira if (ret < 0) 1425089b7c70SJacopo Mondi goto power_off; 1426089b7c70SJacopo Mondi 1427089b7c70SJacopo Mondi /* Enable runtime PM and turn off the device */ 1428089b7c70SJacopo Mondi pm_runtime_set_active(dev); 1429089b7c70SJacopo Mondi pm_runtime_enable(dev); 1430089b7c70SJacopo Mondi pm_runtime_idle(dev); 14313c2472a3SRamiro Oliveira 14323c2472a3SRamiro Oliveira dev_dbg(dev, "OmniVision OV5647 camera driver probed\n"); 1433c9a05cecSJacopo Mondi 14343c2472a3SRamiro Oliveira return 0; 1435c9a05cecSJacopo Mondi 1436089b7c70SJacopo Mondi power_off: 1437089b7c70SJacopo Mondi ov5647_power_off(dev); 1438c9a05cecSJacopo Mondi entity_cleanup: 14393c2472a3SRamiro Oliveira media_entity_cleanup(&sd->entity); 14404974c2f1SDavid Plowman ctrl_handler_free: 14414974c2f1SDavid Plowman v4l2_ctrl_handler_free(&sensor->ctrls); 1442c9a05cecSJacopo Mondi mutex_destroy: 14433c2472a3SRamiro Oliveira mutex_destroy(&sensor->lock); 1444c9a05cecSJacopo Mondi 14453c2472a3SRamiro Oliveira return ret; 14463c2472a3SRamiro Oliveira } 14473c2472a3SRamiro Oliveira 14483c2472a3SRamiro Oliveira static int ov5647_remove(struct i2c_client *client) 14493c2472a3SRamiro Oliveira { 14503c2472a3SRamiro Oliveira struct v4l2_subdev *sd = i2c_get_clientdata(client); 14515bc5ca71SJacopo Mondi struct ov5647 *sensor = to_sensor(sd); 14523c2472a3SRamiro Oliveira 14535bc5ca71SJacopo Mondi v4l2_async_unregister_subdev(&sensor->sd); 14545bc5ca71SJacopo Mondi media_entity_cleanup(&sensor->sd.entity); 14555bc5ca71SJacopo Mondi v4l2_ctrl_handler_free(&sensor->ctrls); 14563c2472a3SRamiro Oliveira v4l2_device_unregister_subdev(sd); 1457089b7c70SJacopo Mondi pm_runtime_disable(&client->dev); 14585bc5ca71SJacopo Mondi mutex_destroy(&sensor->lock); 14593c2472a3SRamiro Oliveira 14603c2472a3SRamiro Oliveira return 0; 14613c2472a3SRamiro Oliveira } 14623c2472a3SRamiro Oliveira 1463089b7c70SJacopo Mondi static const struct dev_pm_ops ov5647_pm_ops = { 1464089b7c70SJacopo Mondi SET_RUNTIME_PM_OPS(ov5647_power_off, ov5647_power_on, NULL) 1465089b7c70SJacopo Mondi }; 1466089b7c70SJacopo Mondi 14673c2472a3SRamiro Oliveira static const struct i2c_device_id ov5647_id[] = { 14683c2472a3SRamiro Oliveira { "ov5647", 0 }, 1469c9a05cecSJacopo Mondi { /* sentinel */ } 14703c2472a3SRamiro Oliveira }; 14713c2472a3SRamiro Oliveira MODULE_DEVICE_TABLE(i2c, ov5647_id); 14723c2472a3SRamiro Oliveira 14733c2472a3SRamiro Oliveira #if IS_ENABLED(CONFIG_OF) 14743c2472a3SRamiro Oliveira static const struct of_device_id ov5647_of_match[] = { 14753c2472a3SRamiro Oliveira { .compatible = "ovti,ov5647" }, 14763c2472a3SRamiro Oliveira { /* sentinel */ }, 14773c2472a3SRamiro Oliveira }; 14783c2472a3SRamiro Oliveira MODULE_DEVICE_TABLE(of, ov5647_of_match); 14793c2472a3SRamiro Oliveira #endif 14803c2472a3SRamiro Oliveira 14813c2472a3SRamiro Oliveira static struct i2c_driver ov5647_driver = { 14823c2472a3SRamiro Oliveira .driver = { 14833c2472a3SRamiro Oliveira .of_match_table = of_match_ptr(ov5647_of_match), 1484c9a05cecSJacopo Mondi .name = "ov5647", 1485089b7c70SJacopo Mondi .pm = &ov5647_pm_ops, 14863c2472a3SRamiro Oliveira }, 1487e6714993SKieran Bingham .probe_new = ov5647_probe, 14883c2472a3SRamiro Oliveira .remove = ov5647_remove, 14893c2472a3SRamiro Oliveira .id_table = ov5647_id, 14903c2472a3SRamiro Oliveira }; 14913c2472a3SRamiro Oliveira 14923c2472a3SRamiro Oliveira module_i2c_driver(ov5647_driver); 14933c2472a3SRamiro Oliveira 14943c2472a3SRamiro Oliveira MODULE_AUTHOR("Ramiro Oliveira <roliveir@synopsys.com>"); 14953c2472a3SRamiro Oliveira MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors"); 14963c2472a3SRamiro Oliveira MODULE_LICENSE("GPL v2"); 1497