Linux应用程序开发笔记:nanopi-m4(rk3399)camera isp(附OV4689 4-lane-MIPI驱动,支持1080p@120fps)
参考资料:
NanoPi M4资料:
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_M4/zh
Rockchip-isp介绍:
http://opensource.rock-chips.com/wiki_Rockchip-isp1
http://blog.iotwrt.com/media/2017/10/01/camera/
Camera ISP(Image Signal Processor)
Kernel V4L2介绍
Linux Kernel Media API Introduction
V4L2框架概述
V4L2框架-v4l2 device
V4L2框架-media device
v4l2设备读写流程(CSI驱动调用流程)
V4L2 driver -整体架构
内核v4l2框架之video for linux 2
结合芯片exynos 4412介绍V4L2用来视频编解码的驱动
Android P摄像头开发和V4l2视频处理
【Linux开发】IO streaming DMA buffer importing
V4L2编程:
Linux v4l2编程(摄像头信息采集)
linux v4l2摄像头应用层编程介绍
多平面API中的缓存映射
其他资料:
ISP图像传感器原理
附ov4689 4-lane MIPI驱动:
// SPDX-License-Identifier: GPL-2.0/* * ov4689 driver * * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. * * V0.0X01.0X01 add poweron function. */#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DRIVER_VERSIONKERNEL_VERSION(0, 0x01, 0x01)#ifndef V4L2_CID_DIGITAL_GAIN#define V4L2_CID_DIGITAL_GAINV4L2_CID_GAIN#endif#define OV4689_LANES 4#define OV4689_BITS_PER_SAMPLE10#define OV4689_LINK_FREQ_500MHZ500000000LL/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */#define OV4689_PIXEL_RATE(OV4689_LINK_FREQ_500MHZ * 2 * OV4689_LANES / OV4689_BITS_PER_SAMPLE)#define OV4689_XVCLK_FREQ24000000#define CHIP_ID0x004688#define OV4689_REG_CHIP_ID0x300a#define OV4689_REG_CTRL_MODE0x0100#define OV4689_MODE_SW_STANDBY0x0#define OV4689_MODE_STREAMINGBIT(0)#define OV4689_REG_EXPOSURE0x3500#defineOV4689_EXPOSURE_MIN4#defineOV4689_EXPOSURE_STEP1#define OV4689_VTS_MAX0x7fff#define OV4689_REG_GAIN_H0x3508#define OV4689_REG_GAIN_L0x3509#define OV4689_GAIN_H_MASK0x07#define OV4689_GAIN_H_SHIFT8#define OV4689_GAIN_L_MASK0xff#define OV4689_GAIN_MIN0x10#define OV4689_GAIN_MAX0xfff8/* 0xf8 */#define OV4689_GAIN_STEP1#define OV4689_GAIN_DEFAULT0x10#define OV4689_REG_TEST_PATTERN0x5040#define OV4689_TEST_PATTERN_ENABLE0x80#define OV4689_TEST_PATTERN_DISABLE0x0#define OV4689_REG_VTS0x380e#define REG_NULL0xFFFF#define OV4689_REG_VALUE_08BIT1#define OV4689_REG_VALUE_16BIT2#define OV4689_REG_VALUE_24BIT3#define OF_CAMERA_PINCTRL_STATE_DEFAULT"rockchip,camera_default"#define OF_CAMERA_PINCTRL_STATE_SLEEP"rockchip,camera_sleep"#define OV4689_NAME"ov4689"static const char * const ov4689_supply_names[] = {"avdd",/* Analog power */"dovdd",/* Digital I/O power */"dvdd",/* Digital core power */};#define OV4689_NUM_SUPPLIES ARRAY_SIZE(ov4689_supply_names)struct regval {u16 addr;u8 val;};struct ov4689_mode {u32 width;u32 height;u32 max_fps;u32 hts_def;u32 vts_def;u32 exp_def;const struct regval *reg_list;};struct ov4689 {struct i2c_client*client;struct clk*xvclk;struct gpio_desc*reset_gpio;struct gpio_desc*pwdn_gpio;struct regulator_bulk_data supplies[OV4689_NUM_SUPPLIES];struct pinctrl*pinctrl;struct pinctrl_state*pins_default;struct pinctrl_state*pins_sleep;struct v4l2_subdevsubdev;struct media_padpad;struct v4l2_ctrl_handler ctrl_handler;struct v4l2_ctrl*exposure;struct v4l2_ctrl*anal_gain;struct v4l2_ctrl*digi_gain;struct v4l2_ctrl*hblank;struct v4l2_ctrl*vblank;struct v4l2_ctrl*test_pattern;struct mutexmutex;boolstreaming;boolpower_on;const struct ov4689_mode *cur_mode;u32module_index;const char*module_facing;const char*module_name;const char*len_name;};#define to_ov4689(sd) container_of(sd, struct ov4689, subdev)/* * Xclk 24Mhz */static const struct regval ov4689_global_regs[] = {{REG_NULL, 0x00},};/* * Xclk 24Mhz * max_framerate 30fps * mipi_datarate per lane 1008Mbps */static const struct regval ov4689_2688x1520_regs[] = {{0x0103, 0x01},{0x3638, 0x00},{0x0300, 0x00},{0x0302, 0x2a},{0x0303, 0x00},{0x0304, 0x03},{0x030b, 0x00},{0x030d, 0x1e},{0x030e, 0x04},{0x030f, 0x01},{0x0312, 0x01},{0x031e, 0x00},{0x3000, 0x20},{0x3002, 0x00},{0x3018, 0x32},{0x3020, 0x93},{0x3021, 0x03},{0x3022, 0x01},{0x3031, 0x0a},{0x303f, 0x0c},{0x3305, 0xf1},{0x3307, 0x04},{0x3309, 0x29},{0x3500, 0x00},{0x3501, 0x60},{0x3502, 0x00},{0x3503, 0x04},{0x3504, 0x00},{0x3505, 0x00},{0x3506, 0x00},{0x3507, 0x00},{0x3508, 0x00},{0x3509, 0x80},{0x350a, 0x00},{0x350b, 0x00},{0x350c, 0x00},{0x350d, 0x00},{0x350e, 0x00},{0x350f, 0x80},{0x3510, 0x00},{0x3511, 0x00},{0x3512, 0x00},{0x3513, 0x00},{0x3514, 0x00},{0x3515, 0x80},{0x3516, 0x00},{0x3517, 0x00},{0x3518, 0x00},{0x3519, 0x00},{0x351a, 0x00},{0x351b, 0x80},{0x351c, 0x00},{0x351d, 0x00},{0x351e, 0x00},{0x351f, 0x00},{0x3520, 0x00},{0x3521, 0x80},{0x3522, 0x08},{0x3524, 0x08},{0x3526, 0x08},{0x3528, 0x08},{0x352a, 0x08},{0x3602, 0x00},{0x3603, 0x40},{0x3604, 0x02},{0x3605, 0x00},{0x3606, 0x00},{0x3607, 0x00},{0x3609, 0x12},{0x360a, 0x40},{0x360c, 0x08},{0x360f, 0xe5},{0x3608, 0x8f},{0x3611, 0x00},{0x3613, 0xf7},{0x3616, 0x58},{0x3619, 0x99},{0x361b, 0x60},{0x361c, 0x7a},{0x361e, 0x79},{0x361f, 0x02},{0x3632, 0x00},{0x3633, 0x10},{0x3634, 0x10},{0x3635, 0x10},{0x3636, 0x15},{0x3646, 0x86},{0x364a, 0x0b},{0x3700, 0x17},{0x3701, 0x22},{0x3703, 0x10},{0x370a, 0x37},{0x3705, 0x00},{0x3706, 0x63},{0x3709, 0x3c},{0x370b, 0x01},{0x370c, 0x30},{0x3710, 0x24},{0x3711, 0x0c},{0x3716, 0x00},{0x3720, 0x28},{0x3729, 0x7b},{0x372a, 0x84},{0x372b, 0xbd},{0x372c, 0xbc},{0x372e, 0x52},{0x373c, 0x0e},{0x373e, 0x33},{0x3743, 0x10},{0x3744, 0x88},{0x3745, 0xc0},{0x374a, 0x43},{0x374c, 0x00},{0x374e, 0x23},{0x3751, 0x7b},{0x3752, 0x84},{0x3753, 0xbd},{0x3754, 0xbc},{0x3756, 0x52},{0x375c, 0x00},{0x3760, 0x00},{0x3761, 0x00},{0x3762, 0x00},{0x3763, 0x00},{0x3764, 0x00},{0x3767, 0x04},{0x3768, 0x04},{0x3769, 0x08},{0x376a, 0x08},{0x376b, 0x20},{0x376c, 0x00},{0x376d, 0x00},{0x376e, 0x00},{0x3773, 0x00},{0x3774, 0x51},{0x3776, 0xbd},{0x3777, 0xbd},{0x3781, 0x18},{0x3783, 0x25},{0x3798, 0x1b},{0x3800, 0x00},{0x3801, 0x08},{0x3802, 0x00},{0x3803, 0x04},{0x3804, 0x0a},{0x3805, 0x97},{0x3806, 0x05},{0x3807, 0xfb},{0x3808, 0x0a},{0x3809, 0x80},{0x380a, 0x05},{0x380b, 0xf0},{0x380c, 0x0a},{0x380d, 0x18},{0x380e, 0x06},{0x380f, 0x12},{0x3810, 0x00},{0x3811, 0x08},{0x3812, 0x00},{0x3813, 0x04},{0x3814, 0x01},{0x3815, 0x01},{0x3819, 0x01},{0x3820, 0x00},{0x3821, 0x06},{0x3829, 0x00},{0x382a, 0x01},{0x382b, 0x01},{0x382d, 0x7f},{0x3830, 0x04},{0x3836, 0x01},{0x3837, 0x00},{0x3841, 0x02},{0x3846, 0x08},{0x3847, 0x07},{0x3d85, 0x36},{0x3d8c, 0x71},{0x3d8d, 0xcb},{0x3f0a, 0x00},{0x4000, 0xf1},{0x4001, 0x40},{0x4002, 0x04},{0x4003, 0x14},{0x400e, 0x00},{0x4011, 0x00},{0x401a, 0x00},{0x401b, 0x00},{0x401c, 0x00},{0x401d, 0x00},{0x401f, 0x00},{0x4020, 0x00},{0x4021, 0x10},{0x4022, 0x07},{0x4023, 0xcf},{0x4024, 0x09},{0x4025, 0x60},{0x4026, 0x09},{0x4027, 0x6f},{0x4028, 0x00},{0x4029, 0x02},{0x402a, 0x06},{0x402b, 0x04},{0x402c, 0x02},{0x402d, 0x02},{0x402e, 0x0e},{0x402f, 0x04},{0x4302, 0xff},{0x4303, 0xff},{0x4304, 0x00},{0x4305, 0x00},{0x4306, 0x00},{0x4308, 0x02},{0x4500, 0x6c},{0x4501, 0xc4},{0x4502, 0x40},{0x4503, 0x01},{0x4601, 0xa7},{0x4800, 0x04},{0x4813, 0x08},{0x481f, 0x40},{0x4829, 0x78},{0x4837, 0x10},{0x4b00, 0x2a},{0x4b0d, 0x00},{0x4d00, 0x04},{0x4d01, 0x42},{0x4d02, 0xd1},{0x4d03, 0x93},{0x4d04, 0xf5},{0x4d05, 0xc1},{0x5000, 0xf3},{0x5001, 0x11},{0x5004, 0x00},{0x500a, 0x00},{0x500b, 0x00},{0x5032, 0x00},{0x5040, 0x00},{0x5050, 0x0c},{0x5500, 0x00},{0x5501, 0x10},{0x5502, 0x01},{0x5503, 0x0f},{0x8000, 0x00},{0x8001, 0x00},{0x8002, 0x00},{0x8003, 0x00},{0x8004, 0x00},{0x8005, 0x00},{0x8006, 0x00},{0x8007, 0x00},{0x8008, 0x00},{0x3638, 0x00},{REG_NULL, 0x00},};static const struct regval ov4689_1280x720_regs[] = {{0x0103, 0x01},{0x3638, 0x00},{0x0300, 0x00},{0x0302, 0x22},{0x0303, 0x00},{0x0304, 0x03},{0x030b, 0x00},{0x030d, 0x1e},{0x030e, 0x04},{0x030f, 0x01},{0x0312, 0x01},{0x031e, 0x00},{0x3000, 0x20},{0x3002, 0x00},{0x3018, 0x32},{0x3019, 0x0c},{0x3020, 0x93},{0x3021, 0x03},{0x3022, 0x01},{0x3031, 0x0a},{0x303f, 0x0c},{0x3305, 0xf1},{0x3307, 0x04},{0x3309, 0x29},{0x3500, 0x00},{0x3501, 0x30},{0x3502, 0x00},{0x3503, 0x04},{0x3504, 0x00},{0x3505, 0x00},{0x3506, 0x00},{0x3507, 0x00},{0x3508, 0x07},{0x3509, 0x78},{0x350a, 0x00},{0x350b, 0x00},{0x350c, 0x00},{0x350d, 0x00},{0x350e, 0x00},{0x350f, 0x80},{0x3510, 0x00},{0x3511, 0x00},{0x3512, 0x00},{0x3513, 0x00},{0x3514, 0x00},{0x3515, 0x80},{0x3516, 0x00},{0x3517, 0x00},{0x3518, 0x00},{0x3519, 0x00},{0x351a, 0x00},{0x351b, 0x80},{0x351c, 0x00},{0x351d, 0x00},{0x351e, 0x00},{0x351f, 0x00},{0x3520, 0x00},{0x3521, 0x80},{0x3522, 0x08},{0x3524, 0x08},{0x3526, 0x08},{0x3528, 0x08},{0x352a, 0x08},{0x3602, 0x00},{0x3603, 0x40},{0x3604, 0x02},{0x3605, 0x00},{0x3606, 0x00},{0x3607, 0x00},{0x3609, 0x12},{0x360a, 0x40},{0x360c, 0x08},{0x360f, 0xe5},{0x3608, 0x8f},{0x3611, 0x00},{0x3613, 0xf7},{0x3616, 0x58},{0x3619, 0x99},{0x361b, 0x60},{0x361c, 0x7a},{0x361e, 0x79},{0x361f, 0x02},{0x3632, 0x05},{0x3633, 0x10},{0x3634, 0x10},{0x3635, 0x10},{0x3636, 0x15},{0x3646, 0x86},{0x364a, 0x0b},{0x3700, 0x17},{0x3701, 0x22},{0x3703, 0x10},{0x370a, 0x37},{0x3705, 0x00},{0x3706, 0x63},{0x3709, 0x3c},{0x370b, 0x01},{0x370c, 0x30},{0x3710, 0x24},{0x3711, 0x0c},{0x3716, 0x00},{0x3720, 0x28},{0x3729, 0x7b},{0x372a, 0x84},{0x372b, 0xbd},{0x372c, 0xbc},{0x372e, 0x52},{0x373c, 0x0e},{0x373e, 0x33},{0x3743, 0x10},{0x3744, 0x88},{0x3745, 0xc0},{0x374a, 0x43},{0x374c, 0x00},{0x374e, 0x23},{0x3751, 0x7b},{0x3752, 0x84},{0x3753, 0xbd},{0x3754, 0xbc},{0x3756, 0x52},{0x375c, 0x00},{0x3760, 0x00},{0x3761, 0x00},{0x3762, 0x00},{0x3763, 0x00},{0x3764, 0x00},{0x3767, 0x04},{0x3768, 0x04},{0x3769, 0x08},{0x376a, 0x08},{0x376b, 0x40},{0x376c, 0x00},{0x376d, 0x00},{0x376e, 0x00},{0x3773, 0x00},{0x3774, 0x51},{0x3776, 0xbd},{0x3777, 0xbd},{0x3781, 0x18},{0x3783, 0x25},{0x3798, 0x1b},{0x3800, 0x00},{0x3801, 0x48},{0x3802, 0x00},{0x3803, 0x2c},{0x3804, 0x0a},{0x3805, 0x57},{0x3806, 0x05},{0x3807, 0xd3},{0x3808, 0x05},{0x3809, 0x00},{0x380a, 0x02},{0x380b, 0xd0},{0x380c, 0x05},{0x380d, 0x0d},{0x380e, 0x03},{0x380f, 0x05},{0x3810, 0x00},{0x3811, 0x04},{0x3812, 0x00},{0x3813, 0x02},{0x3814, 0x03},{0x3815, 0x01},{0x3819, 0x01},{0x3820, 0x10},{0x3821, 0x07},{0x3829, 0x00},{0x382a, 0x03},{0x382b, 0x01},{0x382d, 0x7f},{0x3830, 0x08},{0x3836, 0x02},{0x3837, 0x00},{0x3841, 0x02},{0x3846, 0x08},{0x3847, 0x07},{0x3d85, 0x36},{0x3d8c, 0x71},{0x3d8d, 0xcb},{0x3f0a, 0x00},{0x4000, 0x71},{0x4001, 0x50},{0x4002, 0x04},{0x4003, 0x14},{0x400e, 0x00},{0x4011, 0x00},{0x401a, 0x00},{0x401b, 0x00},{0x401c, 0x00},{0x401d, 0x00},{0x401f, 0x00},{0x4020, 0x00},{0x4021, 0x10},{0x4022, 0x03},{0x4023, 0x93},{0x4024, 0x04},{0x4025, 0xc0},{0x4026, 0x04},{0x4027, 0xd0},{0x4028, 0x00},{0x4029, 0x02},{0x402a, 0x06},{0x402b, 0x04},{0x402c, 0x02},{0x402d, 0x02},{0x402e, 0x0e},{0x402f, 0x04},{0x4302, 0xff},{0x4303, 0xff},{0x4304, 0x00},{0x4305, 0x00},{0x4306, 0x00},{0x4308, 0x02},{0x4500, 0x6c},{0x4501, 0xc4},{0x4502, 0x44},{0x4503, 0x01},{0x4600, 0x00},{0x4601, 0x4f},{0x4800, 0x04},{0x4813, 0x08},{0x481f, 0x40},{0x4829, 0x78},{0x4837, 0x14},{0x4b00, 0x2a},{0x4b0d, 0x00},{0x4d00, 0x04},{0x4d01, 0x42},{0x4d02, 0xd1},{0x4d03, 0x93},{0x4d04, 0xf5},{0x4d05, 0xc1},{0x5000, 0xf3},{0x5001, 0x11},{0x5004, 0x00},{0x500a, 0x00},{0x500b, 0x00},{0x5032, 0x00},{0x5040, 0x00},{0x5050, 0x3c},{0x5500, 0x00},{0x5501, 0x10},{0x5502, 0x01},{0x5503, 0x0f},{0x8000, 0x00},{0x8001, 0x00},{0x8002, 0x00},{0x8003, 0x00},{0x8004, 0x00},{0x8005, 0x00},{0x8006, 0x00},{0x8007, 0x00},{0x8008, 0x00},{0x3638, 0x00},{REG_NULL, 0x00},};static const struct regval ov4689_1920x1080_regs[] = {{0x0103, 0x01},{0x3638, 0x00},{0x0300, 0x00},{0x0302, 0x2a},/* 1008Mbps */{0x0303, 0x00},{0x0304, 0x03},{0x030b, 0x00},{0x030d, 0x1e},{0x030e, 0x04},{0x030f, 0x01},{0x0312, 0x01},{0x031e, 0x00},{0x3000, 0x20},{0x3002, 0x00},{0x3018, 0x32},{0x3019, 0x0c},{0x3020, 0x93},{0x3021, 0x03},{0x3022, 0x01},{0x3031, 0x0a},{0x303f, 0x0c},{0x3305, 0xf1},{0x3307, 0x04},{0x3309, 0x29},{0x3500, 0x00},{0x3501, 0x30},{0x3502, 0x00},{0x3503, 0x04},{0x3504, 0x00},{0x3505, 0x00},{0x3506, 0x00},{0x3507, 0x00},{0x3508, 0x07},{0x3509, 0x78},{0x350a, 0x00},{0x350b, 0x00},{0x350c, 0x00},{0x350d, 0x00},{0x350e, 0x00},{0x350f, 0x80},{0x3510, 0x00},{0x3511, 0x00},{0x3512, 0x00},{0x3513, 0x00},{0x3514, 0x00},{0x3515, 0x80},{0x3516, 0x00},{0x3517, 0x00},{0x3518, 0x00},{0x3519, 0x00},{0x351a, 0x00},{0x351b, 0x80},{0x351c, 0x00},{0x351d, 0x00},{0x351e, 0x00},{0x351f, 0x00},{0x3520, 0x00},{0x3521, 0x80},{0x3522, 0x08},{0x3524, 0x08},{0x3526, 0x08},{0x3528, 0x08},{0x352a, 0x08},{0x3602, 0x00},{0x3603, 0x40},{0x3604, 0x02},{0x3605, 0x00},{0x3606, 0x00},{0x3607, 0x00},{0x3609, 0x12},{0x360a, 0x40},{0x360c, 0x08},{0x360f, 0xe5},{0x3608, 0x8f},{0x3611, 0x00},{0x3613, 0xf7},{0x3616, 0x58},{0x3619, 0x99},{0x361b, 0x60},{0x361c, 0x7a},{0x361e, 0x79},{0x361f, 0x02},{0x3632, 0x00},{0x3633, 0x10},{0x3634, 0x10},{0x3635, 0x10},{0x3636, 0x15},{0x3646, 0x86},{0x364a, 0x0b},{0x3700, 0x17},{0x3701, 0x22},{0x3703, 0x10},{0x370a, 0x37},{0x3705, 0x00},{0x3706, 0x63},{0x3709, 0x3c},{0x370b, 0x01},{0x370c, 0x30},{0x3710, 0x24},{0x3711, 0x0c},{0x3716, 0x00},{0x3720, 0x28},{0x3729, 0x7b},{0x372a, 0x84},{0x372b, 0xbd},{0x372c, 0xbc},{0x372e, 0x52},{0x373c, 0x0e},{0x373e, 0x33},{0x3743, 0x10},{0x3744, 0x88},{0x3745, 0xc0},{0x374a, 0x43},{0x374c, 0x00},{0x374e, 0x23},{0x3751, 0x7b},{0x3752, 0x84},{0x3753, 0xbd},{0x3754, 0xbc},{0x3756, 0x52},{0x375c, 0x00},{0x3760, 0x00},{0x3761, 0x00},{0x3762, 0x00},{0x3763, 0x00},{0x3764, 0x00},{0x3767, 0x04},{0x3768, 0x04},{0x3769, 0x08},{0x376a, 0x08},{0x376b, 0x20},{0x376c, 0x00},{0x376d, 0x00},{0x376e, 0x00},{0x3773, 0x00},{0x3774, 0x51},{0x3776, 0xbd},{0x3777, 0xbd},{0x3781, 0x18},{0x3783, 0x25},{0x3798, 0x1b},{0x3800, 0x01},{0x3801, 0x88},{0x3802, 0x00},{0x3803, 0xe0},{0x3804, 0x09},{0x3805, 0x17},{0x3806, 0x05},{0x3807, 0x1f},{0x3808, 0x07},{0x3809, 0x80},{0x380a, 0x04},{0x380b, 0x38},{0x380c, 0x05},{0x380d, 0x7f},{0x380e, 0x04},{0x380f, 0x70},{0x3810, 0x00},{0x3811, 0x08},{0x3812, 0x00},{0x3813, 0x04},{0x3814, 0x01},{0x3815, 0x01},{0x3819, 0x01},{0x3820, 0x00},{0x3821, 0x06},{0x3829, 0x00},{0x382a, 0x01},{0x382b, 0x01},{0x382d, 0x7f},{0x3830, 0x04},{0x3836, 0x01},{0x3837, 0x00},{0x3841, 0x02},{0x3846, 0x08},{0x3847, 0x07},{0x3d85, 0x36},{0x3d8c, 0x71},{0x3d8d, 0xcb},{0x3f0a, 0x00},{0x4000, 0x71},{0x4001, 0x40},{0x4002, 0x04},{0x4003, 0x14},{0x400e, 0x00},{0x4011, 0x00},{0x401a, 0x00},{0x401b, 0x00},{0x401c, 0x00},{0x401d, 0x00},{0x401f, 0x00},{0x4020, 0x00},{0x4021, 0x10},{0x4022, 0x06},{0x4023, 0x13},{0x4024, 0x07},{0x4025, 0x40},{0x4026, 0x07},{0x4027, 0x50},{0x4028, 0x00},{0x4029, 0x02},{0x402a, 0x06},{0x402b, 0x04},{0x402c, 0x02},{0x402d, 0x02},{0x402e, 0x0e},{0x402f, 0x04},{0x4302, 0xff},{0x4303, 0xff},{0x4304, 0x00},{0x4305, 0x00},{0x4306, 0x00},{0x4308, 0x02},{0x4500, 0x6c},{0x4501, 0xc4},{0x4502, 0x40},{0x4503, 0x01},{0x4600, 0x00},{0x4601, 0x77},{0x4800, 0x04},{0x4813, 0x08},{0x481f, 0x40},{0x4829, 0x78},{0x4837, 0x14},{0x4b00, 0x2a},{0x4b0d, 0x00},{0x4d00, 0x04},{0x4d01, 0x42},{0x4d02, 0xd1},{0x4d03, 0x93},{0x4d04, 0xf5},{0x4d05, 0xc1},{0x5000, 0xf3},{0x5001, 0x11},{0x5004, 0x00},{0x500a, 0x00},{0x500b, 0x00},{0x5032, 0x00},{0x5040, 0x00},{0x5050, 0x0c},{0x5500, 0x00},{0x5501, 0x10},{0x5502, 0x01},{0x5503, 0x0f},{0x8000, 0x00},{0x8001, 0x00},{0x8002, 0x00},{0x8003, 0x00},{0x8004, 0x00},{0x8005, 0x00},{0x8006, 0x00},{0x8007, 0x00},{0x8008, 0x00},{0x3638, 0x00},{REG_NULL, 0x00},};static const struct regval ov4689_1920x1080_90fps_regs[] = {{0x0103, 0x01},{0x3638, 0x00},{0x0300, 0x00},{0x0302, 0x2a},/* 1008Mbps */{0x0303, 0x00},{0x0304, 0x03},{0x030b, 0x00},{0x030d, 0x1e},{0x030e, 0x04},{0x030f, 0x01},{0x0312, 0x01},{0x031e, 0x00},{0x3000, 0x20},{0x3002, 0x00},{0x3018, 0x72},/* 0x32: 2 lanes, 0x72: 4 lanes */{0x3019, 0x00},/* 0x0c: 2 lanes, 0x00: 4 lanes */{0x3020, 0x93},{0x3021, 0x03},{0x3022, 0x01},{0x3031, 0x0a},{0x303f, 0x0c},{0x3305, 0xf1},{0x3307, 0x04},{0x3309, 0x29},{0x3500, 0x00},{0x3501, 0x30},{0x3502, 0x00},{0x3503, 0x04},{0x3504, 0x00},{0x3505, 0x00},{0x3506, 0x00},{0x3507, 0x00},{0x3508, 0x07},{0x3509, 0x78},{0x350a, 0x00},{0x350b, 0x00},{0x350c, 0x00},{0x350d, 0x00},{0x350e, 0x00},{0x350f, 0x80},{0x3510, 0x00},{0x3511, 0x00},{0x3512, 0x00},{0x3513, 0x00},{0x3514, 0x00},{0x3515, 0x80},{0x3516, 0x00},{0x3517, 0x00},{0x3518, 0x00},{0x3519, 0x00},{0x351a, 0x00},{0x351b, 0x80},{0x351c, 0x00},{0x351d, 0x00},{0x351e, 0x00},{0x351f, 0x00},{0x3520, 0x00},{0x3521, 0x80},{0x3522, 0x08},{0x3524, 0x08},{0x3526, 0x08},{0x3528, 0x08},{0x352a, 0x08},{0x3602, 0x00},{0x3603, 0x40},{0x3604, 0x02},{0x3605, 0x00},{0x3606, 0x00},{0x3607, 0x00},{0x3609, 0x12},{0x360a, 0x40},{0x360c, 0x08},{0x360f, 0xe5},{0x3608, 0x8f},{0x3611, 0x00},{0x3613, 0xf7},{0x3616, 0x58},{0x3619, 0x99},{0x361b, 0x60},{0x361c, 0x7a},{0x361e, 0x79},{0x361f, 0x02},{0x3632, 0x00},{0x3633, 0x10},{0x3634, 0x10},{0x3635, 0x10},{0x3636, 0x15},{0x3646, 0x86},{0x364a, 0x0b},{0x3700, 0x17},{0x3701, 0x22},{0x3703, 0x10},{0x370a, 0x37},{0x3705, 0x00},{0x3706, 0x63},{0x3709, 0x3c},{0x370b, 0x01},{0x370c, 0x30},{0x3710, 0x24},{0x3711, 0x0c},{0x3716, 0x00},{0x3720, 0x28},{0x3729, 0x7b},{0x372a, 0x84},{0x372b, 0xbd},{0x372c, 0xbc},{0x372e, 0x52},{0x373c, 0x0e},{0x373e, 0x33},{0x3743, 0x10},{0x3744, 0x88},{0x3745, 0xc0},{0x374a, 0x43},{0x374c, 0x00},{0x374e, 0x23},{0x3751, 0x7b},{0x3752, 0x84},{0x3753, 0xbd},{0x3754, 0xbc},{0x3756, 0x52},{0x375c, 0x00},{0x3760, 0x00},{0x3761, 0x00},{0x3762, 0x00},{0x3763, 0x00},{0x3764, 0x00},{0x3767, 0x04},{0x3768, 0x04},{0x3769, 0x08},{0x376a, 0x08},{0x376b, 0x20},{0x376c, 0x00},{0x376d, 0x00},{0x376e, 0x00},{0x3773, 0x00},{0x3774, 0x51},{0x3776, 0xbd},{0x3777, 0xbd},{0x3781, 0x18},{0x3783, 0x25},{0x3798, 0x1b},{0x3800, 0x01},{0x3801, 0x88},{0x3802, 0x00},{0x3803, 0xe0},{0x3804, 0x09},{0x3805, 0x17},{0x3806, 0x05},{0x3807, 0x1f},{0x3808, 0x07},{0x3809, 0x80},{0x380a, 0x04},{0x380b, 0x38},{0x380c, 0x04},{0x380d, 0x95},{0x380e, 0x04},{0x380f, 0x70},{0x3810, 0x00},{0x3811, 0x08},{0x3812, 0x00},{0x3813, 0x04},{0x3814, 0x01},{0x3815, 0x01},{0x3819, 0x01},{0x3820, 0x00},{0x3821, 0x06},{0x3829, 0x00},{0x382a, 0x01},{0x382b, 0x01},{0x382d, 0x7f},{0x3830, 0x04},{0x3836, 0x01},{0x3837, 0x00},{0x3841, 0x02},{0x3846, 0x08},{0x3847, 0x07},{0x3d85, 0x36},{0x3d8c, 0x71},{0x3d8d, 0xcb},{0x3f0a, 0x00},{0x4000, 0x71},{0x4001, 0x40},{0x4002, 0x04},{0x4003, 0x14},{0x400e, 0x00},{0x4011, 0x00},{0x401a, 0x00},{0x401b, 0x00},{0x401c, 0x00},{0x401d, 0x00},{0x401f, 0x00},{0x4020, 0x00},{0x4021, 0x10},{0x4022, 0x06},{0x4023, 0x13},{0x4024, 0x07},{0x4025, 0x40},{0x4026, 0x07},{0x4027, 0x50},{0x4028, 0x00},{0x4029, 0x02},{0x402a, 0x06},{0x402b, 0x04},{0x402c, 0x02},{0x402d, 0x02},{0x402e, 0x0e},{0x402f, 0x04},{0x4302, 0xff},{0x4303, 0xff},{0x4304, 0x00},{0x4305, 0x00},{0x4306, 0x00},{0x4308, 0x02},{0x4500, 0x6c},{0x4501, 0xc4},{0x4502, 0x40},{0x4503, 0x01},{0x4600, 0x00},{0x4601, 0x77},{0x4800, 0x04},{0x4813, 0x08},{0x481f, 0x40},{0x4829, 0x78},{0x4837, 0x14},{0x4b00, 0x2a},{0x4b0d, 0x00},{0x4d00, 0x04},{0x4d01, 0x42},{0x4d02, 0xd1},{0x4d03, 0x93},{0x4d04, 0xf5},{0x4d05, 0xc1},{0x5000, 0xf3},{0x5001, 0x11},{0x5004, 0x00},{0x500a, 0x00},{0x500b, 0x00},{0x5032, 0x00},{0x5040, 0x00},{0x5050, 0x0c},{0x5500, 0x00},{0x5501, 0x10},{0x5502, 0x01},{0x5503, 0x0f},{0x8000, 0x00},{0x8001, 0x00},{0x8002, 0x00},{0x8003, 0x00},{0x8004, 0x00},{0x8005, 0x00},{0x8006, 0x00},{0x8007, 0x00},{0x8008, 0x00},{0x3638, 0x00},{REG_NULL, 0x00},};static const struct regval ov4689_1920x1080_120fps_regs[] = {{0x0103, 0x01},{0x3638, 0x00},{0x0300, 0x00},{0x0302, 0x2a},/* 1008Mbps */{0x0303, 0x00},{0x0304, 0x03},{0x030b, 0x00},{0x030d, 0x1e},{0x030e, 0x04},{0x030f, 0x01},{0x0312, 0x01},{0x031e, 0x00},{0x3000, 0x20},{0x3002, 0x00},{0x3018, 0x72},/* 0x32: 2 lanes, 0x72: 4 lanes */{0x3019, 0x00},/* 0x0c: 2 lanes, 0x00: 4 lanes */{0x3020, 0x93},{0x3021, 0x03},{0x3022, 0x01},{0x3031, 0x0a},{0x303f, 0x0c},{0x3305, 0xf1},{0x3307, 0x04},{0x3309, 0x29},{0x3500, 0x00},{0x3501, 0x30},{0x3502, 0x00},{0x3503, 0x04},{0x3504, 0x00},{0x3505, 0x00},{0x3506, 0x00},{0x3507, 0x00},{0x3508, 0x07},{0x3509, 0x78},{0x350a, 0x00},{0x350b, 0x00},{0x350c, 0x00},{0x350d, 0x00},{0x350e, 0x00},{0x350f, 0x80},{0x3510, 0x00},{0x3511, 0x00},{0x3512, 0x00},{0x3513, 0x00},{0x3514, 0x00},{0x3515, 0x80},{0x3516, 0x00},{0x3517, 0x00},{0x3518, 0x00},{0x3519, 0x00},{0x351a, 0x00},{0x351b, 0x80},{0x351c, 0x00},{0x351d, 0x00},{0x351e, 0x00},{0x351f, 0x00},{0x3520, 0x00},{0x3521, 0x80},{0x3522, 0x08},{0x3524, 0x08},{0x3526, 0x08},{0x3528, 0x08},{0x352a, 0x08},{0x3602, 0x00},{0x3603, 0x40},{0x3604, 0x02},{0x3605, 0x00},{0x3606, 0x00},{0x3607, 0x00},{0x3609, 0x12},{0x360a, 0x40},{0x360c, 0x08},{0x360f, 0xe5},{0x3608, 0x8f},{0x3611, 0x00},{0x3613, 0xf7},{0x3616, 0x58},{0x3619, 0x99},{0x361b, 0x60},{0x361c, 0x7a},{0x361e, 0x79},{0x361f, 0x02},{0x3632, 0x00},{0x3633, 0x10},{0x3634, 0x10},{0x3635, 0x10},{0x3636, 0x15},{0x3646, 0x86},{0x364a, 0x0b},{0x3700, 0x17},{0x3701, 0x22},{0x3703, 0x10},{0x370a, 0x37},{0x3705, 0x00},{0x3706, 0x63},{0x3709, 0x3c},{0x370b, 0x01},{0x370c, 0x30},{0x3710, 0x24},{0x3711, 0x0c},{0x3716, 0x00},{0x3720, 0x28},{0x3729, 0x7b},{0x372a, 0x84},{0x372b, 0xbd},{0x372c, 0xbc},{0x372e, 0x52},{0x373c, 0x0e},{0x373e, 0x33},{0x3743, 0x10},{0x3744, 0x88},{0x3745, 0xc0},{0x374a, 0x43},{0x374c, 0x00},{0x374e, 0x23},{0x3751, 0x7b},{0x3752, 0x84},{0x3753, 0xbd},{0x3754, 0xbc},{0x3756, 0x52},{0x375c, 0x00},{0x3760, 0x00},{0x3761, 0x00},{0x3762, 0x00},{0x3763, 0x00},{0x3764, 0x00},{0x3767, 0x04},{0x3768, 0x04},{0x3769, 0x08},{0x376a, 0x08},{0x376b, 0x20},{0x376c, 0x00},{0x376d, 0x00},{0x376e, 0x00},{0x3773, 0x00},{0x3774, 0x51},{0x3776, 0xbd},{0x3777, 0xbd},{0x3781, 0x18},{0x3783, 0x25},{0x3798, 0x1b},{0x3800, 0x01},{0x3801, 0x88},{0x3802, 0x00},{0x3803, 0xe0},{0x3804, 0x09},{0x3805, 0x17},{0x3806, 0x05},{0x3807, 0x1f},{0x3808, 0x07},{0x3809, 0x80},{0x380a, 0x04},{0x380b, 0x38},{0x380c, 0x03},{0x380d, 0x70},{0x380e, 0x04},{0x380f, 0x70},{0x3810, 0x00},{0x3811, 0x08},{0x3812, 0x00},{0x3813, 0x04},{0x3814, 0x01},{0x3815, 0x01},{0x3819, 0x01},{0x3820, 0x00},{0x3821, 0x06},{0x3829, 0x00},{0x382a, 0x01},{0x382b, 0x01},{0x382d, 0x7f},{0x3830, 0x04},{0x3836, 0x01},{0x3837, 0x00},{0x3841, 0x02},{0x3846, 0x08},{0x3847, 0x07},{0x3d85, 0x36},{0x3d8c, 0x71},{0x3d8d, 0xcb},{0x3f0a, 0x00},{0x4000, 0x71},{0x4001, 0x40},{0x4002, 0x04},{0x4003, 0x14},{0x400e, 0x00},{0x4011, 0x00},{0x401a, 0x00},{0x401b, 0x00},{0x401c, 0x00},{0x401d, 0x00},{0x401f, 0x00},{0x4020, 0x00},{0x4021, 0x10},{0x4022, 0x06},{0x4023, 0x13},{0x4024, 0x07},{0x4025, 0x40},{0x4026, 0x07},{0x4027, 0x50},{0x4028, 0x00},{0x4029, 0x02},{0x402a, 0x06},{0x402b, 0x04},{0x402c, 0x02},{0x402d, 0x02},{0x402e, 0x0e},{0x402f, 0x04},{0x4302, 0xff},{0x4303, 0xff},{0x4304, 0x00},{0x4305, 0x00},{0x4306, 0x00},{0x4308, 0x02},{0x4500, 0x6c},{0x4501, 0xc4},{0x4502, 0x40},{0x4503, 0x01},{0x4600, 0x00},{0x4601, 0x77},{0x4800, 0x04},{0x4813, 0x08},{0x481f, 0x40},{0x4829, 0x78},{0x4837, 0x14},{0x4b00, 0x2a},{0x4b0d, 0x00},{0x4d00, 0x04},{0x4d01, 0x42},{0x4d02, 0xd1},{0x4d03, 0x93},{0x4d04, 0xf5},{0x4d05, 0xc1},{0x5000, 0xf3},{0x5001, 0x11},{0x5004, 0x00},{0x500a, 0x00},{0x500b, 0x00},{0x5032, 0x00},{0x5040, 0x00},{0x5050, 0x0c},{0x5500, 0x00},{0x5501, 0x10},{0x5502, 0x01},{0x5503, 0x0f},{0x8000, 0x00},{0x8001, 0x00},{0x8002, 0x00},{0x8003, 0x00},{0x8004, 0x00},{0x8005, 0x00},{0x8006, 0x00},{0x8007, 0x00},{0x8008, 0x00},{0x3638, 0x00},{REG_NULL, 0x00},};static const struct ov4689_mode supported_modes[] = {#if 0{.width = 1920,.height = 1080,.max_fps = 75,.exp_def = 0x0460,.hts_def = 0x057f,.vts_def = 0x0470,.reg_list = ov4689_1920x1080_regs,},{.width = 1920,.height = 1080,.max_fps = 90,.exp_def = 0x0460,.hts_def = 0x0495,/* 1173 */.vts_def = 0x0470,/* 1136 */.reg_list = ov4689_1920x1080_90fps_regs,},#endif{.width = 1920,.height = 1080,.max_fps = 90,.exp_def = 0x0460,.hts_def = 0x0370,/* 880 */.vts_def = 0x0470,/* 1136 */.reg_list = ov4689_1920x1080_120fps_regs,},#if 0{.width = 2688,.height = 1520,.max_fps = 30,.exp_def = 0x0600,.hts_def = 0x0a18,.vts_def = 0x0612,.reg_list = ov4689_2688x1520_regs,},{.width = 1280,.height = 720,.max_fps = 120,.exp_def = 0x0300,.hts_def = 0x050d,.vts_def = 0x0305,.reg_list = ov4689_1280x720_regs,},#endif};static const s64 link_freq_menu_items[] = {OV4689_LINK_FREQ_500MHZ};static const char * const ov4689_test_pattern_menu[] = {"Disabled","Vertical Color Bar Type 1","Vertical Color Bar Type 2","Vertical Color Bar Type 3","Vertical Color Bar Type 4"};/* Write registers up to 4 at a time */static int ov4689_write_reg(struct i2c_client *client, u16 reg, u32 len, u32 val){u32 buf_i, val_i;u8 buf[6];u8 *val_p;__be32 val_be;if (len > 4)return -EINVAL;buf[0] = reg >> 8;buf[1] = reg & 0xff;val_be = cpu_to_be32(val);val_p = (u8 *)&val_be;buf_i = 2;val_i = 4 - len;while (val_i 4 || !len)return -EINVAL;data_be_p = (u8 *)&data_be;/* Write register address */msgs[0].addr = client->addr;msgs[0].flags = 0;msgs[0].len = 2;msgs[0].buf = (u8 *)®_addr_be;/* Read data from register */msgs[1].addr = client->addr;msgs[1].flags = I2C_M_RD;msgs[1].len = len;msgs[1].buf = &data_be_p[4 - len];ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));if (ret != ARRAY_SIZE(msgs))return -EIO;*val = be32_to_cpu(data_be);return 0;}static int ov4689_get_reso_dist(const struct ov4689_mode *mode,struct v4l2_mbus_framefmt *framefmt){return abs(mode->width - framefmt->width) +abs(mode->height - framefmt->height);}static const struct ov4689_mode *ov4689_find_best_fit(struct v4l2_subdev_format *fmt){struct v4l2_mbus_framefmt *framefmt = &fmt->format;int dist;int cur_best_fit = 0;int cur_best_fit_dist = -1;unsigned int i;for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {dist = ov4689_get_reso_dist(&supported_modes[i], framefmt);if (cur_best_fit_dist == -1 || dist mutex);mode = ov4689_find_best_fit(fmt);fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;fmt->format.width = mode->width;fmt->format.height = mode->height;fmt->format.field = V4L2_FIELD_NONE;if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;#elsemutex_unlock(&ov4689->mutex);return -ENOTTY;#endif} else {ov4689->cur_mode = mode;h_blank = mode->hts_def - mode->width;__v4l2_ctrl_modify_range(ov4689->hblank, h_blank, h_blank, 1, h_blank);vblank_def = mode->vts_def - mode->height;__v4l2_ctrl_modify_range(ov4689->vblank, vblank_def, OV4689_VTS_MAX - mode->height, 1, vblank_def);}mutex_unlock(&ov4689->mutex);return 0;}static int ov4689_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt){struct ov4689 *ov4689 = to_ov4689(sd);const struct ov4689_mode *mode = ov4689->cur_mode;mutex_lock(&ov4689->mutex);if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIfmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);#elsemutex_unlock(&ov4689->mutex);return -ENOTTY;#endif} else {fmt->format.width = mode->width;fmt->format.height = mode->height;fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;fmt->format.field = V4L2_FIELD_NONE;}mutex_unlock(&ov4689->mutex);return 0;}static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code){if (code->index != 0)return -EINVAL;code->code = MEDIA_BUS_FMT_SBGGR10_1X10;return 0;}static int ov4689_enum_frame_sizes(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse){if (fse->index >= ARRAY_SIZE(supported_modes))return -EINVAL;if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)return -EINVAL;fse->min_width = supported_modes[fse->index].width;fse->max_width = supported_modes[fse->index].width;fse->max_height = supported_modes[fse->index].height;fse->min_height = supported_modes[fse->index].height;return 0;}static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern){u32 val;if (pattern)val = (pattern - 1) | OV4689_TEST_PATTERN_ENABLE;elseval = OV4689_TEST_PATTERN_DISABLE;return ov4689_write_reg(ov4689->client, OV4689_REG_TEST_PATTERN,OV4689_REG_VALUE_08BIT, val);}static int ov4689_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi){struct ov4689 *ov4689 = to_ov4689(sd);const struct ov4689_mode *mode = ov4689->cur_mode;mutex_lock(&ov4689->mutex);fi->interval.numerator = 10000;fi->interval.denominator = mode->max_fps * 10000;mutex_unlock(&ov4689->mutex);return 0;}static void ov4689_get_module_inf(struct ov4689 *ov4689, struct rkmodule_inf *inf){memset(inf, 0, sizeof(*inf));strlcpy(inf->base.sensor, OV4689_NAME, sizeof(inf->base.sensor));strlcpy(inf->base.module, ov4689->module_name,sizeof(inf->base.module));strlcpy(inf->base.lens, ov4689->len_name, sizeof(inf->base.lens));}static long ov4689_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg){struct ov4689 *ov4689 = to_ov4689(sd);long ret = 0;switch (cmd) {case RKMODULE_GET_MODULE_INFO:if (ov4689->module_name)ov4689_get_module_inf(ov4689, (struct rkmodule_inf *)arg);elseret = -ENOIOCTLCMD;break;default:ret = -ENOIOCTLCMD;break;}return ret;}#ifdef CONFIG_COMPATstatic long ov4689_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg){void __user *up = compat_ptr(arg);struct rkmodule_inf *inf;struct rkmodule_awb_cfg *cfg;long ret;switch (cmd) {case RKMODULE_GET_MODULE_INFO:inf = kzalloc(sizeof(*inf), GFP_KERNEL);if (!inf) {ret = -ENOMEM;return ret;}ret = ov4689_ioctl(sd, cmd, inf);if (!ret)ret = copy_to_user(up, inf, sizeof(*inf));kfree(inf);break;case RKMODULE_AWB_CFG:cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);if (!cfg) {ret = -ENOMEM;return ret;}ret = copy_from_user(cfg, up, sizeof(*cfg));if (!ret)ret = ov4689_ioctl(sd, cmd, cfg);kfree(cfg);break;default:ret = -ENOIOCTLCMD;break;}return ret;}#endifstatic int __ov4689_start_stream(struct ov4689 *ov4689){int ret;ret = ov4689_write_array(ov4689->client, ov4689->cur_mode->reg_list);if (ret)return ret;/* In case these controls are set before streaming */mutex_unlock(&ov4689->mutex);ret = v4l2_ctrl_handler_setup(&ov4689->ctrl_handler);mutex_lock(&ov4689->mutex);if (ret)return ret; return ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,OV4689_REG_VALUE_08BIT, OV4689_MODE_STREAMING);}static int __ov4689_stop_stream(struct ov4689 *ov4689){return ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,OV4689_REG_VALUE_08BIT, OV4689_MODE_SW_STANDBY);}static int ov4689_s_stream(struct v4l2_subdev *sd, int on){struct ov4689 *ov4689 = to_ov4689(sd);struct i2c_client *client = ov4689->client;int ret = 0;mutex_lock(&ov4689->mutex);on = !!on;if (on == ov4689->streaming)goto unlock_and_return;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret dev);goto unlock_and_return;}ret = __ov4689_start_stream(ov4689);if (ret) {v4l2_err(sd, "start stream failed while write regs\n");pm_runtime_put(&client->dev);goto unlock_and_return;}} else {__ov4689_stop_stream(ov4689);pm_runtime_put(&client->dev);}ov4689->streaming = on;unlock_and_return:mutex_unlock(&ov4689->mutex);return ret;}static int ov4689_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg){cfg->type = V4L2_MBUS_CSI2;/* Support for non-continuous CSI-2 clock is missing in the driver */cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;switch (OV4689_LANES) {case 2:cfg->flags |= V4L2_MBUS_CSI2_2_LANE;break;case 4:cfg->flags |= V4L2_MBUS_CSI2_4_LANE;break;default:cfg->flags |= V4L2_MBUS_CSI2_2_LANE;break;}return 0;}static int ov4689_s_power(struct v4l2_subdev *sd, int on){struct ov4689 *ov4689 = to_ov4689(sd);struct i2c_client *client = ov4689->client;int ret = 0;mutex_lock(&ov4689->mutex);/* If the power state is not modified - no work to do. */if (ov4689->power_on == !!on)goto unlock_and_return;if (on) {ret = pm_runtime_get_sync(&client->dev);if (ret dev);goto unlock_and_return;}ret = ov4689_write_array(ov4689->client, ov4689_global_regs);if (ret) {v4l2_err(sd, "could not set init registers\n");pm_runtime_put_noidle(&client->dev);goto unlock_and_return;}ov4689->power_on = true;} else {pm_runtime_put(&client->dev);ov4689->power_on = false;}unlock_and_return:mutex_unlock(&ov4689->mutex);return ret;}/* Calculate the delay in us by clock rate and clock cycles */static inline u32 ov4689_cal_delay(u32 cycles){return DIV_ROUND_UP(cycles, OV4689_XVCLK_FREQ / 1000 / 1000);}static int __ov4689_power_on(struct ov4689 *ov4689){int ret;u32 delay_us;struct device *dev = &ov4689->client->dev;if (!IS_ERR_OR_NULL(ov4689->pins_default)) {ret = pinctrl_select_state(ov4689->pinctrl, ov4689->pins_default);if (ret xvclk);if (ret reset_gpio))gpiod_set_value_cansleep(ov4689->reset_gpio, 0);ret = regulator_bulk_enable(OV4689_NUM_SUPPLIES, ov4689->supplies);if (ret reset_gpio))gpiod_set_value_cansleep(ov4689->reset_gpio, 1);usleep_range(500, 1000);if (!IS_ERR(ov4689->pwdn_gpio))gpiod_set_value_cansleep(ov4689->pwdn_gpio, 1);/* 8192 cycles prior to first SCCB transaction */delay_us = ov4689_cal_delay(8192);usleep_range(delay_us, delay_us * 2);return 0;disable_clk:clk_disable_unprepare(ov4689->xvclk);return ret;}static void __ov4689_power_off(struct ov4689 *ov4689){int ret;struct device *dev = &ov4689->client->dev;if (!IS_ERR(ov4689->pwdn_gpio))gpiod_set_value_cansleep(ov4689->pwdn_gpio, 0);clk_disable_unprepare(ov4689->xvclk);if (!IS_ERR(ov4689->reset_gpio))gpiod_set_value_cansleep(ov4689->reset_gpio, 0);if (!IS_ERR_OR_NULL(ov4689->pins_sleep)) {ret = pinctrl_select_state(ov4689->pinctrl, ov4689->pins_sleep);if (ret supplies);}static int ov4689_runtime_resume(struct device *dev){struct i2c_client *client = to_i2c_client(dev);struct v4l2_subdev *sd = i2c_get_clientdata(client);struct ov4689 *ov4689 = to_ov4689(sd);return __ov4689_power_on(ov4689);}static int ov4689_runtime_suspend(struct device *dev){struct i2c_client *client = to_i2c_client(dev);struct v4l2_subdev *sd = i2c_get_clientdata(client);struct ov4689 *ov4689 = to_ov4689(sd);__ov4689_power_off(ov4689);return 0;}#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIstatic int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh){struct ov4689 *ov4689 = to_ov4689(sd);struct v4l2_mbus_framefmt *try_fmt =v4l2_subdev_get_try_format(sd, fh->pad, 0);const struct ov4689_mode *def_mode = &supported_modes[0];mutex_lock(&ov4689->mutex);/* Initialize try_fmt */try_fmt->width = def_mode->width;try_fmt->height = def_mode->height;try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;try_fmt->field = V4L2_FIELD_NONE;mutex_unlock(&ov4689->mutex);/* No crop or compose */return 0;}#endifstatic const struct dev_pm_ops ov4689_pm_ops = {SET_RUNTIME_PM_OPS(ov4689_runtime_suspend, ov4689_runtime_resume, NULL)};#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIstatic const struct v4l2_subdev_internal_ops ov4689_internal_ops = {.open = ov4689_open,};#endifstatic const struct v4l2_subdev_core_ops ov4689_core_ops = {.s_power = ov4689_s_power,.ioctl = ov4689_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl32 = ov4689_compat_ioctl32,#endif};static const struct v4l2_subdev_video_ops ov4689_video_ops = {.s_stream = ov4689_s_stream,.g_frame_interval = ov4689_g_frame_interval,.g_mbus_config = ov4689_g_mbus_config,};static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {.enum_mbus_code = ov4689_enum_mbus_code,.enum_frame_size = ov4689_enum_frame_sizes,.get_fmt = ov4689_get_fmt,.set_fmt = ov4689_set_fmt,};static const struct v4l2_subdev_ops ov4689_subdev_ops = {.core= &ov4689_core_ops,.video= &ov4689_video_ops,.pad= &ov4689_pad_ops,};static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl){struct ov4689 *ov4689 = container_of(ctrl->handler, struct ov4689, ctrl_handler);struct i2c_client *client = ov4689->client;s64 max;int ret = 0;/* Propagate change of current control to all related controls */switch (ctrl->id) {case V4L2_CID_VBLANK:/* Update max exposure while meeting expected vblanking */max = ov4689->cur_mode->height + ctrl->val - 4;__v4l2_ctrl_modify_range(ov4689->exposure, ov4689->exposure->minimum, max, ov4689->exposure->step, ov4689->exposure->default_value);break;}if (pm_runtime_get(&client->dev) id) {case V4L2_CID_EXPOSURE:/* 4 least significant bits of expsoure are fractional part */ret = ov4689_write_reg(ov4689->client, OV4689_REG_EXPOSURE,OV4689_REG_VALUE_24BIT, ctrl->val <client, OV4689_REG_GAIN_H,OV4689_REG_VALUE_08BIT,(ctrl->val >> OV4689_GAIN_H_SHIFT) & OV4689_GAIN_H_MASK);ret |= ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_L,OV4689_REG_VALUE_08BIT,ctrl->val & OV4689_GAIN_L_MASK);break;case V4L2_CID_VBLANK:ret = ov4689_write_reg(ov4689->client, OV4689_REG_VTS,OV4689_REG_VALUE_16BIT,ctrl->val + ov4689->cur_mode->height);break;case V4L2_CID_TEST_PATTERN:ret = ov4689_enable_test_pattern(ov4689, ctrl->val);break;default:dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val);break;}pm_runtime_put(&client->dev);return ret;}static const struct v4l2_ctrl_ops ov4689_ctrl_ops = {.s_ctrl = ov4689_set_ctrl,};static int ov4689_initialize_controls(struct ov4689 *ov4689){const struct ov4689_mode *mode;struct v4l2_ctrl_handler *handler;struct v4l2_ctrl *ctrl;s64 exposure_max, vblank_def;u32 h_blank;int ret;handler = &ov4689->ctrl_handler;mode = ov4689->cur_mode;ret = v4l2_ctrl_handler_init(handler, 8);if (ret)return ret;handler->lock = &ov4689->mutex;ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, link_freq_menu_items);if (ctrl)ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, OV4689_PIXEL_RATE, 1, OV4689_PIXEL_RATE);h_blank = mode->hts_def - mode->width;ov4689->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,h_blank, h_blank, 1, h_blank);if (ov4689->hblank)ov4689->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;vblank_def = mode->vts_def - mode->height;ov4689->vblank = v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops,V4L2_CID_VBLANK, vblank_def,OV4689_VTS_MAX - mode->height,1, vblank_def);exposure_max = mode->vts_def - 4;ov4689->exposure = v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops,V4L2_CID_EXPOSURE, OV4689_EXPOSURE_MIN,exposure_max, OV4689_EXPOSURE_STEP,mode->exp_def);ov4689->anal_gain = v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops,V4L2_CID_ANALOGUE_GAIN, OV4689_GAIN_MIN,OV4689_GAIN_MAX, OV4689_GAIN_STEP,OV4689_GAIN_DEFAULT);ov4689->test_pattern = v4l2_ctrl_new_std_menu_items(handler,&ov4689_ctrl_ops, V4L2_CID_TEST_PATTERN,ARRAY_SIZE(ov4689_test_pattern_menu) - 1,0, 0, ov4689_test_pattern_menu);if (handler->error) {ret = handler->error;dev_err(&ov4689->client->dev,"Failed to init controls(%d)\n", ret);goto err_free_handler;}ov4689->subdev.ctrl_handler = handler;return 0;err_free_handler:v4l2_ctrl_handler_free(handler);return ret;}static int ov4689_check_sensor_id(struct ov4689 *ov4689, struct i2c_client *client){struct device *dev = &ov4689->client->dev;u32 id = 0;int ret;ret = ov4689_read_reg(client, OV4689_REG_CHIP_ID, OV4689_REG_VALUE_16BIT, &id);if (id != CHIP_ID) {dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);return -ENODEV;}dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);return 0;}static int ov4689_configure_regulators(struct ov4689 *ov4689){unsigned int i;for (i = 0; i supplies[i].supply = ov4689_supply_names[i];return devm_regulator_bulk_get(&ov4689->client->dev,OV4689_NUM_SUPPLIES,ov4689->supplies);}static int ov4689_probe(struct i2c_client *client,const struct i2c_device_id *id){struct device *dev = &client->dev;struct device_node *node = dev->of_node;struct ov4689 *ov4689;struct v4l2_subdev *sd;char facing[2];int ret;dev_info(dev, "driver version: %02x.%02x.%02x",DRIVER_VERSION >> 16,(DRIVER_VERSION & 0xff00) >> 8,DRIVER_VERSION & 0x00ff);ov4689 = devm_kzalloc(dev, sizeof(*ov4689), GFP_KERNEL);if (!ov4689)return -ENOMEM;ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, &ov4689->module_index);ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,&ov4689->module_facing);ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,&ov4689->module_name);ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,&ov4689->len_name);if (ret) {dev_warn(dev, "could not get module information!\n");}ov4689->client = client;ov4689->cur_mode = &supported_modes[0];ov4689->xvclk = devm_clk_get(dev, "xvclk");if (IS_ERR(ov4689->xvclk)) {dev_err(dev, "Failed to get xvclk\n");return -EINVAL;}ret = clk_set_rate(ov4689->xvclk, OV4689_XVCLK_FREQ);if (ret xvclk) != OV4689_XVCLK_FREQ)dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");ov4689->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);if (IS_ERR(ov4689->reset_gpio))dev_warn(dev, "Failed to get reset-gpios\n");ov4689->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);if (IS_ERR(ov4689->pwdn_gpio))dev_warn(dev, "Failed to get pwdn-gpios\n");ov4689->pinctrl = devm_pinctrl_get(dev);if (!IS_ERR(ov4689->pinctrl)) {ov4689->pins_default =pinctrl_lookup_state(ov4689->pinctrl, OF_CAMERA_PINCTRL_STATE_DEFAULT);if (IS_ERR(ov4689->pins_default))dev_err(dev, "could not get default pinstate\n");ov4689->pins_sleep =pinctrl_lookup_state(ov4689->pinctrl, OF_CAMERA_PINCTRL_STATE_SLEEP);if (IS_ERR(ov4689->pins_sleep))dev_err(dev, "could not get sleep pinstate\n");} else {dev_err(dev, "no pinctrl\n");}ret = ov4689_configure_regulators(ov4689);if (ret) {dev_err(dev, "Failed to get power regulators\n");return ret;}mutex_init(&ov4689->mutex);sd = &ov4689->subdev;v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops);ret = ov4689_initialize_controls(ov4689);if (ret)goto err_destroy_mutex;ret = __ov4689_power_on(ov4689);if (ret)goto err_free_handler;ret = ov4689_check_sensor_id(ov4689, client);if (ret)goto err_power_off;#ifdef CONFIG_VIDEO_V4L2_SUBDEV_APIsd->internal_ops = &ov4689_internal_ops;sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;#endif#if defined(CONFIG_MEDIA_CONTROLLER)ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;ret = media_entity_init(&sd->entity, 1, &ov4689->pad, 0);if (ret module_facing && ov4689->module_name) {memset(facing, 0, sizeof(facing));if (strcmp(ov4689->module_facing, "back") == 0)facing[0] = 'b';elsefacing[0] = 'f';snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", ov4689->module_index, facing, OV4689_NAME, dev_name(sd->dev));}ret = v4l2_async_register_subdev_sensor_common(sd);if (ret) {dev_err(dev, "v4l2 async register subdev failed\n");goto err_clean_entity;}pm_runtime_set_active(dev);pm_runtime_enable(dev);pm_runtime_idle(dev);return 0;err_clean_entity:#if defined(CONFIG_MEDIA_CONTROLLER)media_entity_cleanup(&sd->entity);#endiferr_power_off:__ov4689_power_off(ov4689);err_free_handler:v4l2_ctrl_handler_free(&ov4689->ctrl_handler);err_destroy_mutex:mutex_destroy(&ov4689->mutex);return ret;}static int ov4689_remove(struct i2c_client *client){struct v4l2_subdev *sd = i2c_get_clientdata(client);struct ov4689 *ov4689 = to_ov4689(sd);v4l2_async_unregister_subdev(sd);#if defined(CONFIG_MEDIA_CONTROLLER)media_entity_cleanup(&sd->entity);#endifv4l2_ctrl_handler_free(&ov4689->ctrl_handler);mutex_destroy(&ov4689->mutex);pm_runtime_disable(&client->dev);if (!pm_runtime_status_suspended(&client->dev))__ov4689_power_off(ov4689);pm_runtime_set_suspended(&client->dev);return 0;}#if IS_ENABLED(CONFIG_OF)static const struct of_device_id ov4689_of_match[] = {{ .compatible = "ovti,ov4689" },{},};MODULE_DEVICE_TABLE(of, ov4689_of_match);#endifstatic const struct i2c_device_id ov4689_match_id[] = {{ "ovti,ov4689", 0 },{ },};static struct i2c_driver ov4689_i2c_driver = {.driver = {.name = OV4689_NAME,.pm = &ov4689_pm_ops,.of_match_table = of_match_ptr(ov4689_of_match),},.probe= &ov4689_probe,.remove= &ov4689_remove,.id_table= ov4689_match_id,};static int __init sensor_mod_init(void){return i2c_add_driver(&ov4689_i2c_driver);}static void __exit sensor_mod_exit(void){i2c_del_driver(&ov4689_i2c_driver);}device_initcall_sync(sensor_mod_init);module_exit(sensor_mod_exit);MODULE_DESCRIPTION("OmniVision ov4689 sensor driver");MODULE_LICENSE("GPL v2");