xref: /linux/drivers/media/i2c/ov13b10.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
17ee85054SArec Kao // SPDX-License-Identifier: GPL-2.0
27ee85054SArec Kao // Copyright (c) 2021 Intel Corporation.
37ee85054SArec Kao 
47ee85054SArec Kao #include <linux/acpi.h>
56e28afd1SBingbu Cao #include <linux/clk.h>
66e28afd1SBingbu Cao #include <linux/delay.h>
76e28afd1SBingbu Cao #include <linux/gpio/consumer.h>
87ee85054SArec Kao #include <linux/i2c.h>
97ee85054SArec Kao #include <linux/module.h>
107ee85054SArec Kao #include <linux/pm_runtime.h>
117ee85054SArec Kao #include <media/v4l2-ctrls.h>
127ee85054SArec Kao #include <media/v4l2-device.h>
137ee85054SArec Kao #include <media/v4l2-fwnode.h>
147ee85054SArec Kao 
157ee85054SArec Kao #define OV13B10_REG_VALUE_08BIT		1
167ee85054SArec Kao #define OV13B10_REG_VALUE_16BIT		2
177ee85054SArec Kao #define OV13B10_REG_VALUE_24BIT		3
187ee85054SArec Kao 
197ee85054SArec Kao #define OV13B10_REG_MODE_SELECT		0x0100
207ee85054SArec Kao #define OV13B10_MODE_STANDBY		0x00
217ee85054SArec Kao #define OV13B10_MODE_STREAMING		0x01
227ee85054SArec Kao 
237ee85054SArec Kao #define OV13B10_REG_SOFTWARE_RST	0x0103
247ee85054SArec Kao #define OV13B10_SOFTWARE_RST		0x01
257ee85054SArec Kao 
267ee85054SArec Kao /* Chip ID */
277ee85054SArec Kao #define OV13B10_REG_CHIP_ID		0x300a
287ee85054SArec Kao #define OV13B10_CHIP_ID			0x560d42
297ee85054SArec Kao 
307ee85054SArec Kao /* V_TIMING internal */
317ee85054SArec Kao #define OV13B10_REG_VTS			0x380e
327ee85054SArec Kao #define OV13B10_VTS_30FPS		0x0c7c
337ee85054SArec Kao #define OV13B10_VTS_60FPS		0x063e
34397b2a25SHao Yao #define OV13B10_VTS_120FPS		0x0320
357ee85054SArec Kao #define OV13B10_VTS_MAX			0x7fff
367ee85054SArec Kao 
377ee85054SArec Kao /* HBLANK control - read only */
387ee85054SArec Kao #define OV13B10_PPL_560MHZ		4704
397ee85054SArec Kao 
407ee85054SArec Kao /* Exposure control */
417ee85054SArec Kao #define OV13B10_REG_EXPOSURE		0x3500
427ee85054SArec Kao #define OV13B10_EXPOSURE_MIN		4
437ee85054SArec Kao #define OV13B10_EXPOSURE_STEP		1
447ee85054SArec Kao #define OV13B10_EXPOSURE_DEFAULT	0x40
457ee85054SArec Kao 
467ee85054SArec Kao /* Analog gain control */
477ee85054SArec Kao #define OV13B10_REG_ANALOG_GAIN		0x3508
487ee85054SArec Kao #define OV13B10_ANA_GAIN_MIN		0x80
497ee85054SArec Kao #define OV13B10_ANA_GAIN_MAX		0x07c0
507ee85054SArec Kao #define OV13B10_ANA_GAIN_STEP		1
517ee85054SArec Kao #define OV13B10_ANA_GAIN_DEFAULT	0x80
527ee85054SArec Kao 
537ee85054SArec Kao /* Digital gain control */
547ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_H		0x350a
557ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_M		0x350b
567ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_L		0x350c
577ee85054SArec Kao 
587ee85054SArec Kao #define OV13B10_DGTL_GAIN_MIN		1024	     /* Min = 1 X */
597ee85054SArec Kao #define OV13B10_DGTL_GAIN_MAX		(4096 - 1)   /* Max = 4 X */
607ee85054SArec Kao #define OV13B10_DGTL_GAIN_DEFAULT	2560	     /* Default gain = 2.5 X */
617ee85054SArec Kao #define OV13B10_DGTL_GAIN_STEP		1	     /* Each step = 1/1024 */
627ee85054SArec Kao 
637ee85054SArec Kao #define OV13B10_DGTL_GAIN_L_SHIFT	6
647ee85054SArec Kao #define OV13B10_DGTL_GAIN_L_MASK	0x3
657ee85054SArec Kao #define OV13B10_DGTL_GAIN_M_SHIFT	2
667ee85054SArec Kao #define OV13B10_DGTL_GAIN_M_MASK	0xff
677ee85054SArec Kao #define OV13B10_DGTL_GAIN_H_SHIFT	10
687ee85054SArec Kao #define OV13B10_DGTL_GAIN_H_MASK	0x3
697ee85054SArec Kao 
707ee85054SArec Kao /* Test Pattern Control */
717ee85054SArec Kao #define OV13B10_REG_TEST_PATTERN	0x5080
727ee85054SArec Kao #define OV13B10_TEST_PATTERN_ENABLE	BIT(7)
737ee85054SArec Kao #define OV13B10_TEST_PATTERN_MASK	0xf3
747ee85054SArec Kao #define OV13B10_TEST_PATTERN_BAR_SHIFT	2
757ee85054SArec Kao 
767ee85054SArec Kao /* Flip Control */
777ee85054SArec Kao #define OV13B10_REG_FORMAT1		0x3820
787ee85054SArec Kao #define OV13B10_REG_FORMAT2		0x3821
797ee85054SArec Kao 
807ee85054SArec Kao /* Horizontal Window Offset */
817ee85054SArec Kao #define OV13B10_REG_H_WIN_OFFSET	0x3811
827ee85054SArec Kao 
837ee85054SArec Kao /* Vertical Window Offset */
847ee85054SArec Kao #define OV13B10_REG_V_WIN_OFFSET	0x3813
857ee85054SArec Kao 
867ee85054SArec Kao struct ov13b10_reg {
877ee85054SArec Kao 	u16 address;
887ee85054SArec Kao 	u8 val;
897ee85054SArec Kao };
907ee85054SArec Kao 
917ee85054SArec Kao struct ov13b10_reg_list {
927ee85054SArec Kao 	u32 num_of_regs;
937ee85054SArec Kao 	const struct ov13b10_reg *regs;
947ee85054SArec Kao };
957ee85054SArec Kao 
967ee85054SArec Kao /* Link frequency config */
977ee85054SArec Kao struct ov13b10_link_freq_config {
987ee85054SArec Kao 	u32 pixels_per_line;
997ee85054SArec Kao 
1007ee85054SArec Kao 	/* registers for this link frequency */
1017ee85054SArec Kao 	struct ov13b10_reg_list reg_list;
1027ee85054SArec Kao };
1037ee85054SArec Kao 
1047ee85054SArec Kao /* Mode : resolution and related config&values */
1057ee85054SArec Kao struct ov13b10_mode {
1067ee85054SArec Kao 	/* Frame width */
1077ee85054SArec Kao 	u32 width;
1087ee85054SArec Kao 	/* Frame height */
1097ee85054SArec Kao 	u32 height;
1107ee85054SArec Kao 
1117ee85054SArec Kao 	/* V-timing */
1127ee85054SArec Kao 	u32 vts_def;
1137ee85054SArec Kao 	u32 vts_min;
1147ee85054SArec Kao 
1157ee85054SArec Kao 	/* Index of Link frequency config to be used */
1167ee85054SArec Kao 	u32 link_freq_index;
1177ee85054SArec Kao 	/* Default register values */
1187ee85054SArec Kao 	struct ov13b10_reg_list reg_list;
1197ee85054SArec Kao };
1207ee85054SArec Kao 
1217ee85054SArec Kao /* 4208x3120 needs 1120Mbps/lane, 4 lanes */
1227ee85054SArec Kao static const struct ov13b10_reg mipi_data_rate_1120mbps[] = {
1237ee85054SArec Kao 	{0x0103, 0x01},
1247ee85054SArec Kao 	{0x0303, 0x04},
1257ee85054SArec Kao 	{0x0305, 0xaf},
1267ee85054SArec Kao 	{0x0321, 0x00},
1277ee85054SArec Kao 	{0x0323, 0x04},
1287ee85054SArec Kao 	{0x0324, 0x01},
1297ee85054SArec Kao 	{0x0325, 0xa4},
1307ee85054SArec Kao 	{0x0326, 0x81},
1317ee85054SArec Kao 	{0x0327, 0x04},
1327ee85054SArec Kao 	{0x3012, 0x07},
1337ee85054SArec Kao 	{0x3013, 0x32},
1347ee85054SArec Kao 	{0x3107, 0x23},
1357ee85054SArec Kao 	{0x3501, 0x0c},
1367ee85054SArec Kao 	{0x3502, 0x10},
1377ee85054SArec Kao 	{0x3504, 0x08},
1387ee85054SArec Kao 	{0x3508, 0x07},
1397ee85054SArec Kao 	{0x3509, 0xc0},
1407ee85054SArec Kao 	{0x3600, 0x16},
1417ee85054SArec Kao 	{0x3601, 0x54},
1427ee85054SArec Kao 	{0x3612, 0x4e},
1437ee85054SArec Kao 	{0x3620, 0x00},
1447ee85054SArec Kao 	{0x3621, 0x68},
1457ee85054SArec Kao 	{0x3622, 0x66},
1467ee85054SArec Kao 	{0x3623, 0x03},
1477ee85054SArec Kao 	{0x3662, 0x92},
1487ee85054SArec Kao 	{0x3666, 0xbb},
1497ee85054SArec Kao 	{0x3667, 0x44},
1507ee85054SArec Kao 	{0x366e, 0xff},
1517ee85054SArec Kao 	{0x366f, 0xf3},
1527ee85054SArec Kao 	{0x3675, 0x44},
1537ee85054SArec Kao 	{0x3676, 0x00},
1547ee85054SArec Kao 	{0x367f, 0xe9},
1557ee85054SArec Kao 	{0x3681, 0x32},
1567ee85054SArec Kao 	{0x3682, 0x1f},
1577ee85054SArec Kao 	{0x3683, 0x0b},
1587ee85054SArec Kao 	{0x3684, 0x0b},
1597ee85054SArec Kao 	{0x3704, 0x0f},
1607ee85054SArec Kao 	{0x3706, 0x40},
1617ee85054SArec Kao 	{0x3708, 0x3b},
1627ee85054SArec Kao 	{0x3709, 0x72},
1637ee85054SArec Kao 	{0x370b, 0xa2},
1647ee85054SArec Kao 	{0x3714, 0x24},
1657ee85054SArec Kao 	{0x371a, 0x3e},
1667ee85054SArec Kao 	{0x3725, 0x42},
1677ee85054SArec Kao 	{0x3739, 0x12},
1687ee85054SArec Kao 	{0x3767, 0x00},
1697ee85054SArec Kao 	{0x377a, 0x0d},
1707ee85054SArec Kao 	{0x3789, 0x18},
1717ee85054SArec Kao 	{0x3790, 0x40},
1727ee85054SArec Kao 	{0x3791, 0xa2},
1737ee85054SArec Kao 	{0x37c2, 0x04},
1747ee85054SArec Kao 	{0x37c3, 0xf1},
1757ee85054SArec Kao 	{0x37d9, 0x0c},
1767ee85054SArec Kao 	{0x37da, 0x02},
1777ee85054SArec Kao 	{0x37dc, 0x02},
1787ee85054SArec Kao 	{0x37e1, 0x04},
1797ee85054SArec Kao 	{0x37e2, 0x0a},
1807ee85054SArec Kao 	{0x3800, 0x00},
1817ee85054SArec Kao 	{0x3801, 0x00},
1827ee85054SArec Kao 	{0x3802, 0x00},
1837ee85054SArec Kao 	{0x3803, 0x08},
1847ee85054SArec Kao 	{0x3804, 0x10},
1857ee85054SArec Kao 	{0x3805, 0x8f},
1867ee85054SArec Kao 	{0x3806, 0x0c},
1877ee85054SArec Kao 	{0x3807, 0x47},
1887ee85054SArec Kao 	{0x3808, 0x10},
1897ee85054SArec Kao 	{0x3809, 0x70},
1907ee85054SArec Kao 	{0x380a, 0x0c},
1917ee85054SArec Kao 	{0x380b, 0x30},
1927ee85054SArec Kao 	{0x380c, 0x04},
1937ee85054SArec Kao 	{0x380d, 0x98},
1947ee85054SArec Kao 	{0x380e, 0x0c},
1957ee85054SArec Kao 	{0x380f, 0x7c},
1967ee85054SArec Kao 	{0x3811, 0x0f},
1977ee85054SArec Kao 	{0x3813, 0x09},
1987ee85054SArec Kao 	{0x3814, 0x01},
1997ee85054SArec Kao 	{0x3815, 0x01},
2007ee85054SArec Kao 	{0x3816, 0x01},
2017ee85054SArec Kao 	{0x3817, 0x01},
2027ee85054SArec Kao 	{0x381f, 0x08},
2037ee85054SArec Kao 	{0x3820, 0x88},
2047ee85054SArec Kao 	{0x3821, 0x00},
2057ee85054SArec Kao 	{0x3822, 0x14},
2067ee85054SArec Kao 	{0x382e, 0xe6},
2077ee85054SArec Kao 	{0x3c80, 0x00},
2087ee85054SArec Kao 	{0x3c87, 0x01},
2097ee85054SArec Kao 	{0x3c8c, 0x19},
2107ee85054SArec Kao 	{0x3c8d, 0x1c},
2117ee85054SArec Kao 	{0x3ca0, 0x00},
2127ee85054SArec Kao 	{0x3ca1, 0x00},
2137ee85054SArec Kao 	{0x3ca2, 0x00},
2147ee85054SArec Kao 	{0x3ca3, 0x00},
2157ee85054SArec Kao 	{0x3ca4, 0x50},
2167ee85054SArec Kao 	{0x3ca5, 0x11},
2177ee85054SArec Kao 	{0x3ca6, 0x01},
2187ee85054SArec Kao 	{0x3ca7, 0x00},
2197ee85054SArec Kao 	{0x3ca8, 0x00},
2207ee85054SArec Kao 	{0x4008, 0x02},
2217ee85054SArec Kao 	{0x4009, 0x0f},
2227ee85054SArec Kao 	{0x400a, 0x01},
2237ee85054SArec Kao 	{0x400b, 0x19},
2247ee85054SArec Kao 	{0x4011, 0x21},
2257ee85054SArec Kao 	{0x4017, 0x08},
2267ee85054SArec Kao 	{0x4019, 0x04},
2277ee85054SArec Kao 	{0x401a, 0x58},
2287ee85054SArec Kao 	{0x4032, 0x1e},
2297ee85054SArec Kao 	{0x4050, 0x02},
2307ee85054SArec Kao 	{0x4051, 0x09},
2317ee85054SArec Kao 	{0x405e, 0x00},
2327ee85054SArec Kao 	{0x4066, 0x02},
2337ee85054SArec Kao 	{0x4501, 0x00},
2347ee85054SArec Kao 	{0x4502, 0x10},
2357ee85054SArec Kao 	{0x4505, 0x00},
2367ee85054SArec Kao 	{0x4800, 0x64},
2377ee85054SArec Kao 	{0x481b, 0x3e},
2387ee85054SArec Kao 	{0x481f, 0x30},
2397ee85054SArec Kao 	{0x4825, 0x34},
2407ee85054SArec Kao 	{0x4837, 0x0e},
2417ee85054SArec Kao 	{0x484b, 0x01},
2427ee85054SArec Kao 	{0x4883, 0x02},
2437ee85054SArec Kao 	{0x5000, 0xff},
2447ee85054SArec Kao 	{0x5001, 0x0f},
2457ee85054SArec Kao 	{0x5045, 0x20},
2467ee85054SArec Kao 	{0x5046, 0x20},
2477ee85054SArec Kao 	{0x5047, 0xa4},
2487ee85054SArec Kao 	{0x5048, 0x20},
2497ee85054SArec Kao 	{0x5049, 0xa4},
2507ee85054SArec Kao };
2517ee85054SArec Kao 
2527ee85054SArec Kao static const struct ov13b10_reg mode_4208x3120_regs[] = {
2537ee85054SArec Kao 	{0x0305, 0xaf},
2547ee85054SArec Kao 	{0x3501, 0x0c},
2557ee85054SArec Kao 	{0x3662, 0x92},
2567ee85054SArec Kao 	{0x3714, 0x24},
2577ee85054SArec Kao 	{0x3739, 0x12},
2587ee85054SArec Kao 	{0x37c2, 0x04},
2597ee85054SArec Kao 	{0x37d9, 0x0c},
2607ee85054SArec Kao 	{0x37e2, 0x0a},
2617ee85054SArec Kao 	{0x3800, 0x00},
2627ee85054SArec Kao 	{0x3801, 0x00},
2637ee85054SArec Kao 	{0x3802, 0x00},
2647ee85054SArec Kao 	{0x3803, 0x08},
2657ee85054SArec Kao 	{0x3804, 0x10},
2667ee85054SArec Kao 	{0x3805, 0x8f},
2677ee85054SArec Kao 	{0x3806, 0x0c},
2687ee85054SArec Kao 	{0x3807, 0x47},
2697ee85054SArec Kao 	{0x3808, 0x10},
2707ee85054SArec Kao 	{0x3809, 0x70},
2717ee85054SArec Kao 	{0x380a, 0x0c},
2727ee85054SArec Kao 	{0x380b, 0x30},
2737ee85054SArec Kao 	{0x380c, 0x04},
2747ee85054SArec Kao 	{0x380d, 0x98},
2757ee85054SArec Kao 	{0x380e, 0x0c},
2767ee85054SArec Kao 	{0x380f, 0x7c},
2777ee85054SArec Kao 	{0x3810, 0x00},
2787ee85054SArec Kao 	{0x3811, 0x0f},
2797ee85054SArec Kao 	{0x3812, 0x00},
2807ee85054SArec Kao 	{0x3813, 0x09},
2817ee85054SArec Kao 	{0x3814, 0x01},
2827ee85054SArec Kao 	{0x3816, 0x01},
2837ee85054SArec Kao 	{0x3820, 0x88},
2847ee85054SArec Kao 	{0x3c8c, 0x19},
2857ee85054SArec Kao 	{0x4008, 0x02},
2867ee85054SArec Kao 	{0x4009, 0x0f},
2877ee85054SArec Kao 	{0x4050, 0x02},
2887ee85054SArec Kao 	{0x4051, 0x09},
2897ee85054SArec Kao 	{0x4501, 0x00},
2907ee85054SArec Kao 	{0x4505, 0x00},
2917ee85054SArec Kao 	{0x4837, 0x0e},
2927ee85054SArec Kao 	{0x5000, 0xff},
2937ee85054SArec Kao 	{0x5001, 0x0f},
2947ee85054SArec Kao };
2957ee85054SArec Kao 
2967ee85054SArec Kao static const struct ov13b10_reg mode_4160x3120_regs[] = {
2977ee85054SArec Kao 	{0x0305, 0xaf},
2987ee85054SArec Kao 	{0x3501, 0x0c},
2997ee85054SArec Kao 	{0x3662, 0x92},
3007ee85054SArec Kao 	{0x3714, 0x24},
3017ee85054SArec Kao 	{0x3739, 0x12},
3027ee85054SArec Kao 	{0x37c2, 0x04},
3037ee85054SArec Kao 	{0x37d9, 0x0c},
3047ee85054SArec Kao 	{0x37e2, 0x0a},
3057ee85054SArec Kao 	{0x3800, 0x00},
3067ee85054SArec Kao 	{0x3801, 0x00},
3077ee85054SArec Kao 	{0x3802, 0x00},
3087ee85054SArec Kao 	{0x3803, 0x08},
3097ee85054SArec Kao 	{0x3804, 0x10},
3107ee85054SArec Kao 	{0x3805, 0x8f},
3117ee85054SArec Kao 	{0x3806, 0x0c},
3127ee85054SArec Kao 	{0x3807, 0x47},
3137ee85054SArec Kao 	{0x3808, 0x10},
3147ee85054SArec Kao 	{0x3809, 0x40},
3157ee85054SArec Kao 	{0x380a, 0x0c},
3167ee85054SArec Kao 	{0x380b, 0x30},
3177ee85054SArec Kao 	{0x380c, 0x04},
3187ee85054SArec Kao 	{0x380d, 0x98},
3197ee85054SArec Kao 	{0x380e, 0x0c},
3207ee85054SArec Kao 	{0x380f, 0x7c},
3217ee85054SArec Kao 	{0x3810, 0x00},
3227ee85054SArec Kao 	{0x3811, 0x27},
3237ee85054SArec Kao 	{0x3812, 0x00},
3247ee85054SArec Kao 	{0x3813, 0x09},
3257ee85054SArec Kao 	{0x3814, 0x01},
3267ee85054SArec Kao 	{0x3816, 0x01},
3277ee85054SArec Kao 	{0x3820, 0x88},
3287ee85054SArec Kao 	{0x3c8c, 0x19},
3297ee85054SArec Kao 	{0x4008, 0x02},
3307ee85054SArec Kao 	{0x4009, 0x0f},
3317ee85054SArec Kao 	{0x4050, 0x02},
3327ee85054SArec Kao 	{0x4051, 0x09},
3337ee85054SArec Kao 	{0x4501, 0x00},
3347ee85054SArec Kao 	{0x4505, 0x00},
3357ee85054SArec Kao 	{0x4837, 0x0e},
3367ee85054SArec Kao 	{0x5000, 0xff},
3377ee85054SArec Kao 	{0x5001, 0x0f},
3387ee85054SArec Kao };
3397ee85054SArec Kao 
3407ee85054SArec Kao static const struct ov13b10_reg mode_4160x2340_regs[] = {
3417ee85054SArec Kao 	{0x0305, 0xaf},
3427ee85054SArec Kao 	{0x3501, 0x0c},
3437ee85054SArec Kao 	{0x3662, 0x92},
3447ee85054SArec Kao 	{0x3714, 0x24},
3457ee85054SArec Kao 	{0x3739, 0x12},
3467ee85054SArec Kao 	{0x37c2, 0x04},
3477ee85054SArec Kao 	{0x37d9, 0x0c},
3487ee85054SArec Kao 	{0x37e2, 0x0a},
3497ee85054SArec Kao 	{0x3800, 0x00},
3507ee85054SArec Kao 	{0x3801, 0x00},
3517ee85054SArec Kao 	{0x3802, 0x00},
3527ee85054SArec Kao 	{0x3803, 0x08},
3537ee85054SArec Kao 	{0x3804, 0x10},
3547ee85054SArec Kao 	{0x3805, 0x8f},
3557ee85054SArec Kao 	{0x3806, 0x0c},
3567ee85054SArec Kao 	{0x3807, 0x47},
3577ee85054SArec Kao 	{0x3808, 0x10},
3587ee85054SArec Kao 	{0x3809, 0x40},
3597ee85054SArec Kao 	{0x380a, 0x09},
3607ee85054SArec Kao 	{0x380b, 0x24},
3617ee85054SArec Kao 	{0x380c, 0x04},
3627ee85054SArec Kao 	{0x380d, 0x98},
3637ee85054SArec Kao 	{0x380e, 0x0c},
3647ee85054SArec Kao 	{0x380f, 0x7c},
3657ee85054SArec Kao 	{0x3810, 0x00},
3667ee85054SArec Kao 	{0x3811, 0x27},
3677ee85054SArec Kao 	{0x3812, 0x01},
3687ee85054SArec Kao 	{0x3813, 0x8f},
3697ee85054SArec Kao 	{0x3814, 0x01},
3707ee85054SArec Kao 	{0x3816, 0x01},
3717ee85054SArec Kao 	{0x3820, 0x88},
3727ee85054SArec Kao 	{0x3c8c, 0x19},
3737ee85054SArec Kao 	{0x4008, 0x02},
3747ee85054SArec Kao 	{0x4009, 0x0f},
3757ee85054SArec Kao 	{0x4050, 0x02},
3767ee85054SArec Kao 	{0x4051, 0x09},
3777ee85054SArec Kao 	{0x4501, 0x00},
3787ee85054SArec Kao 	{0x4505, 0x00},
3797ee85054SArec Kao 	{0x4837, 0x0e},
3807ee85054SArec Kao 	{0x5000, 0xff},
3817ee85054SArec Kao 	{0x5001, 0x0f},
3827ee85054SArec Kao };
3837ee85054SArec Kao 
3847ee85054SArec Kao static const struct ov13b10_reg mode_2104x1560_regs[] = {
3857ee85054SArec Kao 	{0x0305, 0xaf},
3867ee85054SArec Kao 	{0x3501, 0x06},
3877ee85054SArec Kao 	{0x3662, 0x88},
3887ee85054SArec Kao 	{0x3714, 0x28},
3897ee85054SArec Kao 	{0x3739, 0x10},
3907ee85054SArec Kao 	{0x37c2, 0x14},
3917ee85054SArec Kao 	{0x37d9, 0x06},
3927ee85054SArec Kao 	{0x37e2, 0x0c},
3937ee85054SArec Kao 	{0x3800, 0x00},
3947ee85054SArec Kao 	{0x3801, 0x00},
3957ee85054SArec Kao 	{0x3802, 0x00},
3967ee85054SArec Kao 	{0x3803, 0x08},
3977ee85054SArec Kao 	{0x3804, 0x10},
3987ee85054SArec Kao 	{0x3805, 0x8f},
3997ee85054SArec Kao 	{0x3806, 0x0c},
4007ee85054SArec Kao 	{0x3807, 0x47},
4017ee85054SArec Kao 	{0x3808, 0x08},
4027ee85054SArec Kao 	{0x3809, 0x38},
4037ee85054SArec Kao 	{0x380a, 0x06},
4047ee85054SArec Kao 	{0x380b, 0x18},
4057ee85054SArec Kao 	{0x380c, 0x04},
4067ee85054SArec Kao 	{0x380d, 0x98},
4077ee85054SArec Kao 	{0x380e, 0x06},
4087ee85054SArec Kao 	{0x380f, 0x3e},
4097ee85054SArec Kao 	{0x3810, 0x00},
4107ee85054SArec Kao 	{0x3811, 0x07},
4117ee85054SArec Kao 	{0x3812, 0x00},
4127ee85054SArec Kao 	{0x3813, 0x05},
4137ee85054SArec Kao 	{0x3814, 0x03},
4147ee85054SArec Kao 	{0x3816, 0x03},
4157ee85054SArec Kao 	{0x3820, 0x8b},
4167ee85054SArec Kao 	{0x3c8c, 0x18},
4177ee85054SArec Kao 	{0x4008, 0x00},
4187ee85054SArec Kao 	{0x4009, 0x05},
4197ee85054SArec Kao 	{0x4050, 0x00},
4207ee85054SArec Kao 	{0x4051, 0x05},
4217ee85054SArec Kao 	{0x4501, 0x08},
4227ee85054SArec Kao 	{0x4505, 0x00},
4237ee85054SArec Kao 	{0x4837, 0x0e},
4247ee85054SArec Kao 	{0x5000, 0xfd},
4257ee85054SArec Kao 	{0x5001, 0x0d},
4267ee85054SArec Kao };
4277ee85054SArec Kao 
4287ee85054SArec Kao static const struct ov13b10_reg mode_2080x1170_regs[] = {
4297ee85054SArec Kao 	{0x0305, 0xaf},
4307ee85054SArec Kao 	{0x3501, 0x06},
4317ee85054SArec Kao 	{0x3662, 0x88},
4327ee85054SArec Kao 	{0x3714, 0x28},
4337ee85054SArec Kao 	{0x3739, 0x10},
4347ee85054SArec Kao 	{0x37c2, 0x14},
4357ee85054SArec Kao 	{0x37d9, 0x06},
4367ee85054SArec Kao 	{0x37e2, 0x0c},
4377ee85054SArec Kao 	{0x3800, 0x00},
4387ee85054SArec Kao 	{0x3801, 0x00},
4397ee85054SArec Kao 	{0x3802, 0x00},
4407ee85054SArec Kao 	{0x3803, 0x08},
4417ee85054SArec Kao 	{0x3804, 0x10},
4427ee85054SArec Kao 	{0x3805, 0x8f},
4437ee85054SArec Kao 	{0x3806, 0x0c},
4447ee85054SArec Kao 	{0x3807, 0x47},
4457ee85054SArec Kao 	{0x3808, 0x08},
4467ee85054SArec Kao 	{0x3809, 0x20},
4477ee85054SArec Kao 	{0x380a, 0x04},
4487ee85054SArec Kao 	{0x380b, 0x92},
4497ee85054SArec Kao 	{0x380c, 0x04},
4507ee85054SArec Kao 	{0x380d, 0x98},
4517ee85054SArec Kao 	{0x380e, 0x06},
4527ee85054SArec Kao 	{0x380f, 0x3e},
4537ee85054SArec Kao 	{0x3810, 0x00},
4547ee85054SArec Kao 	{0x3811, 0x13},
4557ee85054SArec Kao 	{0x3812, 0x00},
4567ee85054SArec Kao 	{0x3813, 0xc9},
4577ee85054SArec Kao 	{0x3814, 0x03},
4587ee85054SArec Kao 	{0x3816, 0x03},
4597ee85054SArec Kao 	{0x3820, 0x8b},
4607ee85054SArec Kao 	{0x3c8c, 0x18},
4617ee85054SArec Kao 	{0x4008, 0x00},
4627ee85054SArec Kao 	{0x4009, 0x05},
4637ee85054SArec Kao 	{0x4050, 0x00},
4647ee85054SArec Kao 	{0x4051, 0x05},
4657ee85054SArec Kao 	{0x4501, 0x08},
4667ee85054SArec Kao 	{0x4505, 0x00},
4677ee85054SArec Kao 	{0x4837, 0x0e},
4687ee85054SArec Kao 	{0x5000, 0xfd},
4697ee85054SArec Kao 	{0x5001, 0x0d},
4707ee85054SArec Kao };
4717ee85054SArec Kao 
472397b2a25SHao Yao static const struct ov13b10_reg mode_1364x768_120fps_regs[] = {
473397b2a25SHao Yao 	{0x0305, 0xaf},
474397b2a25SHao Yao 	{0x3011, 0x7c},
475397b2a25SHao Yao 	{0x3501, 0x03},
476397b2a25SHao Yao 	{0x3502, 0x00},
477397b2a25SHao Yao 	{0x3662, 0x88},
478397b2a25SHao Yao 	{0x3714, 0x28},
479397b2a25SHao Yao 	{0x3739, 0x10},
480397b2a25SHao Yao 	{0x37c2, 0x14},
481397b2a25SHao Yao 	{0x37d9, 0x06},
482397b2a25SHao Yao 	{0x37e2, 0x0c},
483397b2a25SHao Yao 	{0x37e4, 0x00},
484397b2a25SHao Yao 	{0x3800, 0x02},
485397b2a25SHao Yao 	{0x3801, 0xe4},
486397b2a25SHao Yao 	{0x3802, 0x03},
487397b2a25SHao Yao 	{0x3803, 0x48},
488397b2a25SHao Yao 	{0x3804, 0x0d},
489397b2a25SHao Yao 	{0x3805, 0xab},
490397b2a25SHao Yao 	{0x3806, 0x09},
491397b2a25SHao Yao 	{0x3807, 0x60},
492397b2a25SHao Yao 	{0x3808, 0x05},
493397b2a25SHao Yao 	{0x3809, 0x54},
494397b2a25SHao Yao 	{0x380a, 0x03},
495397b2a25SHao Yao 	{0x380b, 0x00},
496397b2a25SHao Yao 	{0x380c, 0x04},
497397b2a25SHao Yao 	{0x380d, 0x8e},
498397b2a25SHao Yao 	{0x380e, 0x03},
499397b2a25SHao Yao 	{0x380f, 0x20},
500397b2a25SHao Yao 	{0x3811, 0x07},
501397b2a25SHao Yao 	{0x3813, 0x07},
502397b2a25SHao Yao 	{0x3814, 0x03},
503397b2a25SHao Yao 	{0x3816, 0x03},
504397b2a25SHao Yao 	{0x3820, 0x8b},
505397b2a25SHao Yao 	{0x3c8c, 0x18},
506397b2a25SHao Yao 	{0x4008, 0x00},
507397b2a25SHao Yao 	{0x4009, 0x05},
508397b2a25SHao Yao 	{0x4050, 0x00},
509397b2a25SHao Yao 	{0x4051, 0x05},
510397b2a25SHao Yao 	{0x4501, 0x08},
511397b2a25SHao Yao 	{0x4505, 0x04},
512397b2a25SHao Yao 	{0x5000, 0xfd},
513397b2a25SHao Yao 	{0x5001, 0x0d},
514397b2a25SHao Yao };
515397b2a25SHao Yao 
5167ee85054SArec Kao static const char * const ov13b10_test_pattern_menu[] = {
5177ee85054SArec Kao 	"Disabled",
5187ee85054SArec Kao 	"Vertical Color Bar Type 1",
5197ee85054SArec Kao 	"Vertical Color Bar Type 2",
5207ee85054SArec Kao 	"Vertical Color Bar Type 3",
5217ee85054SArec Kao 	"Vertical Color Bar Type 4"
5227ee85054SArec Kao };
5237ee85054SArec Kao 
5247ee85054SArec Kao /* Configurations for supported link frequencies */
5257ee85054SArec Kao #define OV13B10_LINK_FREQ_560MHZ	560000000ULL
5267ee85054SArec Kao #define OV13B10_LINK_FREQ_INDEX_0	0
5277ee85054SArec Kao 
5287ee85054SArec Kao #define OV13B10_EXT_CLK			19200000
5297ee85054SArec Kao #define OV13B10_DATA_LANES		4
5307ee85054SArec Kao 
5317ee85054SArec Kao /*
5327ee85054SArec Kao  * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
5337ee85054SArec Kao  * data rate => double data rate; number of lanes => 4; bits per pixel => 10
5347ee85054SArec Kao  */
link_freq_to_pixel_rate(u64 f)5357ee85054SArec Kao static u64 link_freq_to_pixel_rate(u64 f)
5367ee85054SArec Kao {
5377ee85054SArec Kao 	f *= 2 * OV13B10_DATA_LANES;
5387ee85054SArec Kao 	do_div(f, 10);
5397ee85054SArec Kao 
5407ee85054SArec Kao 	return f;
5417ee85054SArec Kao }
5427ee85054SArec Kao 
5437ee85054SArec Kao /* Menu items for LINK_FREQ V4L2 control */
5447ee85054SArec Kao static const s64 link_freq_menu_items[] = {
5457ee85054SArec Kao 	OV13B10_LINK_FREQ_560MHZ
5467ee85054SArec Kao };
5477ee85054SArec Kao 
5487ee85054SArec Kao /* Link frequency configs */
5497ee85054SArec Kao static const struct ov13b10_link_freq_config
5507ee85054SArec Kao 			link_freq_configs[] = {
5517ee85054SArec Kao 	{
5527ee85054SArec Kao 		.pixels_per_line = OV13B10_PPL_560MHZ,
5537ee85054SArec Kao 		.reg_list = {
5547ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mipi_data_rate_1120mbps),
5557ee85054SArec Kao 			.regs = mipi_data_rate_1120mbps,
5567ee85054SArec Kao 		}
5577ee85054SArec Kao 	}
5587ee85054SArec Kao };
5597ee85054SArec Kao 
5607ee85054SArec Kao /* Mode configs */
5617ee85054SArec Kao static const struct ov13b10_mode supported_modes[] = {
5627ee85054SArec Kao 	{
5637ee85054SArec Kao 		.width = 4208,
5647ee85054SArec Kao 		.height = 3120,
5657ee85054SArec Kao 		.vts_def = OV13B10_VTS_30FPS,
5667ee85054SArec Kao 		.vts_min = OV13B10_VTS_30FPS,
5677ee85054SArec Kao 		.reg_list = {
5687ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mode_4208x3120_regs),
5697ee85054SArec Kao 			.regs = mode_4208x3120_regs,
5707ee85054SArec Kao 		},
5717ee85054SArec Kao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5727ee85054SArec Kao 	},
5737ee85054SArec Kao 	{
5747ee85054SArec Kao 		.width = 4160,
5757ee85054SArec Kao 		.height = 3120,
5767ee85054SArec Kao 		.vts_def = OV13B10_VTS_30FPS,
5777ee85054SArec Kao 		.vts_min = OV13B10_VTS_30FPS,
5787ee85054SArec Kao 		.reg_list = {
5797ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mode_4160x3120_regs),
5807ee85054SArec Kao 			.regs = mode_4160x3120_regs,
5817ee85054SArec Kao 		},
5827ee85054SArec Kao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5837ee85054SArec Kao 	},
5847ee85054SArec Kao 	{
5857ee85054SArec Kao 		.width = 4160,
5867ee85054SArec Kao 		.height = 2340,
5877ee85054SArec Kao 		.vts_def = OV13B10_VTS_30FPS,
5887ee85054SArec Kao 		.vts_min = OV13B10_VTS_30FPS,
5897ee85054SArec Kao 		.reg_list = {
5907ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mode_4160x2340_regs),
5917ee85054SArec Kao 			.regs = mode_4160x2340_regs,
5927ee85054SArec Kao 		},
5937ee85054SArec Kao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5947ee85054SArec Kao 	},
5957ee85054SArec Kao 	{
5967ee85054SArec Kao 		.width = 2104,
5977ee85054SArec Kao 		.height = 1560,
5987ee85054SArec Kao 		.vts_def = OV13B10_VTS_60FPS,
5997ee85054SArec Kao 		.vts_min = OV13B10_VTS_60FPS,
6007ee85054SArec Kao 		.reg_list = {
6017ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mode_2104x1560_regs),
6027ee85054SArec Kao 			.regs = mode_2104x1560_regs,
6037ee85054SArec Kao 		},
6047ee85054SArec Kao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
6057ee85054SArec Kao 	},
6067ee85054SArec Kao 	{
6077ee85054SArec Kao 		.width = 2080,
6087ee85054SArec Kao 		.height = 1170,
6097ee85054SArec Kao 		.vts_def = OV13B10_VTS_60FPS,
6107ee85054SArec Kao 		.vts_min = OV13B10_VTS_60FPS,
6117ee85054SArec Kao 		.reg_list = {
6127ee85054SArec Kao 			.num_of_regs = ARRAY_SIZE(mode_2080x1170_regs),
6137ee85054SArec Kao 			.regs = mode_2080x1170_regs,
6147ee85054SArec Kao 		},
6157ee85054SArec Kao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
616397b2a25SHao Yao 	},
617397b2a25SHao Yao 	{
618397b2a25SHao Yao 		.width = 1364,
619397b2a25SHao Yao 		.height = 768,
620397b2a25SHao Yao 		.vts_def = OV13B10_VTS_120FPS,
621397b2a25SHao Yao 		.vts_min = OV13B10_VTS_120FPS,
622397b2a25SHao Yao 		.link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
623397b2a25SHao Yao 		.reg_list = {
624397b2a25SHao Yao 			.num_of_regs = ARRAY_SIZE(mode_1364x768_120fps_regs),
625397b2a25SHao Yao 			.regs = mode_1364x768_120fps_regs,
626397b2a25SHao Yao 		},
627397b2a25SHao Yao 	},
6287ee85054SArec Kao };
6297ee85054SArec Kao 
6307ee85054SArec Kao struct ov13b10 {
6317ee85054SArec Kao 	struct v4l2_subdev sd;
6327ee85054SArec Kao 	struct media_pad pad;
6337ee85054SArec Kao 
6347ee85054SArec Kao 	struct v4l2_ctrl_handler ctrl_handler;
6356e28afd1SBingbu Cao 
6366e28afd1SBingbu Cao 	struct clk *img_clk;
6376e28afd1SBingbu Cao 	struct regulator *avdd;
6386e28afd1SBingbu Cao 	struct gpio_desc *reset;
6396e28afd1SBingbu Cao 
6407ee85054SArec Kao 	/* V4L2 Controls */
6417ee85054SArec Kao 	struct v4l2_ctrl *link_freq;
6427ee85054SArec Kao 	struct v4l2_ctrl *pixel_rate;
6437ee85054SArec Kao 	struct v4l2_ctrl *vblank;
6447ee85054SArec Kao 	struct v4l2_ctrl *hblank;
6457ee85054SArec Kao 	struct v4l2_ctrl *exposure;
6467ee85054SArec Kao 
6477ee85054SArec Kao 	/* Current mode */
6487ee85054SArec Kao 	const struct ov13b10_mode *cur_mode;
6497ee85054SArec Kao 
6507ee85054SArec Kao 	/* Mutex for serialized access */
6517ee85054SArec Kao 	struct mutex mutex;
6527ee85054SArec Kao 
6531af2f618SArec Kao 	/* True if the device has been identified */
6541af2f618SArec Kao 	bool identified;
6557ee85054SArec Kao };
6567ee85054SArec Kao 
6577ee85054SArec Kao #define to_ov13b10(_sd)	container_of(_sd, struct ov13b10, sd)
6587ee85054SArec Kao 
6597ee85054SArec Kao /* Read registers up to 4 at a time */
ov13b10_read_reg(struct ov13b10 * ov13b,u16 reg,u32 len,u32 * val)6607ee85054SArec Kao static int ov13b10_read_reg(struct ov13b10 *ov13b,
6617ee85054SArec Kao 			    u16 reg, u32 len, u32 *val)
6627ee85054SArec Kao {
6637ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
6647ee85054SArec Kao 	struct i2c_msg msgs[2];
6657ee85054SArec Kao 	u8 *data_be_p;
6667ee85054SArec Kao 	int ret;
6677ee85054SArec Kao 	__be32 data_be = 0;
6687ee85054SArec Kao 	__be16 reg_addr_be = cpu_to_be16(reg);
6697ee85054SArec Kao 
6707ee85054SArec Kao 	if (len > 4)
6717ee85054SArec Kao 		return -EINVAL;
6727ee85054SArec Kao 
6737ee85054SArec Kao 	data_be_p = (u8 *)&data_be;
6747ee85054SArec Kao 	/* Write register address */
6757ee85054SArec Kao 	msgs[0].addr = client->addr;
6767ee85054SArec Kao 	msgs[0].flags = 0;
6777ee85054SArec Kao 	msgs[0].len = 2;
6787ee85054SArec Kao 	msgs[0].buf = (u8 *)&reg_addr_be;
6797ee85054SArec Kao 
6807ee85054SArec Kao 	/* Read data from register */
6817ee85054SArec Kao 	msgs[1].addr = client->addr;
6827ee85054SArec Kao 	msgs[1].flags = I2C_M_RD;
6837ee85054SArec Kao 	msgs[1].len = len;
6847ee85054SArec Kao 	msgs[1].buf = &data_be_p[4 - len];
6857ee85054SArec Kao 
6867ee85054SArec Kao 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
6877ee85054SArec Kao 	if (ret != ARRAY_SIZE(msgs))
6887ee85054SArec Kao 		return -EIO;
6897ee85054SArec Kao 
6907ee85054SArec Kao 	*val = be32_to_cpu(data_be);
6917ee85054SArec Kao 
6927ee85054SArec Kao 	return 0;
6937ee85054SArec Kao }
6947ee85054SArec Kao 
6957ee85054SArec Kao /* Write registers up to 4 at a time */
ov13b10_write_reg(struct ov13b10 * ov13b,u16 reg,u32 len,u32 __val)6967ee85054SArec Kao static int ov13b10_write_reg(struct ov13b10 *ov13b,
6977ee85054SArec Kao 			     u16 reg, u32 len, u32 __val)
6987ee85054SArec Kao {
6997ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
7007ee85054SArec Kao 	int buf_i, val_i;
7017ee85054SArec Kao 	u8 buf[6], *val_p;
7027ee85054SArec Kao 	__be32 val;
7037ee85054SArec Kao 
7047ee85054SArec Kao 	if (len > 4)
7057ee85054SArec Kao 		return -EINVAL;
7067ee85054SArec Kao 
7077ee85054SArec Kao 	buf[0] = reg >> 8;
7087ee85054SArec Kao 	buf[1] = reg & 0xff;
7097ee85054SArec Kao 
7107ee85054SArec Kao 	val = cpu_to_be32(__val);
7117ee85054SArec Kao 	val_p = (u8 *)&val;
7127ee85054SArec Kao 	buf_i = 2;
7137ee85054SArec Kao 	val_i = 4 - len;
7147ee85054SArec Kao 
7157ee85054SArec Kao 	while (val_i < 4)
7167ee85054SArec Kao 		buf[buf_i++] = val_p[val_i++];
7177ee85054SArec Kao 
7187ee85054SArec Kao 	if (i2c_master_send(client, buf, len + 2) != len + 2)
7197ee85054SArec Kao 		return -EIO;
7207ee85054SArec Kao 
7217ee85054SArec Kao 	return 0;
7227ee85054SArec Kao }
7237ee85054SArec Kao 
7247ee85054SArec Kao /* Write a list of registers */
ov13b10_write_regs(struct ov13b10 * ov13b,const struct ov13b10_reg * regs,u32 len)7257ee85054SArec Kao static int ov13b10_write_regs(struct ov13b10 *ov13b,
7267ee85054SArec Kao 			      const struct ov13b10_reg *regs, u32 len)
7277ee85054SArec Kao {
7287ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
7297ee85054SArec Kao 	int ret;
7307ee85054SArec Kao 	u32 i;
7317ee85054SArec Kao 
7327ee85054SArec Kao 	for (i = 0; i < len; i++) {
7337ee85054SArec Kao 		ret = ov13b10_write_reg(ov13b, regs[i].address, 1,
7347ee85054SArec Kao 					regs[i].val);
7357ee85054SArec Kao 		if (ret) {
7367ee85054SArec Kao 			dev_err_ratelimited(&client->dev,
7377ee85054SArec Kao 					    "Failed to write reg 0x%4.4x. error = %d\n",
7387ee85054SArec Kao 					    regs[i].address, ret);
7397ee85054SArec Kao 
7407ee85054SArec Kao 			return ret;
7417ee85054SArec Kao 		}
7427ee85054SArec Kao 	}
7437ee85054SArec Kao 
7447ee85054SArec Kao 	return 0;
7457ee85054SArec Kao }
7467ee85054SArec Kao 
ov13b10_write_reg_list(struct ov13b10 * ov13b,const struct ov13b10_reg_list * r_list)7477ee85054SArec Kao static int ov13b10_write_reg_list(struct ov13b10 *ov13b,
7487ee85054SArec Kao 				  const struct ov13b10_reg_list *r_list)
7497ee85054SArec Kao {
7507ee85054SArec Kao 	return ov13b10_write_regs(ov13b, r_list->regs, r_list->num_of_regs);
7517ee85054SArec Kao }
7527ee85054SArec Kao 
7537ee85054SArec Kao /* Open sub-device */
ov13b10_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)7547ee85054SArec Kao static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
7557ee85054SArec Kao {
7567ee85054SArec Kao 	const struct ov13b10_mode *default_mode = &supported_modes[0];
7577ee85054SArec Kao 	struct ov13b10 *ov13b = to_ov13b10(sd);
758bc0e8d91SSakari Ailus 	struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state,
7597ee85054SArec Kao 									  0);
7607ee85054SArec Kao 
7617ee85054SArec Kao 	mutex_lock(&ov13b->mutex);
7627ee85054SArec Kao 
7637ee85054SArec Kao 	/* Initialize try_fmt */
7647ee85054SArec Kao 	try_fmt->width = default_mode->width;
7657ee85054SArec Kao 	try_fmt->height = default_mode->height;
7667ee85054SArec Kao 	try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
7677ee85054SArec Kao 	try_fmt->field = V4L2_FIELD_NONE;
7687ee85054SArec Kao 
7697ee85054SArec Kao 	/* No crop or compose */
7707ee85054SArec Kao 	mutex_unlock(&ov13b->mutex);
7717ee85054SArec Kao 
7727ee85054SArec Kao 	return 0;
7737ee85054SArec Kao }
7747ee85054SArec Kao 
ov13b10_update_digital_gain(struct ov13b10 * ov13b,u32 d_gain)7757ee85054SArec Kao static int ov13b10_update_digital_gain(struct ov13b10 *ov13b, u32 d_gain)
7767ee85054SArec Kao {
7777ee85054SArec Kao 	int ret;
7787ee85054SArec Kao 	u32 val;
7797ee85054SArec Kao 
7807ee85054SArec Kao 	/*
7817ee85054SArec Kao 	 * 0x350C[7:6], 0x350B[7:0], 0x350A[1:0]
7827ee85054SArec Kao 	 */
7837ee85054SArec Kao 
7847ee85054SArec Kao 	val = (d_gain & OV13B10_DGTL_GAIN_L_MASK) << OV13B10_DGTL_GAIN_L_SHIFT;
7857ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_L,
7867ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT, val);
7877ee85054SArec Kao 	if (ret)
7887ee85054SArec Kao 		return ret;
7897ee85054SArec Kao 
7907ee85054SArec Kao 	val = (d_gain >> OV13B10_DGTL_GAIN_M_SHIFT) & OV13B10_DGTL_GAIN_M_MASK;
7917ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_M,
7927ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT, val);
7937ee85054SArec Kao 	if (ret)
7947ee85054SArec Kao 		return ret;
7957ee85054SArec Kao 
7967ee85054SArec Kao 	val = (d_gain >> OV13B10_DGTL_GAIN_H_SHIFT) & OV13B10_DGTL_GAIN_H_MASK;
7977ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_H,
7987ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT, val);
7997ee85054SArec Kao 
8007ee85054SArec Kao 	return ret;
8017ee85054SArec Kao }
8027ee85054SArec Kao 
ov13b10_enable_test_pattern(struct ov13b10 * ov13b,u32 pattern)8037ee85054SArec Kao static int ov13b10_enable_test_pattern(struct ov13b10 *ov13b, u32 pattern)
8047ee85054SArec Kao {
8057ee85054SArec Kao 	int ret;
8067ee85054SArec Kao 	u32 val;
8077ee85054SArec Kao 
8087ee85054SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_TEST_PATTERN,
8097ee85054SArec Kao 			       OV13B10_REG_VALUE_08BIT, &val);
8107ee85054SArec Kao 	if (ret)
8117ee85054SArec Kao 		return ret;
8127ee85054SArec Kao 
8137ee85054SArec Kao 	if (pattern) {
8147ee85054SArec Kao 		val &= OV13B10_TEST_PATTERN_MASK;
8157ee85054SArec Kao 		val |= ((pattern - 1) << OV13B10_TEST_PATTERN_BAR_SHIFT) |
8167ee85054SArec Kao 		     OV13B10_TEST_PATTERN_ENABLE;
8177ee85054SArec Kao 	} else {
8187ee85054SArec Kao 		val &= ~OV13B10_TEST_PATTERN_ENABLE;
8197ee85054SArec Kao 	}
8207ee85054SArec Kao 
8217ee85054SArec Kao 	return ov13b10_write_reg(ov13b, OV13B10_REG_TEST_PATTERN,
8227ee85054SArec Kao 				 OV13B10_REG_VALUE_08BIT, val);
8237ee85054SArec Kao }
8247ee85054SArec Kao 
ov13b10_set_ctrl_hflip(struct ov13b10 * ov13b,u32 ctrl_val)8257ee85054SArec Kao static int ov13b10_set_ctrl_hflip(struct ov13b10 *ov13b, u32 ctrl_val)
8267ee85054SArec Kao {
8277ee85054SArec Kao 	int ret;
8287ee85054SArec Kao 	u32 val;
8297ee85054SArec Kao 
8307ee85054SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1,
8317ee85054SArec Kao 			       OV13B10_REG_VALUE_08BIT, &val);
8327ee85054SArec Kao 	if (ret)
8337ee85054SArec Kao 		return ret;
8347ee85054SArec Kao 
8357ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1,
8367ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT,
8377ee85054SArec Kao 				ctrl_val ? val & ~BIT(3) : val);
8387ee85054SArec Kao 
8397ee85054SArec Kao 	if (ret)
8407ee85054SArec Kao 		return ret;
8417ee85054SArec Kao 
8427ee85054SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_H_WIN_OFFSET,
8437ee85054SArec Kao 			       OV13B10_REG_VALUE_08BIT, &val);
8447ee85054SArec Kao 	if (ret)
8457ee85054SArec Kao 		return ret;
8467ee85054SArec Kao 
8477ee85054SArec Kao 	/*
8487ee85054SArec Kao 	 * Applying cropping offset to reverse the change of Bayer order
8497ee85054SArec Kao 	 * after mirroring image
8507ee85054SArec Kao 	 */
8517ee85054SArec Kao 	return ov13b10_write_reg(ov13b, OV13B10_REG_H_WIN_OFFSET,
8527ee85054SArec Kao 				 OV13B10_REG_VALUE_08BIT,
8537ee85054SArec Kao 				 ctrl_val ? ++val : val);
8547ee85054SArec Kao }
8557ee85054SArec Kao 
ov13b10_set_ctrl_vflip(struct ov13b10 * ov13b,u32 ctrl_val)8567ee85054SArec Kao static int ov13b10_set_ctrl_vflip(struct ov13b10 *ov13b, u32 ctrl_val)
8577ee85054SArec Kao {
8587ee85054SArec Kao 	int ret;
8597ee85054SArec Kao 	u32 val;
8607ee85054SArec Kao 
8617ee85054SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1,
8627ee85054SArec Kao 			       OV13B10_REG_VALUE_08BIT, &val);
8637ee85054SArec Kao 	if (ret)
8647ee85054SArec Kao 		return ret;
8657ee85054SArec Kao 
8667ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1,
8677ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT,
8687ee85054SArec Kao 				ctrl_val ? val | BIT(4) | BIT(5)  : val);
8697ee85054SArec Kao 
8707ee85054SArec Kao 	if (ret)
8717ee85054SArec Kao 		return ret;
8727ee85054SArec Kao 
8737ee85054SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_V_WIN_OFFSET,
8747ee85054SArec Kao 			       OV13B10_REG_VALUE_08BIT, &val);
8757ee85054SArec Kao 	if (ret)
8767ee85054SArec Kao 		return ret;
8777ee85054SArec Kao 
8787ee85054SArec Kao 	/*
8797ee85054SArec Kao 	 * Applying cropping offset to reverse the change of Bayer order
8807ee85054SArec Kao 	 * after flipping image
8817ee85054SArec Kao 	 */
8827ee85054SArec Kao 	return ov13b10_write_reg(ov13b, OV13B10_REG_V_WIN_OFFSET,
8837ee85054SArec Kao 				 OV13B10_REG_VALUE_08BIT,
8847ee85054SArec Kao 				 ctrl_val ? --val : val);
8857ee85054SArec Kao }
8867ee85054SArec Kao 
ov13b10_set_ctrl(struct v4l2_ctrl * ctrl)8877ee85054SArec Kao static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl)
8887ee85054SArec Kao {
8897ee85054SArec Kao 	struct ov13b10 *ov13b = container_of(ctrl->handler,
8907ee85054SArec Kao 					     struct ov13b10, ctrl_handler);
8917ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
8927ee85054SArec Kao 	s64 max;
8937ee85054SArec Kao 	int ret;
8947ee85054SArec Kao 
8957ee85054SArec Kao 	/* Propagate change of current control to all related controls */
8967ee85054SArec Kao 	switch (ctrl->id) {
8977ee85054SArec Kao 	case V4L2_CID_VBLANK:
8987ee85054SArec Kao 		/* Update max exposure while meeting expected vblanking */
8997ee85054SArec Kao 		max = ov13b->cur_mode->height + ctrl->val - 8;
9007ee85054SArec Kao 		__v4l2_ctrl_modify_range(ov13b->exposure,
9017ee85054SArec Kao 					 ov13b->exposure->minimum,
9027ee85054SArec Kao 					 max, ov13b->exposure->step, max);
9037ee85054SArec Kao 		break;
9047ee85054SArec Kao 	}
9057ee85054SArec Kao 
9067ee85054SArec Kao 	/*
9077ee85054SArec Kao 	 * Applying V4L2 control value only happens
9087ee85054SArec Kao 	 * when power is up for streaming
9097ee85054SArec Kao 	 */
9107ee85054SArec Kao 	if (!pm_runtime_get_if_in_use(&client->dev))
9117ee85054SArec Kao 		return 0;
9127ee85054SArec Kao 
9137ee85054SArec Kao 	ret = 0;
9147ee85054SArec Kao 	switch (ctrl->id) {
9157ee85054SArec Kao 	case V4L2_CID_ANALOGUE_GAIN:
9167ee85054SArec Kao 		ret = ov13b10_write_reg(ov13b, OV13B10_REG_ANALOG_GAIN,
9177ee85054SArec Kao 					OV13B10_REG_VALUE_16BIT,
9187ee85054SArec Kao 					ctrl->val << 1);
9197ee85054SArec Kao 		break;
9207ee85054SArec Kao 	case V4L2_CID_DIGITAL_GAIN:
9217ee85054SArec Kao 		ret = ov13b10_update_digital_gain(ov13b, ctrl->val);
9227ee85054SArec Kao 		break;
9237ee85054SArec Kao 	case V4L2_CID_EXPOSURE:
9247ee85054SArec Kao 		ret = ov13b10_write_reg(ov13b, OV13B10_REG_EXPOSURE,
9257ee85054SArec Kao 					OV13B10_REG_VALUE_24BIT,
9267ee85054SArec Kao 					ctrl->val);
9277ee85054SArec Kao 		break;
9287ee85054SArec Kao 	case V4L2_CID_VBLANK:
9297ee85054SArec Kao 		ret = ov13b10_write_reg(ov13b, OV13B10_REG_VTS,
9307ee85054SArec Kao 					OV13B10_REG_VALUE_16BIT,
9317ee85054SArec Kao 					ov13b->cur_mode->height
9327ee85054SArec Kao 					+ ctrl->val);
9337ee85054SArec Kao 		break;
9347ee85054SArec Kao 	case V4L2_CID_TEST_PATTERN:
9357ee85054SArec Kao 		ret = ov13b10_enable_test_pattern(ov13b, ctrl->val);
9367ee85054SArec Kao 		break;
9377ee85054SArec Kao 	case V4L2_CID_HFLIP:
9387ee85054SArec Kao 		ov13b10_set_ctrl_hflip(ov13b, ctrl->val);
9397ee85054SArec Kao 		break;
9407ee85054SArec Kao 	case V4L2_CID_VFLIP:
9417ee85054SArec Kao 		ov13b10_set_ctrl_vflip(ov13b, ctrl->val);
9427ee85054SArec Kao 		break;
9437ee85054SArec Kao 	default:
9447ee85054SArec Kao 		dev_info(&client->dev,
9457ee85054SArec Kao 			 "ctrl(id:0x%x,val:0x%x) is not handled\n",
9467ee85054SArec Kao 			 ctrl->id, ctrl->val);
9477ee85054SArec Kao 		break;
9487ee85054SArec Kao 	}
9497ee85054SArec Kao 
9507ee85054SArec Kao 	pm_runtime_put(&client->dev);
9517ee85054SArec Kao 
9527ee85054SArec Kao 	return ret;
9537ee85054SArec Kao }
9547ee85054SArec Kao 
9557ee85054SArec Kao static const struct v4l2_ctrl_ops ov13b10_ctrl_ops = {
9567ee85054SArec Kao 	.s_ctrl = ov13b10_set_ctrl,
9577ee85054SArec Kao };
9587ee85054SArec Kao 
ov13b10_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)9597ee85054SArec Kao static int ov13b10_enum_mbus_code(struct v4l2_subdev *sd,
9607ee85054SArec Kao 				  struct v4l2_subdev_state *sd_state,
9617ee85054SArec Kao 				  struct v4l2_subdev_mbus_code_enum *code)
9627ee85054SArec Kao {
9637ee85054SArec Kao 	/* Only one bayer order(GRBG) is supported */
9647ee85054SArec Kao 	if (code->index > 0)
9657ee85054SArec Kao 		return -EINVAL;
9667ee85054SArec Kao 
9677ee85054SArec Kao 	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
9687ee85054SArec Kao 
9697ee85054SArec Kao 	return 0;
9707ee85054SArec Kao }
9717ee85054SArec Kao 
ov13b10_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)9727ee85054SArec Kao static int ov13b10_enum_frame_size(struct v4l2_subdev *sd,
9737ee85054SArec Kao 				   struct v4l2_subdev_state *sd_state,
9747ee85054SArec Kao 				   struct v4l2_subdev_frame_size_enum *fse)
9757ee85054SArec Kao {
9767ee85054SArec Kao 	if (fse->index >= ARRAY_SIZE(supported_modes))
9777ee85054SArec Kao 		return -EINVAL;
9787ee85054SArec Kao 
9797ee85054SArec Kao 	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
9807ee85054SArec Kao 		return -EINVAL;
9817ee85054SArec Kao 
9827ee85054SArec Kao 	fse->min_width = supported_modes[fse->index].width;
9837ee85054SArec Kao 	fse->max_width = fse->min_width;
9847ee85054SArec Kao 	fse->min_height = supported_modes[fse->index].height;
9857ee85054SArec Kao 	fse->max_height = fse->min_height;
9867ee85054SArec Kao 
9877ee85054SArec Kao 	return 0;
9887ee85054SArec Kao }
9897ee85054SArec Kao 
ov13b10_update_pad_format(const struct ov13b10_mode * mode,struct v4l2_subdev_format * fmt)9907ee85054SArec Kao static void ov13b10_update_pad_format(const struct ov13b10_mode *mode,
9917ee85054SArec Kao 				      struct v4l2_subdev_format *fmt)
9927ee85054SArec Kao {
9937ee85054SArec Kao 	fmt->format.width = mode->width;
9947ee85054SArec Kao 	fmt->format.height = mode->height;
9957ee85054SArec Kao 	fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
9967ee85054SArec Kao 	fmt->format.field = V4L2_FIELD_NONE;
9977ee85054SArec Kao }
9987ee85054SArec Kao 
ov13b10_do_get_pad_format(struct ov13b10 * ov13b,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)9997ee85054SArec Kao static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b,
10007ee85054SArec Kao 				     struct v4l2_subdev_state *sd_state,
10017ee85054SArec Kao 				     struct v4l2_subdev_format *fmt)
10027ee85054SArec Kao {
10037ee85054SArec Kao 	struct v4l2_mbus_framefmt *framefmt;
10047ee85054SArec Kao 
10057ee85054SArec Kao 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1006bc0e8d91SSakari Ailus 		framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
10077ee85054SArec Kao 		fmt->format = *framefmt;
10087ee85054SArec Kao 	} else {
10097ee85054SArec Kao 		ov13b10_update_pad_format(ov13b->cur_mode, fmt);
10107ee85054SArec Kao 	}
10117ee85054SArec Kao 
10127ee85054SArec Kao 	return 0;
10137ee85054SArec Kao }
10147ee85054SArec Kao 
ov13b10_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)10157ee85054SArec Kao static int ov13b10_get_pad_format(struct v4l2_subdev *sd,
10167ee85054SArec Kao 				  struct v4l2_subdev_state *sd_state,
10177ee85054SArec Kao 				  struct v4l2_subdev_format *fmt)
10187ee85054SArec Kao {
10197ee85054SArec Kao 	struct ov13b10 *ov13b = to_ov13b10(sd);
10207ee85054SArec Kao 	int ret;
10217ee85054SArec Kao 
10227ee85054SArec Kao 	mutex_lock(&ov13b->mutex);
10237ee85054SArec Kao 	ret = ov13b10_do_get_pad_format(ov13b, sd_state, fmt);
10247ee85054SArec Kao 	mutex_unlock(&ov13b->mutex);
10257ee85054SArec Kao 
10267ee85054SArec Kao 	return ret;
10277ee85054SArec Kao }
10287ee85054SArec Kao 
10297ee85054SArec Kao static int
ov13b10_set_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)10307ee85054SArec Kao ov13b10_set_pad_format(struct v4l2_subdev *sd,
10317ee85054SArec Kao 		       struct v4l2_subdev_state *sd_state,
10327ee85054SArec Kao 		       struct v4l2_subdev_format *fmt)
10337ee85054SArec Kao {
10347ee85054SArec Kao 	struct ov13b10 *ov13b = to_ov13b10(sd);
10357ee85054SArec Kao 	const struct ov13b10_mode *mode;
10367ee85054SArec Kao 	struct v4l2_mbus_framefmt *framefmt;
10377ee85054SArec Kao 	s32 vblank_def;
10387ee85054SArec Kao 	s32 vblank_min;
10397ee85054SArec Kao 	s64 h_blank;
10407ee85054SArec Kao 	s64 pixel_rate;
10417ee85054SArec Kao 	s64 link_freq;
10427ee85054SArec Kao 
10437ee85054SArec Kao 	mutex_lock(&ov13b->mutex);
10447ee85054SArec Kao 
10457ee85054SArec Kao 	/* Only one raw bayer(GRBG) order is supported */
10467ee85054SArec Kao 	if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10)
10477ee85054SArec Kao 		fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
10487ee85054SArec Kao 
10497ee85054SArec Kao 	mode = v4l2_find_nearest_size(supported_modes,
10507ee85054SArec Kao 				      ARRAY_SIZE(supported_modes),
10517ee85054SArec Kao 				      width, height,
10527ee85054SArec Kao 				      fmt->format.width, fmt->format.height);
10537ee85054SArec Kao 	ov13b10_update_pad_format(mode, fmt);
10547ee85054SArec Kao 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1055bc0e8d91SSakari Ailus 		framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
10567ee85054SArec Kao 		*framefmt = fmt->format;
10577ee85054SArec Kao 	} else {
10587ee85054SArec Kao 		ov13b->cur_mode = mode;
10597ee85054SArec Kao 		__v4l2_ctrl_s_ctrl(ov13b->link_freq, mode->link_freq_index);
10607ee85054SArec Kao 		link_freq = link_freq_menu_items[mode->link_freq_index];
10617ee85054SArec Kao 		pixel_rate = link_freq_to_pixel_rate(link_freq);
10627ee85054SArec Kao 		__v4l2_ctrl_s_ctrl_int64(ov13b->pixel_rate, pixel_rate);
10637ee85054SArec Kao 
10647ee85054SArec Kao 		/* Update limits and set FPS to default */
10657ee85054SArec Kao 		vblank_def = ov13b->cur_mode->vts_def -
10667ee85054SArec Kao 			     ov13b->cur_mode->height;
10677ee85054SArec Kao 		vblank_min = ov13b->cur_mode->vts_min -
10687ee85054SArec Kao 			     ov13b->cur_mode->height;
10697ee85054SArec Kao 		__v4l2_ctrl_modify_range(ov13b->vblank, vblank_min,
10707ee85054SArec Kao 					 OV13B10_VTS_MAX
10717ee85054SArec Kao 					 - ov13b->cur_mode->height,
10727ee85054SArec Kao 					 1,
10737ee85054SArec Kao 					 vblank_def);
10747ee85054SArec Kao 		__v4l2_ctrl_s_ctrl(ov13b->vblank, vblank_def);
10757ee85054SArec Kao 		h_blank =
10767ee85054SArec Kao 			link_freq_configs[mode->link_freq_index].pixels_per_line
10777ee85054SArec Kao 			 - ov13b->cur_mode->width;
10787ee85054SArec Kao 		__v4l2_ctrl_modify_range(ov13b->hblank, h_blank,
10797ee85054SArec Kao 					 h_blank, 1, h_blank);
10807ee85054SArec Kao 	}
10817ee85054SArec Kao 
10827ee85054SArec Kao 	mutex_unlock(&ov13b->mutex);
10837ee85054SArec Kao 
10847ee85054SArec Kao 	return 0;
10857ee85054SArec Kao }
10867ee85054SArec Kao 
10871af2f618SArec Kao /* Verify chip ID */
ov13b10_identify_module(struct ov13b10 * ov13b)10881af2f618SArec Kao static int ov13b10_identify_module(struct ov13b10 *ov13b)
10891af2f618SArec Kao {
10901af2f618SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
10911af2f618SArec Kao 	int ret;
10921af2f618SArec Kao 	u32 val;
10931af2f618SArec Kao 
10941af2f618SArec Kao 	if (ov13b->identified)
10951af2f618SArec Kao 		return 0;
10961af2f618SArec Kao 
10971af2f618SArec Kao 	ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID,
10981af2f618SArec Kao 			       OV13B10_REG_VALUE_24BIT, &val);
10991af2f618SArec Kao 	if (ret)
11001af2f618SArec Kao 		return ret;
11011af2f618SArec Kao 
11021af2f618SArec Kao 	if (val != OV13B10_CHIP_ID) {
11031af2f618SArec Kao 		dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
11041af2f618SArec Kao 			OV13B10_CHIP_ID, val);
11051af2f618SArec Kao 		return -EIO;
11061af2f618SArec Kao 	}
11071af2f618SArec Kao 
11081af2f618SArec Kao 	ov13b->identified = true;
11091af2f618SArec Kao 
11101af2f618SArec Kao 	return 0;
11111af2f618SArec Kao }
11121af2f618SArec Kao 
ov13b10_power_off(struct device * dev)11136e28afd1SBingbu Cao static int ov13b10_power_off(struct device *dev)
11146e28afd1SBingbu Cao {
11156e28afd1SBingbu Cao 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
11166e28afd1SBingbu Cao 	struct ov13b10 *ov13b10 = to_ov13b10(sd);
11176e28afd1SBingbu Cao 
11186e28afd1SBingbu Cao 	gpiod_set_value_cansleep(ov13b10->reset, 1);
11196e28afd1SBingbu Cao 
11206e28afd1SBingbu Cao 	if (ov13b10->avdd)
11216e28afd1SBingbu Cao 		regulator_disable(ov13b10->avdd);
11226e28afd1SBingbu Cao 
11236e28afd1SBingbu Cao 	clk_disable_unprepare(ov13b10->img_clk);
11246e28afd1SBingbu Cao 
11256e28afd1SBingbu Cao 	return 0;
11266e28afd1SBingbu Cao }
11276e28afd1SBingbu Cao 
ov13b10_power_on(struct device * dev)11286e28afd1SBingbu Cao static int ov13b10_power_on(struct device *dev)
11296e28afd1SBingbu Cao {
11306e28afd1SBingbu Cao 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
11316e28afd1SBingbu Cao 	struct ov13b10 *ov13b10 = to_ov13b10(sd);
11326e28afd1SBingbu Cao 	int ret;
11336e28afd1SBingbu Cao 
11346e28afd1SBingbu Cao 	ret = clk_prepare_enable(ov13b10->img_clk);
11356e28afd1SBingbu Cao 	if (ret < 0) {
11366e28afd1SBingbu Cao 		dev_err(dev, "failed to enable imaging clock: %d", ret);
11376e28afd1SBingbu Cao 		return ret;
11386e28afd1SBingbu Cao 	}
11396e28afd1SBingbu Cao 
11406e28afd1SBingbu Cao 	if (ov13b10->avdd) {
11416e28afd1SBingbu Cao 		ret = regulator_enable(ov13b10->avdd);
11426e28afd1SBingbu Cao 		if (ret < 0) {
11436e28afd1SBingbu Cao 			dev_err(dev, "failed to enable avdd: %d", ret);
11446e28afd1SBingbu Cao 			clk_disable_unprepare(ov13b10->img_clk);
11456e28afd1SBingbu Cao 			return ret;
11466e28afd1SBingbu Cao 		}
11476e28afd1SBingbu Cao 	}
11486e28afd1SBingbu Cao 
11496e28afd1SBingbu Cao 	gpiod_set_value_cansleep(ov13b10->reset, 0);
11506e28afd1SBingbu Cao 	/* 5ms to wait ready after XSHUTDN assert */
11516e28afd1SBingbu Cao 	usleep_range(5000, 5500);
11526e28afd1SBingbu Cao 
11536e28afd1SBingbu Cao 	return 0;
11546e28afd1SBingbu Cao }
11556e28afd1SBingbu Cao 
ov13b10_start_streaming(struct ov13b10 * ov13b)11567ee85054SArec Kao static int ov13b10_start_streaming(struct ov13b10 *ov13b)
11577ee85054SArec Kao {
11587ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
11597ee85054SArec Kao 	const struct ov13b10_reg_list *reg_list;
11607ee85054SArec Kao 	int ret, link_freq_index;
11617ee85054SArec Kao 
11621af2f618SArec Kao 	ret = ov13b10_identify_module(ov13b);
11631af2f618SArec Kao 	if (ret)
11641af2f618SArec Kao 		return ret;
11651af2f618SArec Kao 
11667ee85054SArec Kao 	/* Get out of from software reset */
11677ee85054SArec Kao 	ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST,
11687ee85054SArec Kao 				OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST);
11697ee85054SArec Kao 	if (ret) {
11707ee85054SArec Kao 		dev_err(&client->dev, "%s failed to set powerup registers\n",
11717ee85054SArec Kao 			__func__);
11727ee85054SArec Kao 		return ret;
11737ee85054SArec Kao 	}
11747ee85054SArec Kao 
11757ee85054SArec Kao 	link_freq_index = ov13b->cur_mode->link_freq_index;
11767ee85054SArec Kao 	reg_list = &link_freq_configs[link_freq_index].reg_list;
11777ee85054SArec Kao 	ret = ov13b10_write_reg_list(ov13b, reg_list);
11787ee85054SArec Kao 	if (ret) {
11797ee85054SArec Kao 		dev_err(&client->dev, "%s failed to set plls\n", __func__);
11807ee85054SArec Kao 		return ret;
11817ee85054SArec Kao 	}
11827ee85054SArec Kao 
11837ee85054SArec Kao 	/* Apply default values of current mode */
11847ee85054SArec Kao 	reg_list = &ov13b->cur_mode->reg_list;
11857ee85054SArec Kao 	ret = ov13b10_write_reg_list(ov13b, reg_list);
11867ee85054SArec Kao 	if (ret) {
11877ee85054SArec Kao 		dev_err(&client->dev, "%s failed to set mode\n", __func__);
11887ee85054SArec Kao 		return ret;
11897ee85054SArec Kao 	}
11907ee85054SArec Kao 
11917ee85054SArec Kao 	/* Apply customized values from user */
11927ee85054SArec Kao 	ret =  __v4l2_ctrl_handler_setup(ov13b->sd.ctrl_handler);
11937ee85054SArec Kao 	if (ret)
11947ee85054SArec Kao 		return ret;
11957ee85054SArec Kao 
11967ee85054SArec Kao 	return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT,
11977ee85054SArec Kao 				 OV13B10_REG_VALUE_08BIT,
11987ee85054SArec Kao 				 OV13B10_MODE_STREAMING);
11997ee85054SArec Kao }
12007ee85054SArec Kao 
12017ee85054SArec Kao /* Stop streaming */
ov13b10_stop_streaming(struct ov13b10 * ov13b)12027ee85054SArec Kao static int ov13b10_stop_streaming(struct ov13b10 *ov13b)
12037ee85054SArec Kao {
12047ee85054SArec Kao 	return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT,
12057ee85054SArec Kao 				 OV13B10_REG_VALUE_08BIT, OV13B10_MODE_STANDBY);
12067ee85054SArec Kao }
12077ee85054SArec Kao 
ov13b10_set_stream(struct v4l2_subdev * sd,int enable)12087ee85054SArec Kao static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable)
12097ee85054SArec Kao {
12107ee85054SArec Kao 	struct ov13b10 *ov13b = to_ov13b10(sd);
12117ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(sd);
12127ee85054SArec Kao 	int ret = 0;
12137ee85054SArec Kao 
12147ee85054SArec Kao 	mutex_lock(&ov13b->mutex);
12157ee85054SArec Kao 
12167ee85054SArec Kao 	if (enable) {
12177ee85054SArec Kao 		ret = pm_runtime_resume_and_get(&client->dev);
12187ee85054SArec Kao 		if (ret < 0)
12197ee85054SArec Kao 			goto err_unlock;
12207ee85054SArec Kao 
12217ee85054SArec Kao 		/*
12227ee85054SArec Kao 		 * Apply default & customized values
12237ee85054SArec Kao 		 * and then start streaming.
12247ee85054SArec Kao 		 */
12257ee85054SArec Kao 		ret = ov13b10_start_streaming(ov13b);
12267ee85054SArec Kao 		if (ret)
12277ee85054SArec Kao 			goto err_rpm_put;
12287ee85054SArec Kao 	} else {
12297ee85054SArec Kao 		ov13b10_stop_streaming(ov13b);
12307ee85054SArec Kao 		pm_runtime_put(&client->dev);
12317ee85054SArec Kao 	}
12327ee85054SArec Kao 
12337ee85054SArec Kao 	mutex_unlock(&ov13b->mutex);
12347ee85054SArec Kao 
12357ee85054SArec Kao 	return ret;
12367ee85054SArec Kao 
12377ee85054SArec Kao err_rpm_put:
12387ee85054SArec Kao 	pm_runtime_put(&client->dev);
12397ee85054SArec Kao err_unlock:
12407ee85054SArec Kao 	mutex_unlock(&ov13b->mutex);
12417ee85054SArec Kao 
12427ee85054SArec Kao 	return ret;
12437ee85054SArec Kao }
12447ee85054SArec Kao 
ov13b10_suspend(struct device * dev)12456e28afd1SBingbu Cao static int ov13b10_suspend(struct device *dev)
12467ee85054SArec Kao {
12476e28afd1SBingbu Cao 	ov13b10_power_off(dev);
12486e28afd1SBingbu Cao 
12497ee85054SArec Kao 	return 0;
12507ee85054SArec Kao }
12517ee85054SArec Kao 
ov13b10_resume(struct device * dev)12526e28afd1SBingbu Cao static int ov13b10_resume(struct device *dev)
12537ee85054SArec Kao {
12545c873f07SLaurent Pinchart 	return ov13b10_power_on(dev);
12557ee85054SArec Kao }
12567ee85054SArec Kao 
12577ee85054SArec Kao static const struct v4l2_subdev_video_ops ov13b10_video_ops = {
12587ee85054SArec Kao 	.s_stream = ov13b10_set_stream,
12597ee85054SArec Kao };
12607ee85054SArec Kao 
12617ee85054SArec Kao static const struct v4l2_subdev_pad_ops ov13b10_pad_ops = {
12627ee85054SArec Kao 	.enum_mbus_code = ov13b10_enum_mbus_code,
12637ee85054SArec Kao 	.get_fmt = ov13b10_get_pad_format,
12647ee85054SArec Kao 	.set_fmt = ov13b10_set_pad_format,
12657ee85054SArec Kao 	.enum_frame_size = ov13b10_enum_frame_size,
12667ee85054SArec Kao };
12677ee85054SArec Kao 
12687ee85054SArec Kao static const struct v4l2_subdev_ops ov13b10_subdev_ops = {
12697ee85054SArec Kao 	.video = &ov13b10_video_ops,
12707ee85054SArec Kao 	.pad = &ov13b10_pad_ops,
12717ee85054SArec Kao };
12727ee85054SArec Kao 
12737ee85054SArec Kao static const struct media_entity_operations ov13b10_subdev_entity_ops = {
12747ee85054SArec Kao 	.link_validate = v4l2_subdev_link_validate,
12757ee85054SArec Kao };
12767ee85054SArec Kao 
12777ee85054SArec Kao static const struct v4l2_subdev_internal_ops ov13b10_internal_ops = {
12787ee85054SArec Kao 	.open = ov13b10_open,
12797ee85054SArec Kao };
12807ee85054SArec Kao 
12817ee85054SArec Kao /* Initialize control handlers */
ov13b10_init_controls(struct ov13b10 * ov13b)12827ee85054SArec Kao static int ov13b10_init_controls(struct ov13b10 *ov13b)
12837ee85054SArec Kao {
12847ee85054SArec Kao 	struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
12857ee85054SArec Kao 	struct v4l2_fwnode_device_properties props;
12867ee85054SArec Kao 	struct v4l2_ctrl_handler *ctrl_hdlr;
12877ee85054SArec Kao 	s64 exposure_max;
12887ee85054SArec Kao 	s64 vblank_def;
12897ee85054SArec Kao 	s64 vblank_min;
12907ee85054SArec Kao 	s64 hblank;
12917ee85054SArec Kao 	s64 pixel_rate_min;
12927ee85054SArec Kao 	s64 pixel_rate_max;
12937ee85054SArec Kao 	const struct ov13b10_mode *mode;
12947ee85054SArec Kao 	u32 max;
12957ee85054SArec Kao 	int ret;
12967ee85054SArec Kao 
12977ee85054SArec Kao 	ctrl_hdlr = &ov13b->ctrl_handler;
12987ee85054SArec Kao 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
12997ee85054SArec Kao 	if (ret)
13007ee85054SArec Kao 		return ret;
13017ee85054SArec Kao 
13027ee85054SArec Kao 	mutex_init(&ov13b->mutex);
13037ee85054SArec Kao 	ctrl_hdlr->lock = &ov13b->mutex;
13047ee85054SArec Kao 	max = ARRAY_SIZE(link_freq_menu_items) - 1;
13057ee85054SArec Kao 	ov13b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
13067ee85054SArec Kao 						  &ov13b10_ctrl_ops,
13077ee85054SArec Kao 						  V4L2_CID_LINK_FREQ,
13087ee85054SArec Kao 						  max,
13097ee85054SArec Kao 						  0,
13107ee85054SArec Kao 						  link_freq_menu_items);
13117ee85054SArec Kao 	if (ov13b->link_freq)
13127ee85054SArec Kao 		ov13b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
13137ee85054SArec Kao 
13147ee85054SArec Kao 	pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
13157ee85054SArec Kao 	pixel_rate_min = 0;
13167ee85054SArec Kao 	/* By default, PIXEL_RATE is read only */
13177ee85054SArec Kao 	ov13b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13187ee85054SArec Kao 					      V4L2_CID_PIXEL_RATE,
13197ee85054SArec Kao 					      pixel_rate_min, pixel_rate_max,
13207ee85054SArec Kao 					      1, pixel_rate_max);
13217ee85054SArec Kao 
13227ee85054SArec Kao 	mode = ov13b->cur_mode;
13237ee85054SArec Kao 	vblank_def = mode->vts_def - mode->height;
13247ee85054SArec Kao 	vblank_min = mode->vts_min - mode->height;
13257ee85054SArec Kao 	ov13b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13267ee85054SArec Kao 					  V4L2_CID_VBLANK,
13277ee85054SArec Kao 					  vblank_min,
13287ee85054SArec Kao 					  OV13B10_VTS_MAX - mode->height, 1,
13297ee85054SArec Kao 					  vblank_def);
13307ee85054SArec Kao 
13317ee85054SArec Kao 	hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
13327ee85054SArec Kao 		 mode->width;
13337ee85054SArec Kao 	ov13b->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13347ee85054SArec Kao 					  V4L2_CID_HBLANK,
13357ee85054SArec Kao 					  hblank, hblank, 1, hblank);
13367ee85054SArec Kao 	if (ov13b->hblank)
13377ee85054SArec Kao 		ov13b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
13387ee85054SArec Kao 
13397ee85054SArec Kao 	exposure_max = mode->vts_def - 8;
13407ee85054SArec Kao 	ov13b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13417ee85054SArec Kao 					    V4L2_CID_EXPOSURE,
13427ee85054SArec Kao 					    OV13B10_EXPOSURE_MIN,
13437ee85054SArec Kao 					    exposure_max, OV13B10_EXPOSURE_STEP,
13447ee85054SArec Kao 					    exposure_max);
13457ee85054SArec Kao 
13467ee85054SArec Kao 	v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
13477ee85054SArec Kao 			  OV13B10_ANA_GAIN_MIN, OV13B10_ANA_GAIN_MAX,
13487ee85054SArec Kao 			  OV13B10_ANA_GAIN_STEP, OV13B10_ANA_GAIN_DEFAULT);
13497ee85054SArec Kao 
13507ee85054SArec Kao 	/* Digital gain */
13517ee85054SArec Kao 	v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
13527ee85054SArec Kao 			  OV13B10_DGTL_GAIN_MIN, OV13B10_DGTL_GAIN_MAX,
13537ee85054SArec Kao 			  OV13B10_DGTL_GAIN_STEP, OV13B10_DGTL_GAIN_DEFAULT);
13547ee85054SArec Kao 
13557ee85054SArec Kao 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov13b10_ctrl_ops,
13567ee85054SArec Kao 				     V4L2_CID_TEST_PATTERN,
13577ee85054SArec Kao 				     ARRAY_SIZE(ov13b10_test_pattern_menu) - 1,
13587ee85054SArec Kao 				     0, 0, ov13b10_test_pattern_menu);
13597ee85054SArec Kao 
13607ee85054SArec Kao 	v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13617ee85054SArec Kao 			  V4L2_CID_HFLIP, 0, 1, 1, 0);
13627ee85054SArec Kao 	v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13637ee85054SArec Kao 			  V4L2_CID_VFLIP, 0, 1, 1, 0);
13647ee85054SArec Kao 
13657ee85054SArec Kao 	if (ctrl_hdlr->error) {
13667ee85054SArec Kao 		ret = ctrl_hdlr->error;
13677ee85054SArec Kao 		dev_err(&client->dev, "%s control init failed (%d)\n",
13687ee85054SArec Kao 			__func__, ret);
13697ee85054SArec Kao 		goto error;
13707ee85054SArec Kao 	}
13717ee85054SArec Kao 
13727ee85054SArec Kao 	ret = v4l2_fwnode_device_parse(&client->dev, &props);
13737ee85054SArec Kao 	if (ret)
13747ee85054SArec Kao 		goto error;
13757ee85054SArec Kao 
13767ee85054SArec Kao 	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov13b10_ctrl_ops,
13777ee85054SArec Kao 					      &props);
13787ee85054SArec Kao 	if (ret)
13797ee85054SArec Kao 		goto error;
13807ee85054SArec Kao 
13817ee85054SArec Kao 	ov13b->sd.ctrl_handler = ctrl_hdlr;
13827ee85054SArec Kao 
13837ee85054SArec Kao 	return 0;
13847ee85054SArec Kao 
13857ee85054SArec Kao error:
13867ee85054SArec Kao 	v4l2_ctrl_handler_free(ctrl_hdlr);
13877ee85054SArec Kao 	mutex_destroy(&ov13b->mutex);
13887ee85054SArec Kao 
13897ee85054SArec Kao 	return ret;
13907ee85054SArec Kao }
13917ee85054SArec Kao 
ov13b10_free_controls(struct ov13b10 * ov13b)13927ee85054SArec Kao static void ov13b10_free_controls(struct ov13b10 *ov13b)
13937ee85054SArec Kao {
13947ee85054SArec Kao 	v4l2_ctrl_handler_free(ov13b->sd.ctrl_handler);
13957ee85054SArec Kao 	mutex_destroy(&ov13b->mutex);
13967ee85054SArec Kao }
13977ee85054SArec Kao 
ov13b10_get_pm_resources(struct device * dev)13986e28afd1SBingbu Cao static int ov13b10_get_pm_resources(struct device *dev)
13996e28afd1SBingbu Cao {
14006e28afd1SBingbu Cao 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
14016e28afd1SBingbu Cao 	struct ov13b10 *ov13b = to_ov13b10(sd);
14026e28afd1SBingbu Cao 	int ret;
14036e28afd1SBingbu Cao 
14046e28afd1SBingbu Cao 	ov13b->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
14056e28afd1SBingbu Cao 	if (IS_ERR(ov13b->reset))
14066e28afd1SBingbu Cao 		return dev_err_probe(dev, PTR_ERR(ov13b->reset),
14076e28afd1SBingbu Cao 				     "failed to get reset gpio\n");
14086e28afd1SBingbu Cao 
14096e28afd1SBingbu Cao 	ov13b->img_clk = devm_clk_get_optional(dev, NULL);
14106e28afd1SBingbu Cao 	if (IS_ERR(ov13b->img_clk))
14116e28afd1SBingbu Cao 		return dev_err_probe(dev, PTR_ERR(ov13b->img_clk),
14126e28afd1SBingbu Cao 				     "failed to get imaging clock\n");
14136e28afd1SBingbu Cao 
14146e28afd1SBingbu Cao 	ov13b->avdd = devm_regulator_get_optional(dev, "avdd");
14156e28afd1SBingbu Cao 	if (IS_ERR(ov13b->avdd)) {
14166e28afd1SBingbu Cao 		ret = PTR_ERR(ov13b->avdd);
14176e28afd1SBingbu Cao 		ov13b->avdd = NULL;
14186e28afd1SBingbu Cao 		if (ret != -ENODEV)
14196e28afd1SBingbu Cao 			return dev_err_probe(dev, ret,
14206e28afd1SBingbu Cao 					     "failed to get avdd regulator\n");
14216e28afd1SBingbu Cao 	}
14226e28afd1SBingbu Cao 
14236e28afd1SBingbu Cao 	return 0;
14246e28afd1SBingbu Cao }
14256e28afd1SBingbu Cao 
ov13b10_check_hwcfg(struct device * dev)14267ee85054SArec Kao static int ov13b10_check_hwcfg(struct device *dev)
14277ee85054SArec Kao {
14287ee85054SArec Kao 	struct v4l2_fwnode_endpoint bus_cfg = {
14297ee85054SArec Kao 		.bus_type = V4L2_MBUS_CSI2_DPHY
14307ee85054SArec Kao 	};
14317ee85054SArec Kao 	struct fwnode_handle *ep;
14327ee85054SArec Kao 	struct fwnode_handle *fwnode = dev_fwnode(dev);
14337ee85054SArec Kao 	unsigned int i, j;
14347ee85054SArec Kao 	int ret;
14357ee85054SArec Kao 	u32 ext_clk;
14367ee85054SArec Kao 
14377ee85054SArec Kao 	if (!fwnode)
14387ee85054SArec Kao 		return -ENXIO;
14397ee85054SArec Kao 
1440b7602d62SBingbu Cao 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1441b7602d62SBingbu Cao 	if (!ep)
1442b7602d62SBingbu Cao 		return -EPROBE_DEFER;
1443b7602d62SBingbu Cao 
14447ee85054SArec Kao 	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
14457ee85054SArec Kao 				       &ext_clk);
14467ee85054SArec Kao 	if (ret) {
14477ee85054SArec Kao 		dev_err(dev, "can't get clock frequency");
14487ee85054SArec Kao 		return ret;
14497ee85054SArec Kao 	}
14507ee85054SArec Kao 
14517ee85054SArec Kao 	if (ext_clk != OV13B10_EXT_CLK) {
14527ee85054SArec Kao 		dev_err(dev, "external clock %d is not supported",
14537ee85054SArec Kao 			ext_clk);
14547ee85054SArec Kao 		return -EINVAL;
14557ee85054SArec Kao 	}
14567ee85054SArec Kao 
14577ee85054SArec Kao 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
14587ee85054SArec Kao 	fwnode_handle_put(ep);
14597ee85054SArec Kao 	if (ret)
14607ee85054SArec Kao 		return ret;
14617ee85054SArec Kao 
14627ee85054SArec Kao 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV13B10_DATA_LANES) {
14637ee85054SArec Kao 		dev_err(dev, "number of CSI2 data lanes %d is not supported",
14647ee85054SArec Kao 			bus_cfg.bus.mipi_csi2.num_data_lanes);
14657ee85054SArec Kao 		ret = -EINVAL;
14667ee85054SArec Kao 		goto out_err;
14677ee85054SArec Kao 	}
14687ee85054SArec Kao 
14697ee85054SArec Kao 	if (!bus_cfg.nr_of_link_frequencies) {
14707ee85054SArec Kao 		dev_err(dev, "no link frequencies defined");
14717ee85054SArec Kao 		ret = -EINVAL;
14727ee85054SArec Kao 		goto out_err;
14737ee85054SArec Kao 	}
14747ee85054SArec Kao 
14757ee85054SArec Kao 	for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
14767ee85054SArec Kao 		for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
14777ee85054SArec Kao 			if (link_freq_menu_items[i] ==
14787ee85054SArec Kao 				bus_cfg.link_frequencies[j])
14797ee85054SArec Kao 				break;
14807ee85054SArec Kao 		}
14817ee85054SArec Kao 
14827ee85054SArec Kao 		if (j == bus_cfg.nr_of_link_frequencies) {
14837ee85054SArec Kao 			dev_err(dev, "no link frequency %lld supported",
14847ee85054SArec Kao 				link_freq_menu_items[i]);
14857ee85054SArec Kao 			ret = -EINVAL;
14867ee85054SArec Kao 			goto out_err;
14877ee85054SArec Kao 		}
14887ee85054SArec Kao 	}
14897ee85054SArec Kao 
14907ee85054SArec Kao out_err:
14917ee85054SArec Kao 	v4l2_fwnode_endpoint_free(&bus_cfg);
14927ee85054SArec Kao 
14937ee85054SArec Kao 	return ret;
14947ee85054SArec Kao }
14957ee85054SArec Kao 
ov13b10_probe(struct i2c_client * client)14967ee85054SArec Kao static int ov13b10_probe(struct i2c_client *client)
14977ee85054SArec Kao {
14987ee85054SArec Kao 	struct ov13b10 *ov13b;
14991af2f618SArec Kao 	bool full_power;
15007ee85054SArec Kao 	int ret;
15017ee85054SArec Kao 
15027ee85054SArec Kao 	/* Check HW config */
15037ee85054SArec Kao 	ret = ov13b10_check_hwcfg(&client->dev);
15047ee85054SArec Kao 	if (ret) {
15057ee85054SArec Kao 		dev_err(&client->dev, "failed to check hwcfg: %d", ret);
15067ee85054SArec Kao 		return ret;
15077ee85054SArec Kao 	}
15087ee85054SArec Kao 
15097ee85054SArec Kao 	ov13b = devm_kzalloc(&client->dev, sizeof(*ov13b), GFP_KERNEL);
15107ee85054SArec Kao 	if (!ov13b)
15117ee85054SArec Kao 		return -ENOMEM;
15127ee85054SArec Kao 
15137ee85054SArec Kao 	/* Initialize subdev */
15147ee85054SArec Kao 	v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
15157ee85054SArec Kao 
15166e28afd1SBingbu Cao 	ret = ov13b10_get_pm_resources(&client->dev);
15176e28afd1SBingbu Cao 	if (ret)
15186e28afd1SBingbu Cao 		return ret;
15196e28afd1SBingbu Cao 
15201af2f618SArec Kao 	full_power = acpi_dev_state_d0(&client->dev);
15211af2f618SArec Kao 	if (full_power) {
1522d66b45e1SDan Carpenter 		ret = ov13b10_power_on(&client->dev);
15236e28afd1SBingbu Cao 		if (ret) {
15246e28afd1SBingbu Cao 			dev_err(&client->dev, "failed to power on\n");
15256e28afd1SBingbu Cao 			return ret;
15266e28afd1SBingbu Cao 		}
15276e28afd1SBingbu Cao 
15287ee85054SArec Kao 		/* Check module identity */
15297ee85054SArec Kao 		ret = ov13b10_identify_module(ov13b);
15307ee85054SArec Kao 		if (ret) {
15317ee85054SArec Kao 			dev_err(&client->dev, "failed to find sensor: %d\n", ret);
15326e28afd1SBingbu Cao 			goto error_power_off;
15337ee85054SArec Kao 		}
15341af2f618SArec Kao 	}
15357ee85054SArec Kao 
15367ee85054SArec Kao 	/* Set default mode to max resolution */
15377ee85054SArec Kao 	ov13b->cur_mode = &supported_modes[0];
15387ee85054SArec Kao 
15397ee85054SArec Kao 	ret = ov13b10_init_controls(ov13b);
15407ee85054SArec Kao 	if (ret)
15416e28afd1SBingbu Cao 		goto error_power_off;
15427ee85054SArec Kao 
15437ee85054SArec Kao 	/* Initialize subdev */
15447ee85054SArec Kao 	ov13b->sd.internal_ops = &ov13b10_internal_ops;
15457ee85054SArec Kao 	ov13b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
15467ee85054SArec Kao 	ov13b->sd.entity.ops = &ov13b10_subdev_entity_ops;
15477ee85054SArec Kao 	ov13b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
15487ee85054SArec Kao 
15497ee85054SArec Kao 	/* Initialize source pad */
15507ee85054SArec Kao 	ov13b->pad.flags = MEDIA_PAD_FL_SOURCE;
15517ee85054SArec Kao 	ret = media_entity_pads_init(&ov13b->sd.entity, 1, &ov13b->pad);
15527ee85054SArec Kao 	if (ret) {
15537ee85054SArec Kao 		dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
15547ee85054SArec Kao 		goto error_handler_free;
15557ee85054SArec Kao 	}
15567ee85054SArec Kao 
15577ee85054SArec Kao 
15587ee85054SArec Kao 	/*
15597ee85054SArec Kao 	 * Device is already turned on by i2c-core with ACPI domain PM.
15607ee85054SArec Kao 	 * Enable runtime PM and turn off the device.
15617ee85054SArec Kao 	 */
15621af2f618SArec Kao 	/* Set the device's state to active if it's in D0 state. */
15631af2f618SArec Kao 	if (full_power)
15647ee85054SArec Kao 		pm_runtime_set_active(&client->dev);
15657ee85054SArec Kao 	pm_runtime_enable(&client->dev);
15667ee85054SArec Kao 	pm_runtime_idle(&client->dev);
15677ee85054SArec Kao 
1568*7b0454cfSBingbu Cao 	ret = v4l2_async_register_subdev_sensor(&ov13b->sd);
1569*7b0454cfSBingbu Cao 	if (ret < 0)
1570*7b0454cfSBingbu Cao 		goto error_media_entity_runtime_pm;
1571*7b0454cfSBingbu Cao 
15727ee85054SArec Kao 	return 0;
15737ee85054SArec Kao 
1574*7b0454cfSBingbu Cao error_media_entity_runtime_pm:
1575*7b0454cfSBingbu Cao 	pm_runtime_disable(&client->dev);
1576*7b0454cfSBingbu Cao 	if (full_power)
1577*7b0454cfSBingbu Cao 		pm_runtime_set_suspended(&client->dev);
15787ee85054SArec Kao 	media_entity_cleanup(&ov13b->sd.entity);
15797ee85054SArec Kao 
15807ee85054SArec Kao error_handler_free:
15817ee85054SArec Kao 	ov13b10_free_controls(ov13b);
15827ee85054SArec Kao 	dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
15837ee85054SArec Kao 
15846e28afd1SBingbu Cao error_power_off:
15856e28afd1SBingbu Cao 	ov13b10_power_off(&client->dev);
15866e28afd1SBingbu Cao 
15877ee85054SArec Kao 	return ret;
15887ee85054SArec Kao }
15897ee85054SArec Kao 
ov13b10_remove(struct i2c_client * client)1590ed5c2f5fSUwe Kleine-König static void ov13b10_remove(struct i2c_client *client)
15917ee85054SArec Kao {
15927ee85054SArec Kao 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
15937ee85054SArec Kao 	struct ov13b10 *ov13b = to_ov13b10(sd);
15947ee85054SArec Kao 
15957ee85054SArec Kao 	v4l2_async_unregister_subdev(sd);
15967ee85054SArec Kao 	media_entity_cleanup(&sd->entity);
15977ee85054SArec Kao 	ov13b10_free_controls(ov13b);
15987ee85054SArec Kao 
15997ee85054SArec Kao 	pm_runtime_disable(&client->dev);
1600*7b0454cfSBingbu Cao 	pm_runtime_set_suspended(&client->dev);
16017ee85054SArec Kao }
16027ee85054SArec Kao 
16036e28afd1SBingbu Cao static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend,
16046e28afd1SBingbu Cao 				 ov13b10_resume, NULL);
16057ee85054SArec Kao 
16067ee85054SArec Kao #ifdef CONFIG_ACPI
16077ee85054SArec Kao static const struct acpi_device_id ov13b10_acpi_ids[] = {
16087ee85054SArec Kao 	{"OVTIDB10"},
16099f71a7baSBingbu Cao 	{"OVTI13B1"},
16107ee85054SArec Kao 	{ /* sentinel */ }
16117ee85054SArec Kao };
16127ee85054SArec Kao 
16137ee85054SArec Kao MODULE_DEVICE_TABLE(acpi, ov13b10_acpi_ids);
16147ee85054SArec Kao #endif
16157ee85054SArec Kao 
16167ee85054SArec Kao static struct i2c_driver ov13b10_i2c_driver = {
16177ee85054SArec Kao 	.driver = {
16187ee85054SArec Kao 		.name = "ov13b10",
16196e28afd1SBingbu Cao 		.pm = pm_ptr(&ov13b10_pm_ops),
16207ee85054SArec Kao 		.acpi_match_table = ACPI_PTR(ov13b10_acpi_ids),
16217ee85054SArec Kao 	},
1622aaeb31c0SUwe Kleine-König 	.probe = ov13b10_probe,
16237ee85054SArec Kao 	.remove = ov13b10_remove,
16241af2f618SArec Kao 	.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
16257ee85054SArec Kao };
16267ee85054SArec Kao 
16277ee85054SArec Kao module_i2c_driver(ov13b10_i2c_driver);
16287ee85054SArec Kao 
16297ee85054SArec Kao MODULE_AUTHOR("Kao, Arec <arec.kao@intel.com>");
16307ee85054SArec Kao MODULE_DESCRIPTION("Omnivision ov13b10 sensor driver");
16317ee85054SArec Kao MODULE_LICENSE("GPL v2");
1632