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
347ee85054SArec Kao #define OV13B10_VTS_MAX 0x7fff
357ee85054SArec Kao
367ee85054SArec Kao /* HBLANK control - read only */
377ee85054SArec Kao #define OV13B10_PPL_560MHZ 4704
387ee85054SArec Kao
397ee85054SArec Kao /* Exposure control */
407ee85054SArec Kao #define OV13B10_REG_EXPOSURE 0x3500
417ee85054SArec Kao #define OV13B10_EXPOSURE_MIN 4
427ee85054SArec Kao #define OV13B10_EXPOSURE_STEP 1
437ee85054SArec Kao #define OV13B10_EXPOSURE_DEFAULT 0x40
447ee85054SArec Kao
457ee85054SArec Kao /* Analog gain control */
467ee85054SArec Kao #define OV13B10_REG_ANALOG_GAIN 0x3508
477ee85054SArec Kao #define OV13B10_ANA_GAIN_MIN 0x80
487ee85054SArec Kao #define OV13B10_ANA_GAIN_MAX 0x07c0
497ee85054SArec Kao #define OV13B10_ANA_GAIN_STEP 1
507ee85054SArec Kao #define OV13B10_ANA_GAIN_DEFAULT 0x80
517ee85054SArec Kao
527ee85054SArec Kao /* Digital gain control */
537ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_H 0x350a
547ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_M 0x350b
557ee85054SArec Kao #define OV13B10_REG_DGTL_GAIN_L 0x350c
567ee85054SArec Kao
577ee85054SArec Kao #define OV13B10_DGTL_GAIN_MIN 1024 /* Min = 1 X */
587ee85054SArec Kao #define OV13B10_DGTL_GAIN_MAX (4096 - 1) /* Max = 4 X */
597ee85054SArec Kao #define OV13B10_DGTL_GAIN_DEFAULT 2560 /* Default gain = 2.5 X */
607ee85054SArec Kao #define OV13B10_DGTL_GAIN_STEP 1 /* Each step = 1/1024 */
617ee85054SArec Kao
627ee85054SArec Kao #define OV13B10_DGTL_GAIN_L_SHIFT 6
637ee85054SArec Kao #define OV13B10_DGTL_GAIN_L_MASK 0x3
647ee85054SArec Kao #define OV13B10_DGTL_GAIN_M_SHIFT 2
657ee85054SArec Kao #define OV13B10_DGTL_GAIN_M_MASK 0xff
667ee85054SArec Kao #define OV13B10_DGTL_GAIN_H_SHIFT 10
677ee85054SArec Kao #define OV13B10_DGTL_GAIN_H_MASK 0x3
687ee85054SArec Kao
697ee85054SArec Kao /* Test Pattern Control */
707ee85054SArec Kao #define OV13B10_REG_TEST_PATTERN 0x5080
717ee85054SArec Kao #define OV13B10_TEST_PATTERN_ENABLE BIT(7)
727ee85054SArec Kao #define OV13B10_TEST_PATTERN_MASK 0xf3
737ee85054SArec Kao #define OV13B10_TEST_PATTERN_BAR_SHIFT 2
747ee85054SArec Kao
757ee85054SArec Kao /* Flip Control */
767ee85054SArec Kao #define OV13B10_REG_FORMAT1 0x3820
777ee85054SArec Kao #define OV13B10_REG_FORMAT2 0x3821
787ee85054SArec Kao
797ee85054SArec Kao /* Horizontal Window Offset */
807ee85054SArec Kao #define OV13B10_REG_H_WIN_OFFSET 0x3811
817ee85054SArec Kao
827ee85054SArec Kao /* Vertical Window Offset */
837ee85054SArec Kao #define OV13B10_REG_V_WIN_OFFSET 0x3813
847ee85054SArec Kao
857ee85054SArec Kao struct ov13b10_reg {
867ee85054SArec Kao u16 address;
877ee85054SArec Kao u8 val;
887ee85054SArec Kao };
897ee85054SArec Kao
907ee85054SArec Kao struct ov13b10_reg_list {
917ee85054SArec Kao u32 num_of_regs;
927ee85054SArec Kao const struct ov13b10_reg *regs;
937ee85054SArec Kao };
947ee85054SArec Kao
957ee85054SArec Kao /* Link frequency config */
967ee85054SArec Kao struct ov13b10_link_freq_config {
977ee85054SArec Kao u32 pixels_per_line;
987ee85054SArec Kao
997ee85054SArec Kao /* registers for this link frequency */
1007ee85054SArec Kao struct ov13b10_reg_list reg_list;
1017ee85054SArec Kao };
1027ee85054SArec Kao
1037ee85054SArec Kao /* Mode : resolution and related config&values */
1047ee85054SArec Kao struct ov13b10_mode {
1057ee85054SArec Kao /* Frame width */
1067ee85054SArec Kao u32 width;
1077ee85054SArec Kao /* Frame height */
1087ee85054SArec Kao u32 height;
1097ee85054SArec Kao
1107ee85054SArec Kao /* V-timing */
1117ee85054SArec Kao u32 vts_def;
1127ee85054SArec Kao u32 vts_min;
1137ee85054SArec Kao
1147ee85054SArec Kao /* Index of Link frequency config to be used */
1157ee85054SArec Kao u32 link_freq_index;
1167ee85054SArec Kao /* Default register values */
1177ee85054SArec Kao struct ov13b10_reg_list reg_list;
1187ee85054SArec Kao };
1197ee85054SArec Kao
1207ee85054SArec Kao /* 4208x3120 needs 1120Mbps/lane, 4 lanes */
1217ee85054SArec Kao static const struct ov13b10_reg mipi_data_rate_1120mbps[] = {
1227ee85054SArec Kao {0x0103, 0x01},
1237ee85054SArec Kao {0x0303, 0x04},
1247ee85054SArec Kao {0x0305, 0xaf},
1257ee85054SArec Kao {0x0321, 0x00},
1267ee85054SArec Kao {0x0323, 0x04},
1277ee85054SArec Kao {0x0324, 0x01},
1287ee85054SArec Kao {0x0325, 0xa4},
1297ee85054SArec Kao {0x0326, 0x81},
1307ee85054SArec Kao {0x0327, 0x04},
1317ee85054SArec Kao {0x3012, 0x07},
1327ee85054SArec Kao {0x3013, 0x32},
1337ee85054SArec Kao {0x3107, 0x23},
1347ee85054SArec Kao {0x3501, 0x0c},
1357ee85054SArec Kao {0x3502, 0x10},
1367ee85054SArec Kao {0x3504, 0x08},
1377ee85054SArec Kao {0x3508, 0x07},
1387ee85054SArec Kao {0x3509, 0xc0},
1397ee85054SArec Kao {0x3600, 0x16},
1407ee85054SArec Kao {0x3601, 0x54},
1417ee85054SArec Kao {0x3612, 0x4e},
1427ee85054SArec Kao {0x3620, 0x00},
1437ee85054SArec Kao {0x3621, 0x68},
1447ee85054SArec Kao {0x3622, 0x66},
1457ee85054SArec Kao {0x3623, 0x03},
1467ee85054SArec Kao {0x3662, 0x92},
1477ee85054SArec Kao {0x3666, 0xbb},
1487ee85054SArec Kao {0x3667, 0x44},
1497ee85054SArec Kao {0x366e, 0xff},
1507ee85054SArec Kao {0x366f, 0xf3},
1517ee85054SArec Kao {0x3675, 0x44},
1527ee85054SArec Kao {0x3676, 0x00},
1537ee85054SArec Kao {0x367f, 0xe9},
1547ee85054SArec Kao {0x3681, 0x32},
1557ee85054SArec Kao {0x3682, 0x1f},
1567ee85054SArec Kao {0x3683, 0x0b},
1577ee85054SArec Kao {0x3684, 0x0b},
1587ee85054SArec Kao {0x3704, 0x0f},
1597ee85054SArec Kao {0x3706, 0x40},
1607ee85054SArec Kao {0x3708, 0x3b},
1617ee85054SArec Kao {0x3709, 0x72},
1627ee85054SArec Kao {0x370b, 0xa2},
1637ee85054SArec Kao {0x3714, 0x24},
1647ee85054SArec Kao {0x371a, 0x3e},
1657ee85054SArec Kao {0x3725, 0x42},
1667ee85054SArec Kao {0x3739, 0x12},
1677ee85054SArec Kao {0x3767, 0x00},
1687ee85054SArec Kao {0x377a, 0x0d},
1697ee85054SArec Kao {0x3789, 0x18},
1707ee85054SArec Kao {0x3790, 0x40},
1717ee85054SArec Kao {0x3791, 0xa2},
1727ee85054SArec Kao {0x37c2, 0x04},
1737ee85054SArec Kao {0x37c3, 0xf1},
1747ee85054SArec Kao {0x37d9, 0x0c},
1757ee85054SArec Kao {0x37da, 0x02},
1767ee85054SArec Kao {0x37dc, 0x02},
1777ee85054SArec Kao {0x37e1, 0x04},
1787ee85054SArec Kao {0x37e2, 0x0a},
1797ee85054SArec Kao {0x3800, 0x00},
1807ee85054SArec Kao {0x3801, 0x00},
1817ee85054SArec Kao {0x3802, 0x00},
1827ee85054SArec Kao {0x3803, 0x08},
1837ee85054SArec Kao {0x3804, 0x10},
1847ee85054SArec Kao {0x3805, 0x8f},
1857ee85054SArec Kao {0x3806, 0x0c},
1867ee85054SArec Kao {0x3807, 0x47},
1877ee85054SArec Kao {0x3808, 0x10},
1887ee85054SArec Kao {0x3809, 0x70},
1897ee85054SArec Kao {0x380a, 0x0c},
1907ee85054SArec Kao {0x380b, 0x30},
1917ee85054SArec Kao {0x380c, 0x04},
1927ee85054SArec Kao {0x380d, 0x98},
1937ee85054SArec Kao {0x380e, 0x0c},
1947ee85054SArec Kao {0x380f, 0x7c},
1957ee85054SArec Kao {0x3811, 0x0f},
1967ee85054SArec Kao {0x3813, 0x09},
1977ee85054SArec Kao {0x3814, 0x01},
1987ee85054SArec Kao {0x3815, 0x01},
1997ee85054SArec Kao {0x3816, 0x01},
2007ee85054SArec Kao {0x3817, 0x01},
2017ee85054SArec Kao {0x381f, 0x08},
2027ee85054SArec Kao {0x3820, 0x88},
2037ee85054SArec Kao {0x3821, 0x00},
2047ee85054SArec Kao {0x3822, 0x14},
2057ee85054SArec Kao {0x382e, 0xe6},
2067ee85054SArec Kao {0x3c80, 0x00},
2077ee85054SArec Kao {0x3c87, 0x01},
2087ee85054SArec Kao {0x3c8c, 0x19},
2097ee85054SArec Kao {0x3c8d, 0x1c},
2107ee85054SArec Kao {0x3ca0, 0x00},
2117ee85054SArec Kao {0x3ca1, 0x00},
2127ee85054SArec Kao {0x3ca2, 0x00},
2137ee85054SArec Kao {0x3ca3, 0x00},
2147ee85054SArec Kao {0x3ca4, 0x50},
2157ee85054SArec Kao {0x3ca5, 0x11},
2167ee85054SArec Kao {0x3ca6, 0x01},
2177ee85054SArec Kao {0x3ca7, 0x00},
2187ee85054SArec Kao {0x3ca8, 0x00},
2197ee85054SArec Kao {0x4008, 0x02},
2207ee85054SArec Kao {0x4009, 0x0f},
2217ee85054SArec Kao {0x400a, 0x01},
2227ee85054SArec Kao {0x400b, 0x19},
2237ee85054SArec Kao {0x4011, 0x21},
2247ee85054SArec Kao {0x4017, 0x08},
2257ee85054SArec Kao {0x4019, 0x04},
2267ee85054SArec Kao {0x401a, 0x58},
2277ee85054SArec Kao {0x4032, 0x1e},
2287ee85054SArec Kao {0x4050, 0x02},
2297ee85054SArec Kao {0x4051, 0x09},
2307ee85054SArec Kao {0x405e, 0x00},
2317ee85054SArec Kao {0x4066, 0x02},
2327ee85054SArec Kao {0x4501, 0x00},
2337ee85054SArec Kao {0x4502, 0x10},
2347ee85054SArec Kao {0x4505, 0x00},
2357ee85054SArec Kao {0x4800, 0x64},
2367ee85054SArec Kao {0x481b, 0x3e},
2377ee85054SArec Kao {0x481f, 0x30},
2387ee85054SArec Kao {0x4825, 0x34},
2397ee85054SArec Kao {0x4837, 0x0e},
2407ee85054SArec Kao {0x484b, 0x01},
2417ee85054SArec Kao {0x4883, 0x02},
2427ee85054SArec Kao {0x5000, 0xff},
2437ee85054SArec Kao {0x5001, 0x0f},
2447ee85054SArec Kao {0x5045, 0x20},
2457ee85054SArec Kao {0x5046, 0x20},
2467ee85054SArec Kao {0x5047, 0xa4},
2477ee85054SArec Kao {0x5048, 0x20},
2487ee85054SArec Kao {0x5049, 0xa4},
2497ee85054SArec Kao };
2507ee85054SArec Kao
2517ee85054SArec Kao static const struct ov13b10_reg mode_4208x3120_regs[] = {
2527ee85054SArec Kao {0x0305, 0xaf},
2537ee85054SArec Kao {0x3501, 0x0c},
2547ee85054SArec Kao {0x3662, 0x92},
2557ee85054SArec Kao {0x3714, 0x24},
2567ee85054SArec Kao {0x3739, 0x12},
2577ee85054SArec Kao {0x37c2, 0x04},
2587ee85054SArec Kao {0x37d9, 0x0c},
2597ee85054SArec Kao {0x37e2, 0x0a},
2607ee85054SArec Kao {0x3800, 0x00},
2617ee85054SArec Kao {0x3801, 0x00},
2627ee85054SArec Kao {0x3802, 0x00},
2637ee85054SArec Kao {0x3803, 0x08},
2647ee85054SArec Kao {0x3804, 0x10},
2657ee85054SArec Kao {0x3805, 0x8f},
2667ee85054SArec Kao {0x3806, 0x0c},
2677ee85054SArec Kao {0x3807, 0x47},
2687ee85054SArec Kao {0x3808, 0x10},
2697ee85054SArec Kao {0x3809, 0x70},
2707ee85054SArec Kao {0x380a, 0x0c},
2717ee85054SArec Kao {0x380b, 0x30},
2727ee85054SArec Kao {0x380c, 0x04},
2737ee85054SArec Kao {0x380d, 0x98},
2747ee85054SArec Kao {0x380e, 0x0c},
2757ee85054SArec Kao {0x380f, 0x7c},
2767ee85054SArec Kao {0x3810, 0x00},
2777ee85054SArec Kao {0x3811, 0x0f},
2787ee85054SArec Kao {0x3812, 0x00},
2797ee85054SArec Kao {0x3813, 0x09},
2807ee85054SArec Kao {0x3814, 0x01},
2817ee85054SArec Kao {0x3816, 0x01},
2827ee85054SArec Kao {0x3820, 0x88},
2837ee85054SArec Kao {0x3c8c, 0x19},
2847ee85054SArec Kao {0x4008, 0x02},
2857ee85054SArec Kao {0x4009, 0x0f},
2867ee85054SArec Kao {0x4050, 0x02},
2877ee85054SArec Kao {0x4051, 0x09},
2887ee85054SArec Kao {0x4501, 0x00},
2897ee85054SArec Kao {0x4505, 0x00},
2907ee85054SArec Kao {0x4837, 0x0e},
2917ee85054SArec Kao {0x5000, 0xff},
2927ee85054SArec Kao {0x5001, 0x0f},
2937ee85054SArec Kao };
2947ee85054SArec Kao
2957ee85054SArec Kao static const struct ov13b10_reg mode_4160x3120_regs[] = {
2967ee85054SArec Kao {0x0305, 0xaf},
2977ee85054SArec Kao {0x3501, 0x0c},
2987ee85054SArec Kao {0x3662, 0x92},
2997ee85054SArec Kao {0x3714, 0x24},
3007ee85054SArec Kao {0x3739, 0x12},
3017ee85054SArec Kao {0x37c2, 0x04},
3027ee85054SArec Kao {0x37d9, 0x0c},
3037ee85054SArec Kao {0x37e2, 0x0a},
3047ee85054SArec Kao {0x3800, 0x00},
3057ee85054SArec Kao {0x3801, 0x00},
3067ee85054SArec Kao {0x3802, 0x00},
3077ee85054SArec Kao {0x3803, 0x08},
3087ee85054SArec Kao {0x3804, 0x10},
3097ee85054SArec Kao {0x3805, 0x8f},
3107ee85054SArec Kao {0x3806, 0x0c},
3117ee85054SArec Kao {0x3807, 0x47},
3127ee85054SArec Kao {0x3808, 0x10},
3137ee85054SArec Kao {0x3809, 0x40},
3147ee85054SArec Kao {0x380a, 0x0c},
3157ee85054SArec Kao {0x380b, 0x30},
3167ee85054SArec Kao {0x380c, 0x04},
3177ee85054SArec Kao {0x380d, 0x98},
3187ee85054SArec Kao {0x380e, 0x0c},
3197ee85054SArec Kao {0x380f, 0x7c},
3207ee85054SArec Kao {0x3810, 0x00},
3217ee85054SArec Kao {0x3811, 0x27},
3227ee85054SArec Kao {0x3812, 0x00},
3237ee85054SArec Kao {0x3813, 0x09},
3247ee85054SArec Kao {0x3814, 0x01},
3257ee85054SArec Kao {0x3816, 0x01},
3267ee85054SArec Kao {0x3820, 0x88},
3277ee85054SArec Kao {0x3c8c, 0x19},
3287ee85054SArec Kao {0x4008, 0x02},
3297ee85054SArec Kao {0x4009, 0x0f},
3307ee85054SArec Kao {0x4050, 0x02},
3317ee85054SArec Kao {0x4051, 0x09},
3327ee85054SArec Kao {0x4501, 0x00},
3337ee85054SArec Kao {0x4505, 0x00},
3347ee85054SArec Kao {0x4837, 0x0e},
3357ee85054SArec Kao {0x5000, 0xff},
3367ee85054SArec Kao {0x5001, 0x0f},
3377ee85054SArec Kao };
3387ee85054SArec Kao
3397ee85054SArec Kao static const struct ov13b10_reg mode_4160x2340_regs[] = {
3407ee85054SArec Kao {0x0305, 0xaf},
3417ee85054SArec Kao {0x3501, 0x0c},
3427ee85054SArec Kao {0x3662, 0x92},
3437ee85054SArec Kao {0x3714, 0x24},
3447ee85054SArec Kao {0x3739, 0x12},
3457ee85054SArec Kao {0x37c2, 0x04},
3467ee85054SArec Kao {0x37d9, 0x0c},
3477ee85054SArec Kao {0x37e2, 0x0a},
3487ee85054SArec Kao {0x3800, 0x00},
3497ee85054SArec Kao {0x3801, 0x00},
3507ee85054SArec Kao {0x3802, 0x00},
3517ee85054SArec Kao {0x3803, 0x08},
3527ee85054SArec Kao {0x3804, 0x10},
3537ee85054SArec Kao {0x3805, 0x8f},
3547ee85054SArec Kao {0x3806, 0x0c},
3557ee85054SArec Kao {0x3807, 0x47},
3567ee85054SArec Kao {0x3808, 0x10},
3577ee85054SArec Kao {0x3809, 0x40},
3587ee85054SArec Kao {0x380a, 0x09},
3597ee85054SArec Kao {0x380b, 0x24},
3607ee85054SArec Kao {0x380c, 0x04},
3617ee85054SArec Kao {0x380d, 0x98},
3627ee85054SArec Kao {0x380e, 0x0c},
3637ee85054SArec Kao {0x380f, 0x7c},
3647ee85054SArec Kao {0x3810, 0x00},
3657ee85054SArec Kao {0x3811, 0x27},
3667ee85054SArec Kao {0x3812, 0x01},
3677ee85054SArec Kao {0x3813, 0x8f},
3687ee85054SArec Kao {0x3814, 0x01},
3697ee85054SArec Kao {0x3816, 0x01},
3707ee85054SArec Kao {0x3820, 0x88},
3717ee85054SArec Kao {0x3c8c, 0x19},
3727ee85054SArec Kao {0x4008, 0x02},
3737ee85054SArec Kao {0x4009, 0x0f},
3747ee85054SArec Kao {0x4050, 0x02},
3757ee85054SArec Kao {0x4051, 0x09},
3767ee85054SArec Kao {0x4501, 0x00},
3777ee85054SArec Kao {0x4505, 0x00},
3787ee85054SArec Kao {0x4837, 0x0e},
3797ee85054SArec Kao {0x5000, 0xff},
3807ee85054SArec Kao {0x5001, 0x0f},
3817ee85054SArec Kao };
3827ee85054SArec Kao
3837ee85054SArec Kao static const struct ov13b10_reg mode_2104x1560_regs[] = {
3847ee85054SArec Kao {0x0305, 0xaf},
3857ee85054SArec Kao {0x3501, 0x06},
3867ee85054SArec Kao {0x3662, 0x88},
3877ee85054SArec Kao {0x3714, 0x28},
3887ee85054SArec Kao {0x3739, 0x10},
3897ee85054SArec Kao {0x37c2, 0x14},
3907ee85054SArec Kao {0x37d9, 0x06},
3917ee85054SArec Kao {0x37e2, 0x0c},
3927ee85054SArec Kao {0x3800, 0x00},
3937ee85054SArec Kao {0x3801, 0x00},
3947ee85054SArec Kao {0x3802, 0x00},
3957ee85054SArec Kao {0x3803, 0x08},
3967ee85054SArec Kao {0x3804, 0x10},
3977ee85054SArec Kao {0x3805, 0x8f},
3987ee85054SArec Kao {0x3806, 0x0c},
3997ee85054SArec Kao {0x3807, 0x47},
4007ee85054SArec Kao {0x3808, 0x08},
4017ee85054SArec Kao {0x3809, 0x38},
4027ee85054SArec Kao {0x380a, 0x06},
4037ee85054SArec Kao {0x380b, 0x18},
4047ee85054SArec Kao {0x380c, 0x04},
4057ee85054SArec Kao {0x380d, 0x98},
4067ee85054SArec Kao {0x380e, 0x06},
4077ee85054SArec Kao {0x380f, 0x3e},
4087ee85054SArec Kao {0x3810, 0x00},
4097ee85054SArec Kao {0x3811, 0x07},
4107ee85054SArec Kao {0x3812, 0x00},
4117ee85054SArec Kao {0x3813, 0x05},
4127ee85054SArec Kao {0x3814, 0x03},
4137ee85054SArec Kao {0x3816, 0x03},
4147ee85054SArec Kao {0x3820, 0x8b},
4157ee85054SArec Kao {0x3c8c, 0x18},
4167ee85054SArec Kao {0x4008, 0x00},
4177ee85054SArec Kao {0x4009, 0x05},
4187ee85054SArec Kao {0x4050, 0x00},
4197ee85054SArec Kao {0x4051, 0x05},
4207ee85054SArec Kao {0x4501, 0x08},
4217ee85054SArec Kao {0x4505, 0x00},
4227ee85054SArec Kao {0x4837, 0x0e},
4237ee85054SArec Kao {0x5000, 0xfd},
4247ee85054SArec Kao {0x5001, 0x0d},
4257ee85054SArec Kao };
4267ee85054SArec Kao
4277ee85054SArec Kao static const struct ov13b10_reg mode_2080x1170_regs[] = {
4287ee85054SArec Kao {0x0305, 0xaf},
4297ee85054SArec Kao {0x3501, 0x06},
4307ee85054SArec Kao {0x3662, 0x88},
4317ee85054SArec Kao {0x3714, 0x28},
4327ee85054SArec Kao {0x3739, 0x10},
4337ee85054SArec Kao {0x37c2, 0x14},
4347ee85054SArec Kao {0x37d9, 0x06},
4357ee85054SArec Kao {0x37e2, 0x0c},
4367ee85054SArec Kao {0x3800, 0x00},
4377ee85054SArec Kao {0x3801, 0x00},
4387ee85054SArec Kao {0x3802, 0x00},
4397ee85054SArec Kao {0x3803, 0x08},
4407ee85054SArec Kao {0x3804, 0x10},
4417ee85054SArec Kao {0x3805, 0x8f},
4427ee85054SArec Kao {0x3806, 0x0c},
4437ee85054SArec Kao {0x3807, 0x47},
4447ee85054SArec Kao {0x3808, 0x08},
4457ee85054SArec Kao {0x3809, 0x20},
4467ee85054SArec Kao {0x380a, 0x04},
4477ee85054SArec Kao {0x380b, 0x92},
4487ee85054SArec Kao {0x380c, 0x04},
4497ee85054SArec Kao {0x380d, 0x98},
4507ee85054SArec Kao {0x380e, 0x06},
4517ee85054SArec Kao {0x380f, 0x3e},
4527ee85054SArec Kao {0x3810, 0x00},
4537ee85054SArec Kao {0x3811, 0x13},
4547ee85054SArec Kao {0x3812, 0x00},
4557ee85054SArec Kao {0x3813, 0xc9},
4567ee85054SArec Kao {0x3814, 0x03},
4577ee85054SArec Kao {0x3816, 0x03},
4587ee85054SArec Kao {0x3820, 0x8b},
4597ee85054SArec Kao {0x3c8c, 0x18},
4607ee85054SArec Kao {0x4008, 0x00},
4617ee85054SArec Kao {0x4009, 0x05},
4627ee85054SArec Kao {0x4050, 0x00},
4637ee85054SArec Kao {0x4051, 0x05},
4647ee85054SArec Kao {0x4501, 0x08},
4657ee85054SArec Kao {0x4505, 0x00},
4667ee85054SArec Kao {0x4837, 0x0e},
4677ee85054SArec Kao {0x5000, 0xfd},
4687ee85054SArec Kao {0x5001, 0x0d},
4697ee85054SArec Kao };
4707ee85054SArec Kao
4717ee85054SArec Kao static const char * const ov13b10_test_pattern_menu[] = {
4727ee85054SArec Kao "Disabled",
4737ee85054SArec Kao "Vertical Color Bar Type 1",
4747ee85054SArec Kao "Vertical Color Bar Type 2",
4757ee85054SArec Kao "Vertical Color Bar Type 3",
4767ee85054SArec Kao "Vertical Color Bar Type 4"
4777ee85054SArec Kao };
4787ee85054SArec Kao
4797ee85054SArec Kao /* Configurations for supported link frequencies */
4807ee85054SArec Kao #define OV13B10_LINK_FREQ_560MHZ 560000000ULL
4817ee85054SArec Kao #define OV13B10_LINK_FREQ_INDEX_0 0
4827ee85054SArec Kao
4837ee85054SArec Kao #define OV13B10_EXT_CLK 19200000
4847ee85054SArec Kao #define OV13B10_DATA_LANES 4
4857ee85054SArec Kao
4867ee85054SArec Kao /*
4877ee85054SArec Kao * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
4887ee85054SArec Kao * data rate => double data rate; number of lanes => 4; bits per pixel => 10
4897ee85054SArec Kao */
link_freq_to_pixel_rate(u64 f)4907ee85054SArec Kao static u64 link_freq_to_pixel_rate(u64 f)
4917ee85054SArec Kao {
4927ee85054SArec Kao f *= 2 * OV13B10_DATA_LANES;
4937ee85054SArec Kao do_div(f, 10);
4947ee85054SArec Kao
4957ee85054SArec Kao return f;
4967ee85054SArec Kao }
4977ee85054SArec Kao
4987ee85054SArec Kao /* Menu items for LINK_FREQ V4L2 control */
4997ee85054SArec Kao static const s64 link_freq_menu_items[] = {
5007ee85054SArec Kao OV13B10_LINK_FREQ_560MHZ
5017ee85054SArec Kao };
5027ee85054SArec Kao
5037ee85054SArec Kao /* Link frequency configs */
5047ee85054SArec Kao static const struct ov13b10_link_freq_config
5057ee85054SArec Kao link_freq_configs[] = {
5067ee85054SArec Kao {
5077ee85054SArec Kao .pixels_per_line = OV13B10_PPL_560MHZ,
5087ee85054SArec Kao .reg_list = {
5097ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mipi_data_rate_1120mbps),
5107ee85054SArec Kao .regs = mipi_data_rate_1120mbps,
5117ee85054SArec Kao }
5127ee85054SArec Kao }
5137ee85054SArec Kao };
5147ee85054SArec Kao
5157ee85054SArec Kao /* Mode configs */
5167ee85054SArec Kao static const struct ov13b10_mode supported_modes[] = {
5177ee85054SArec Kao {
5187ee85054SArec Kao .width = 4208,
5197ee85054SArec Kao .height = 3120,
5207ee85054SArec Kao .vts_def = OV13B10_VTS_30FPS,
5217ee85054SArec Kao .vts_min = OV13B10_VTS_30FPS,
5227ee85054SArec Kao .reg_list = {
5237ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs),
5247ee85054SArec Kao .regs = mode_4208x3120_regs,
5257ee85054SArec Kao },
5267ee85054SArec Kao .link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5277ee85054SArec Kao },
5287ee85054SArec Kao {
5297ee85054SArec Kao .width = 4160,
5307ee85054SArec Kao .height = 3120,
5317ee85054SArec Kao .vts_def = OV13B10_VTS_30FPS,
5327ee85054SArec Kao .vts_min = OV13B10_VTS_30FPS,
5337ee85054SArec Kao .reg_list = {
5347ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mode_4160x3120_regs),
5357ee85054SArec Kao .regs = mode_4160x3120_regs,
5367ee85054SArec Kao },
5377ee85054SArec Kao .link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5387ee85054SArec Kao },
5397ee85054SArec Kao {
5407ee85054SArec Kao .width = 4160,
5417ee85054SArec Kao .height = 2340,
5427ee85054SArec Kao .vts_def = OV13B10_VTS_30FPS,
5437ee85054SArec Kao .vts_min = OV13B10_VTS_30FPS,
5447ee85054SArec Kao .reg_list = {
5457ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mode_4160x2340_regs),
5467ee85054SArec Kao .regs = mode_4160x2340_regs,
5477ee85054SArec Kao },
5487ee85054SArec Kao .link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5497ee85054SArec Kao },
5507ee85054SArec Kao {
5517ee85054SArec Kao .width = 2104,
5527ee85054SArec Kao .height = 1560,
5537ee85054SArec Kao .vts_def = OV13B10_VTS_60FPS,
5547ee85054SArec Kao .vts_min = OV13B10_VTS_60FPS,
5557ee85054SArec Kao .reg_list = {
5567ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mode_2104x1560_regs),
5577ee85054SArec Kao .regs = mode_2104x1560_regs,
5587ee85054SArec Kao },
5597ee85054SArec Kao .link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5607ee85054SArec Kao },
5617ee85054SArec Kao {
5627ee85054SArec Kao .width = 2080,
5637ee85054SArec Kao .height = 1170,
5647ee85054SArec Kao .vts_def = OV13B10_VTS_60FPS,
5657ee85054SArec Kao .vts_min = OV13B10_VTS_60FPS,
5667ee85054SArec Kao .reg_list = {
5677ee85054SArec Kao .num_of_regs = ARRAY_SIZE(mode_2080x1170_regs),
5687ee85054SArec Kao .regs = mode_2080x1170_regs,
5697ee85054SArec Kao },
5707ee85054SArec Kao .link_freq_index = OV13B10_LINK_FREQ_INDEX_0,
5717ee85054SArec Kao }
5727ee85054SArec Kao };
5737ee85054SArec Kao
5747ee85054SArec Kao struct ov13b10 {
5757ee85054SArec Kao struct v4l2_subdev sd;
5767ee85054SArec Kao struct media_pad pad;
5777ee85054SArec Kao
5787ee85054SArec Kao struct v4l2_ctrl_handler ctrl_handler;
5796e28afd1SBingbu Cao
5806e28afd1SBingbu Cao struct clk *img_clk;
5816e28afd1SBingbu Cao struct regulator *avdd;
5826e28afd1SBingbu Cao struct gpio_desc *reset;
5836e28afd1SBingbu Cao
5847ee85054SArec Kao /* V4L2 Controls */
5857ee85054SArec Kao struct v4l2_ctrl *link_freq;
5867ee85054SArec Kao struct v4l2_ctrl *pixel_rate;
5877ee85054SArec Kao struct v4l2_ctrl *vblank;
5887ee85054SArec Kao struct v4l2_ctrl *hblank;
5897ee85054SArec Kao struct v4l2_ctrl *exposure;
5907ee85054SArec Kao
5917ee85054SArec Kao /* Current mode */
5927ee85054SArec Kao const struct ov13b10_mode *cur_mode;
5937ee85054SArec Kao
5947ee85054SArec Kao /* Mutex for serialized access */
5957ee85054SArec Kao struct mutex mutex;
5967ee85054SArec Kao
5977ee85054SArec Kao /* Streaming on/off */
5987ee85054SArec Kao bool streaming;
5991af2f618SArec Kao
6001af2f618SArec Kao /* True if the device has been identified */
6011af2f618SArec Kao bool identified;
6027ee85054SArec Kao };
6037ee85054SArec Kao
6047ee85054SArec Kao #define to_ov13b10(_sd) container_of(_sd, struct ov13b10, sd)
6057ee85054SArec Kao
6067ee85054SArec Kao /* Read registers up to 4 at a time */
ov13b10_read_reg(struct ov13b10 * ov13b,u16 reg,u32 len,u32 * val)6077ee85054SArec Kao static int ov13b10_read_reg(struct ov13b10 *ov13b,
6087ee85054SArec Kao u16 reg, u32 len, u32 *val)
6097ee85054SArec Kao {
6107ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
6117ee85054SArec Kao struct i2c_msg msgs[2];
6127ee85054SArec Kao u8 *data_be_p;
6137ee85054SArec Kao int ret;
6147ee85054SArec Kao __be32 data_be = 0;
6157ee85054SArec Kao __be16 reg_addr_be = cpu_to_be16(reg);
6167ee85054SArec Kao
6177ee85054SArec Kao if (len > 4)
6187ee85054SArec Kao return -EINVAL;
6197ee85054SArec Kao
6207ee85054SArec Kao data_be_p = (u8 *)&data_be;
6217ee85054SArec Kao /* Write register address */
6227ee85054SArec Kao msgs[0].addr = client->addr;
6237ee85054SArec Kao msgs[0].flags = 0;
6247ee85054SArec Kao msgs[0].len = 2;
6257ee85054SArec Kao msgs[0].buf = (u8 *)®_addr_be;
6267ee85054SArec Kao
6277ee85054SArec Kao /* Read data from register */
6287ee85054SArec Kao msgs[1].addr = client->addr;
6297ee85054SArec Kao msgs[1].flags = I2C_M_RD;
6307ee85054SArec Kao msgs[1].len = len;
6317ee85054SArec Kao msgs[1].buf = &data_be_p[4 - len];
6327ee85054SArec Kao
6337ee85054SArec Kao ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
6347ee85054SArec Kao if (ret != ARRAY_SIZE(msgs))
6357ee85054SArec Kao return -EIO;
6367ee85054SArec Kao
6377ee85054SArec Kao *val = be32_to_cpu(data_be);
6387ee85054SArec Kao
6397ee85054SArec Kao return 0;
6407ee85054SArec Kao }
6417ee85054SArec Kao
6427ee85054SArec Kao /* Write registers up to 4 at a time */
ov13b10_write_reg(struct ov13b10 * ov13b,u16 reg,u32 len,u32 __val)6437ee85054SArec Kao static int ov13b10_write_reg(struct ov13b10 *ov13b,
6447ee85054SArec Kao u16 reg, u32 len, u32 __val)
6457ee85054SArec Kao {
6467ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
6477ee85054SArec Kao int buf_i, val_i;
6487ee85054SArec Kao u8 buf[6], *val_p;
6497ee85054SArec Kao __be32 val;
6507ee85054SArec Kao
6517ee85054SArec Kao if (len > 4)
6527ee85054SArec Kao return -EINVAL;
6537ee85054SArec Kao
6547ee85054SArec Kao buf[0] = reg >> 8;
6557ee85054SArec Kao buf[1] = reg & 0xff;
6567ee85054SArec Kao
6577ee85054SArec Kao val = cpu_to_be32(__val);
6587ee85054SArec Kao val_p = (u8 *)&val;
6597ee85054SArec Kao buf_i = 2;
6607ee85054SArec Kao val_i = 4 - len;
6617ee85054SArec Kao
6627ee85054SArec Kao while (val_i < 4)
6637ee85054SArec Kao buf[buf_i++] = val_p[val_i++];
6647ee85054SArec Kao
6657ee85054SArec Kao if (i2c_master_send(client, buf, len + 2) != len + 2)
6667ee85054SArec Kao return -EIO;
6677ee85054SArec Kao
6687ee85054SArec Kao return 0;
6697ee85054SArec Kao }
6707ee85054SArec Kao
6717ee85054SArec Kao /* Write a list of registers */
ov13b10_write_regs(struct ov13b10 * ov13b,const struct ov13b10_reg * regs,u32 len)6727ee85054SArec Kao static int ov13b10_write_regs(struct ov13b10 *ov13b,
6737ee85054SArec Kao const struct ov13b10_reg *regs, u32 len)
6747ee85054SArec Kao {
6757ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
6767ee85054SArec Kao int ret;
6777ee85054SArec Kao u32 i;
6787ee85054SArec Kao
6797ee85054SArec Kao for (i = 0; i < len; i++) {
6807ee85054SArec Kao ret = ov13b10_write_reg(ov13b, regs[i].address, 1,
6817ee85054SArec Kao regs[i].val);
6827ee85054SArec Kao if (ret) {
6837ee85054SArec Kao dev_err_ratelimited(&client->dev,
6847ee85054SArec Kao "Failed to write reg 0x%4.4x. error = %d\n",
6857ee85054SArec Kao regs[i].address, ret);
6867ee85054SArec Kao
6877ee85054SArec Kao return ret;
6887ee85054SArec Kao }
6897ee85054SArec Kao }
6907ee85054SArec Kao
6917ee85054SArec Kao return 0;
6927ee85054SArec Kao }
6937ee85054SArec Kao
ov13b10_write_reg_list(struct ov13b10 * ov13b,const struct ov13b10_reg_list * r_list)6947ee85054SArec Kao static int ov13b10_write_reg_list(struct ov13b10 *ov13b,
6957ee85054SArec Kao const struct ov13b10_reg_list *r_list)
6967ee85054SArec Kao {
6977ee85054SArec Kao return ov13b10_write_regs(ov13b, r_list->regs, r_list->num_of_regs);
6987ee85054SArec Kao }
6997ee85054SArec Kao
7007ee85054SArec Kao /* Open sub-device */
ov13b10_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)7017ee85054SArec Kao static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
7027ee85054SArec Kao {
7037ee85054SArec Kao const struct ov13b10_mode *default_mode = &supported_modes[0];
7047ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
7057ee85054SArec Kao struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
7067ee85054SArec Kao fh->state,
7077ee85054SArec Kao 0);
7087ee85054SArec Kao
7097ee85054SArec Kao mutex_lock(&ov13b->mutex);
7107ee85054SArec Kao
7117ee85054SArec Kao /* Initialize try_fmt */
7127ee85054SArec Kao try_fmt->width = default_mode->width;
7137ee85054SArec Kao try_fmt->height = default_mode->height;
7147ee85054SArec Kao try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
7157ee85054SArec Kao try_fmt->field = V4L2_FIELD_NONE;
7167ee85054SArec Kao
7177ee85054SArec Kao /* No crop or compose */
7187ee85054SArec Kao mutex_unlock(&ov13b->mutex);
7197ee85054SArec Kao
7207ee85054SArec Kao return 0;
7217ee85054SArec Kao }
7227ee85054SArec Kao
ov13b10_update_digital_gain(struct ov13b10 * ov13b,u32 d_gain)7237ee85054SArec Kao static int ov13b10_update_digital_gain(struct ov13b10 *ov13b, u32 d_gain)
7247ee85054SArec Kao {
7257ee85054SArec Kao int ret;
7267ee85054SArec Kao u32 val;
7277ee85054SArec Kao
7287ee85054SArec Kao /*
7297ee85054SArec Kao * 0x350C[7:6], 0x350B[7:0], 0x350A[1:0]
7307ee85054SArec Kao */
7317ee85054SArec Kao
7327ee85054SArec Kao val = (d_gain & OV13B10_DGTL_GAIN_L_MASK) << OV13B10_DGTL_GAIN_L_SHIFT;
7337ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_L,
7347ee85054SArec Kao OV13B10_REG_VALUE_08BIT, val);
7357ee85054SArec Kao if (ret)
7367ee85054SArec Kao return ret;
7377ee85054SArec Kao
7387ee85054SArec Kao val = (d_gain >> OV13B10_DGTL_GAIN_M_SHIFT) & OV13B10_DGTL_GAIN_M_MASK;
7397ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_M,
7407ee85054SArec Kao OV13B10_REG_VALUE_08BIT, val);
7417ee85054SArec Kao if (ret)
7427ee85054SArec Kao return ret;
7437ee85054SArec Kao
7447ee85054SArec Kao val = (d_gain >> OV13B10_DGTL_GAIN_H_SHIFT) & OV13B10_DGTL_GAIN_H_MASK;
7457ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_DGTL_GAIN_H,
7467ee85054SArec Kao OV13B10_REG_VALUE_08BIT, val);
7477ee85054SArec Kao
7487ee85054SArec Kao return ret;
7497ee85054SArec Kao }
7507ee85054SArec Kao
ov13b10_enable_test_pattern(struct ov13b10 * ov13b,u32 pattern)7517ee85054SArec Kao static int ov13b10_enable_test_pattern(struct ov13b10 *ov13b, u32 pattern)
7527ee85054SArec Kao {
7537ee85054SArec Kao int ret;
7547ee85054SArec Kao u32 val;
7557ee85054SArec Kao
7567ee85054SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_TEST_PATTERN,
7577ee85054SArec Kao OV13B10_REG_VALUE_08BIT, &val);
7587ee85054SArec Kao if (ret)
7597ee85054SArec Kao return ret;
7607ee85054SArec Kao
7617ee85054SArec Kao if (pattern) {
7627ee85054SArec Kao val &= OV13B10_TEST_PATTERN_MASK;
7637ee85054SArec Kao val |= ((pattern - 1) << OV13B10_TEST_PATTERN_BAR_SHIFT) |
7647ee85054SArec Kao OV13B10_TEST_PATTERN_ENABLE;
7657ee85054SArec Kao } else {
7667ee85054SArec Kao val &= ~OV13B10_TEST_PATTERN_ENABLE;
7677ee85054SArec Kao }
7687ee85054SArec Kao
7697ee85054SArec Kao return ov13b10_write_reg(ov13b, OV13B10_REG_TEST_PATTERN,
7707ee85054SArec Kao OV13B10_REG_VALUE_08BIT, val);
7717ee85054SArec Kao }
7727ee85054SArec Kao
ov13b10_set_ctrl_hflip(struct ov13b10 * ov13b,u32 ctrl_val)7737ee85054SArec Kao static int ov13b10_set_ctrl_hflip(struct ov13b10 *ov13b, u32 ctrl_val)
7747ee85054SArec Kao {
7757ee85054SArec Kao int ret;
7767ee85054SArec Kao u32 val;
7777ee85054SArec Kao
7787ee85054SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1,
7797ee85054SArec Kao OV13B10_REG_VALUE_08BIT, &val);
7807ee85054SArec Kao if (ret)
7817ee85054SArec Kao return ret;
7827ee85054SArec Kao
7837ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1,
7847ee85054SArec Kao OV13B10_REG_VALUE_08BIT,
7857ee85054SArec Kao ctrl_val ? val & ~BIT(3) : val);
7867ee85054SArec Kao
7877ee85054SArec Kao if (ret)
7887ee85054SArec Kao return ret;
7897ee85054SArec Kao
7907ee85054SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_H_WIN_OFFSET,
7917ee85054SArec Kao OV13B10_REG_VALUE_08BIT, &val);
7927ee85054SArec Kao if (ret)
7937ee85054SArec Kao return ret;
7947ee85054SArec Kao
7957ee85054SArec Kao /*
7967ee85054SArec Kao * Applying cropping offset to reverse the change of Bayer order
7977ee85054SArec Kao * after mirroring image
7987ee85054SArec Kao */
7997ee85054SArec Kao return ov13b10_write_reg(ov13b, OV13B10_REG_H_WIN_OFFSET,
8007ee85054SArec Kao OV13B10_REG_VALUE_08BIT,
8017ee85054SArec Kao ctrl_val ? ++val : val);
8027ee85054SArec Kao }
8037ee85054SArec Kao
ov13b10_set_ctrl_vflip(struct ov13b10 * ov13b,u32 ctrl_val)8047ee85054SArec Kao static int ov13b10_set_ctrl_vflip(struct ov13b10 *ov13b, u32 ctrl_val)
8057ee85054SArec Kao {
8067ee85054SArec Kao int ret;
8077ee85054SArec Kao u32 val;
8087ee85054SArec Kao
8097ee85054SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_FORMAT1,
8107ee85054SArec Kao OV13B10_REG_VALUE_08BIT, &val);
8117ee85054SArec Kao if (ret)
8127ee85054SArec Kao return ret;
8137ee85054SArec Kao
8147ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_FORMAT1,
8157ee85054SArec Kao OV13B10_REG_VALUE_08BIT,
8167ee85054SArec Kao ctrl_val ? val | BIT(4) | BIT(5) : val);
8177ee85054SArec Kao
8187ee85054SArec Kao if (ret)
8197ee85054SArec Kao return ret;
8207ee85054SArec Kao
8217ee85054SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_V_WIN_OFFSET,
8227ee85054SArec Kao OV13B10_REG_VALUE_08BIT, &val);
8237ee85054SArec Kao if (ret)
8247ee85054SArec Kao return ret;
8257ee85054SArec Kao
8267ee85054SArec Kao /*
8277ee85054SArec Kao * Applying cropping offset to reverse the change of Bayer order
8287ee85054SArec Kao * after flipping image
8297ee85054SArec Kao */
8307ee85054SArec Kao return ov13b10_write_reg(ov13b, OV13B10_REG_V_WIN_OFFSET,
8317ee85054SArec Kao OV13B10_REG_VALUE_08BIT,
8327ee85054SArec Kao ctrl_val ? --val : val);
8337ee85054SArec Kao }
8347ee85054SArec Kao
ov13b10_set_ctrl(struct v4l2_ctrl * ctrl)8357ee85054SArec Kao static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl)
8367ee85054SArec Kao {
8377ee85054SArec Kao struct ov13b10 *ov13b = container_of(ctrl->handler,
8387ee85054SArec Kao struct ov13b10, ctrl_handler);
8397ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
8407ee85054SArec Kao s64 max;
8417ee85054SArec Kao int ret;
8427ee85054SArec Kao
8437ee85054SArec Kao /* Propagate change of current control to all related controls */
8447ee85054SArec Kao switch (ctrl->id) {
8457ee85054SArec Kao case V4L2_CID_VBLANK:
8467ee85054SArec Kao /* Update max exposure while meeting expected vblanking */
8477ee85054SArec Kao max = ov13b->cur_mode->height + ctrl->val - 8;
8487ee85054SArec Kao __v4l2_ctrl_modify_range(ov13b->exposure,
8497ee85054SArec Kao ov13b->exposure->minimum,
8507ee85054SArec Kao max, ov13b->exposure->step, max);
8517ee85054SArec Kao break;
8527ee85054SArec Kao }
8537ee85054SArec Kao
8547ee85054SArec Kao /*
8557ee85054SArec Kao * Applying V4L2 control value only happens
8567ee85054SArec Kao * when power is up for streaming
8577ee85054SArec Kao */
8587ee85054SArec Kao if (!pm_runtime_get_if_in_use(&client->dev))
8597ee85054SArec Kao return 0;
8607ee85054SArec Kao
8617ee85054SArec Kao ret = 0;
8627ee85054SArec Kao switch (ctrl->id) {
8637ee85054SArec Kao case V4L2_CID_ANALOGUE_GAIN:
8647ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_ANALOG_GAIN,
8657ee85054SArec Kao OV13B10_REG_VALUE_16BIT,
8667ee85054SArec Kao ctrl->val << 1);
8677ee85054SArec Kao break;
8687ee85054SArec Kao case V4L2_CID_DIGITAL_GAIN:
8697ee85054SArec Kao ret = ov13b10_update_digital_gain(ov13b, ctrl->val);
8707ee85054SArec Kao break;
8717ee85054SArec Kao case V4L2_CID_EXPOSURE:
8727ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_EXPOSURE,
8737ee85054SArec Kao OV13B10_REG_VALUE_24BIT,
8747ee85054SArec Kao ctrl->val);
8757ee85054SArec Kao break;
8767ee85054SArec Kao case V4L2_CID_VBLANK:
8777ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_VTS,
8787ee85054SArec Kao OV13B10_REG_VALUE_16BIT,
8797ee85054SArec Kao ov13b->cur_mode->height
8807ee85054SArec Kao + ctrl->val);
8817ee85054SArec Kao break;
8827ee85054SArec Kao case V4L2_CID_TEST_PATTERN:
8837ee85054SArec Kao ret = ov13b10_enable_test_pattern(ov13b, ctrl->val);
8847ee85054SArec Kao break;
8857ee85054SArec Kao case V4L2_CID_HFLIP:
8867ee85054SArec Kao ov13b10_set_ctrl_hflip(ov13b, ctrl->val);
8877ee85054SArec Kao break;
8887ee85054SArec Kao case V4L2_CID_VFLIP:
8897ee85054SArec Kao ov13b10_set_ctrl_vflip(ov13b, ctrl->val);
8907ee85054SArec Kao break;
8917ee85054SArec Kao default:
8927ee85054SArec Kao dev_info(&client->dev,
8937ee85054SArec Kao "ctrl(id:0x%x,val:0x%x) is not handled\n",
8947ee85054SArec Kao ctrl->id, ctrl->val);
8957ee85054SArec Kao break;
8967ee85054SArec Kao }
8977ee85054SArec Kao
8987ee85054SArec Kao pm_runtime_put(&client->dev);
8997ee85054SArec Kao
9007ee85054SArec Kao return ret;
9017ee85054SArec Kao }
9027ee85054SArec Kao
9037ee85054SArec Kao static const struct v4l2_ctrl_ops ov13b10_ctrl_ops = {
9047ee85054SArec Kao .s_ctrl = ov13b10_set_ctrl,
9057ee85054SArec Kao };
9067ee85054SArec Kao
ov13b10_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)9077ee85054SArec Kao static int ov13b10_enum_mbus_code(struct v4l2_subdev *sd,
9087ee85054SArec Kao struct v4l2_subdev_state *sd_state,
9097ee85054SArec Kao struct v4l2_subdev_mbus_code_enum *code)
9107ee85054SArec Kao {
9117ee85054SArec Kao /* Only one bayer order(GRBG) is supported */
9127ee85054SArec Kao if (code->index > 0)
9137ee85054SArec Kao return -EINVAL;
9147ee85054SArec Kao
9157ee85054SArec Kao code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
9167ee85054SArec Kao
9177ee85054SArec Kao return 0;
9187ee85054SArec Kao }
9197ee85054SArec Kao
ov13b10_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)9207ee85054SArec Kao static int ov13b10_enum_frame_size(struct v4l2_subdev *sd,
9217ee85054SArec Kao struct v4l2_subdev_state *sd_state,
9227ee85054SArec Kao struct v4l2_subdev_frame_size_enum *fse)
9237ee85054SArec Kao {
9247ee85054SArec Kao if (fse->index >= ARRAY_SIZE(supported_modes))
9257ee85054SArec Kao return -EINVAL;
9267ee85054SArec Kao
9277ee85054SArec Kao if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
9287ee85054SArec Kao return -EINVAL;
9297ee85054SArec Kao
9307ee85054SArec Kao fse->min_width = supported_modes[fse->index].width;
9317ee85054SArec Kao fse->max_width = fse->min_width;
9327ee85054SArec Kao fse->min_height = supported_modes[fse->index].height;
9337ee85054SArec Kao fse->max_height = fse->min_height;
9347ee85054SArec Kao
9357ee85054SArec Kao return 0;
9367ee85054SArec Kao }
9377ee85054SArec Kao
ov13b10_update_pad_format(const struct ov13b10_mode * mode,struct v4l2_subdev_format * fmt)9387ee85054SArec Kao static void ov13b10_update_pad_format(const struct ov13b10_mode *mode,
9397ee85054SArec Kao struct v4l2_subdev_format *fmt)
9407ee85054SArec Kao {
9417ee85054SArec Kao fmt->format.width = mode->width;
9427ee85054SArec Kao fmt->format.height = mode->height;
9437ee85054SArec Kao fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
9447ee85054SArec Kao fmt->format.field = V4L2_FIELD_NONE;
9457ee85054SArec Kao }
9467ee85054SArec Kao
ov13b10_do_get_pad_format(struct ov13b10 * ov13b,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)9477ee85054SArec Kao static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b,
9487ee85054SArec Kao struct v4l2_subdev_state *sd_state,
9497ee85054SArec Kao struct v4l2_subdev_format *fmt)
9507ee85054SArec Kao {
9517ee85054SArec Kao struct v4l2_mbus_framefmt *framefmt;
9527ee85054SArec Kao struct v4l2_subdev *sd = &ov13b->sd;
9537ee85054SArec Kao
9547ee85054SArec Kao if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
9557ee85054SArec Kao framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
9567ee85054SArec Kao fmt->format = *framefmt;
9577ee85054SArec Kao } else {
9587ee85054SArec Kao ov13b10_update_pad_format(ov13b->cur_mode, fmt);
9597ee85054SArec Kao }
9607ee85054SArec Kao
9617ee85054SArec Kao return 0;
9627ee85054SArec Kao }
9637ee85054SArec Kao
ov13b10_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)9647ee85054SArec Kao static int ov13b10_get_pad_format(struct v4l2_subdev *sd,
9657ee85054SArec Kao struct v4l2_subdev_state *sd_state,
9667ee85054SArec Kao struct v4l2_subdev_format *fmt)
9677ee85054SArec Kao {
9687ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
9697ee85054SArec Kao int ret;
9707ee85054SArec Kao
9717ee85054SArec Kao mutex_lock(&ov13b->mutex);
9727ee85054SArec Kao ret = ov13b10_do_get_pad_format(ov13b, sd_state, fmt);
9737ee85054SArec Kao mutex_unlock(&ov13b->mutex);
9747ee85054SArec Kao
9757ee85054SArec Kao return ret;
9767ee85054SArec Kao }
9777ee85054SArec Kao
9787ee85054SArec Kao static int
ov13b10_set_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)9797ee85054SArec Kao ov13b10_set_pad_format(struct v4l2_subdev *sd,
9807ee85054SArec Kao struct v4l2_subdev_state *sd_state,
9817ee85054SArec Kao struct v4l2_subdev_format *fmt)
9827ee85054SArec Kao {
9837ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
9847ee85054SArec Kao const struct ov13b10_mode *mode;
9857ee85054SArec Kao struct v4l2_mbus_framefmt *framefmt;
9867ee85054SArec Kao s32 vblank_def;
9877ee85054SArec Kao s32 vblank_min;
9887ee85054SArec Kao s64 h_blank;
9897ee85054SArec Kao s64 pixel_rate;
9907ee85054SArec Kao s64 link_freq;
9917ee85054SArec Kao
9927ee85054SArec Kao mutex_lock(&ov13b->mutex);
9937ee85054SArec Kao
9947ee85054SArec Kao /* Only one raw bayer(GRBG) order is supported */
9957ee85054SArec Kao if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10)
9967ee85054SArec Kao fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
9977ee85054SArec Kao
9987ee85054SArec Kao mode = v4l2_find_nearest_size(supported_modes,
9997ee85054SArec Kao ARRAY_SIZE(supported_modes),
10007ee85054SArec Kao width, height,
10017ee85054SArec Kao fmt->format.width, fmt->format.height);
10027ee85054SArec Kao ov13b10_update_pad_format(mode, fmt);
10037ee85054SArec Kao if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
10047ee85054SArec Kao framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
10057ee85054SArec Kao *framefmt = fmt->format;
10067ee85054SArec Kao } else {
10077ee85054SArec Kao ov13b->cur_mode = mode;
10087ee85054SArec Kao __v4l2_ctrl_s_ctrl(ov13b->link_freq, mode->link_freq_index);
10097ee85054SArec Kao link_freq = link_freq_menu_items[mode->link_freq_index];
10107ee85054SArec Kao pixel_rate = link_freq_to_pixel_rate(link_freq);
10117ee85054SArec Kao __v4l2_ctrl_s_ctrl_int64(ov13b->pixel_rate, pixel_rate);
10127ee85054SArec Kao
10137ee85054SArec Kao /* Update limits and set FPS to default */
10147ee85054SArec Kao vblank_def = ov13b->cur_mode->vts_def -
10157ee85054SArec Kao ov13b->cur_mode->height;
10167ee85054SArec Kao vblank_min = ov13b->cur_mode->vts_min -
10177ee85054SArec Kao ov13b->cur_mode->height;
10187ee85054SArec Kao __v4l2_ctrl_modify_range(ov13b->vblank, vblank_min,
10197ee85054SArec Kao OV13B10_VTS_MAX
10207ee85054SArec Kao - ov13b->cur_mode->height,
10217ee85054SArec Kao 1,
10227ee85054SArec Kao vblank_def);
10237ee85054SArec Kao __v4l2_ctrl_s_ctrl(ov13b->vblank, vblank_def);
10247ee85054SArec Kao h_blank =
10257ee85054SArec Kao link_freq_configs[mode->link_freq_index].pixels_per_line
10267ee85054SArec Kao - ov13b->cur_mode->width;
10277ee85054SArec Kao __v4l2_ctrl_modify_range(ov13b->hblank, h_blank,
10287ee85054SArec Kao h_blank, 1, h_blank);
10297ee85054SArec Kao }
10307ee85054SArec Kao
10317ee85054SArec Kao mutex_unlock(&ov13b->mutex);
10327ee85054SArec Kao
10337ee85054SArec Kao return 0;
10347ee85054SArec Kao }
10357ee85054SArec Kao
10361af2f618SArec Kao /* Verify chip ID */
ov13b10_identify_module(struct ov13b10 * ov13b)10371af2f618SArec Kao static int ov13b10_identify_module(struct ov13b10 *ov13b)
10381af2f618SArec Kao {
10391af2f618SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
10401af2f618SArec Kao int ret;
10411af2f618SArec Kao u32 val;
10421af2f618SArec Kao
10431af2f618SArec Kao if (ov13b->identified)
10441af2f618SArec Kao return 0;
10451af2f618SArec Kao
10461af2f618SArec Kao ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID,
10471af2f618SArec Kao OV13B10_REG_VALUE_24BIT, &val);
10481af2f618SArec Kao if (ret)
10491af2f618SArec Kao return ret;
10501af2f618SArec Kao
10511af2f618SArec Kao if (val != OV13B10_CHIP_ID) {
10521af2f618SArec Kao dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
10531af2f618SArec Kao OV13B10_CHIP_ID, val);
10541af2f618SArec Kao return -EIO;
10551af2f618SArec Kao }
10561af2f618SArec Kao
10571af2f618SArec Kao ov13b->identified = true;
10581af2f618SArec Kao
10591af2f618SArec Kao return 0;
10601af2f618SArec Kao }
10611af2f618SArec Kao
ov13b10_power_off(struct device * dev)10626e28afd1SBingbu Cao static int ov13b10_power_off(struct device *dev)
10636e28afd1SBingbu Cao {
10646e28afd1SBingbu Cao struct v4l2_subdev *sd = dev_get_drvdata(dev);
10656e28afd1SBingbu Cao struct ov13b10 *ov13b10 = to_ov13b10(sd);
10666e28afd1SBingbu Cao
10676e28afd1SBingbu Cao gpiod_set_value_cansleep(ov13b10->reset, 1);
10686e28afd1SBingbu Cao
10696e28afd1SBingbu Cao if (ov13b10->avdd)
10706e28afd1SBingbu Cao regulator_disable(ov13b10->avdd);
10716e28afd1SBingbu Cao
10726e28afd1SBingbu Cao clk_disable_unprepare(ov13b10->img_clk);
10736e28afd1SBingbu Cao
10746e28afd1SBingbu Cao return 0;
10756e28afd1SBingbu Cao }
10766e28afd1SBingbu Cao
ov13b10_power_on(struct device * dev)10776e28afd1SBingbu Cao static int ov13b10_power_on(struct device *dev)
10786e28afd1SBingbu Cao {
10796e28afd1SBingbu Cao struct v4l2_subdev *sd = dev_get_drvdata(dev);
10806e28afd1SBingbu Cao struct ov13b10 *ov13b10 = to_ov13b10(sd);
10816e28afd1SBingbu Cao int ret;
10826e28afd1SBingbu Cao
10836e28afd1SBingbu Cao ret = clk_prepare_enable(ov13b10->img_clk);
10846e28afd1SBingbu Cao if (ret < 0) {
10856e28afd1SBingbu Cao dev_err(dev, "failed to enable imaging clock: %d", ret);
10866e28afd1SBingbu Cao return ret;
10876e28afd1SBingbu Cao }
10886e28afd1SBingbu Cao
10896e28afd1SBingbu Cao if (ov13b10->avdd) {
10906e28afd1SBingbu Cao ret = regulator_enable(ov13b10->avdd);
10916e28afd1SBingbu Cao if (ret < 0) {
10926e28afd1SBingbu Cao dev_err(dev, "failed to enable avdd: %d", ret);
10936e28afd1SBingbu Cao clk_disable_unprepare(ov13b10->img_clk);
10946e28afd1SBingbu Cao return ret;
10956e28afd1SBingbu Cao }
10966e28afd1SBingbu Cao }
10976e28afd1SBingbu Cao
10986e28afd1SBingbu Cao gpiod_set_value_cansleep(ov13b10->reset, 0);
10996e28afd1SBingbu Cao /* 5ms to wait ready after XSHUTDN assert */
11006e28afd1SBingbu Cao usleep_range(5000, 5500);
11016e28afd1SBingbu Cao
11026e28afd1SBingbu Cao return 0;
11036e28afd1SBingbu Cao }
11046e28afd1SBingbu Cao
ov13b10_start_streaming(struct ov13b10 * ov13b)11057ee85054SArec Kao static int ov13b10_start_streaming(struct ov13b10 *ov13b)
11067ee85054SArec Kao {
11077ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
11087ee85054SArec Kao const struct ov13b10_reg_list *reg_list;
11097ee85054SArec Kao int ret, link_freq_index;
11107ee85054SArec Kao
11111af2f618SArec Kao ret = ov13b10_identify_module(ov13b);
11121af2f618SArec Kao if (ret)
11131af2f618SArec Kao return ret;
11141af2f618SArec Kao
11157ee85054SArec Kao /* Get out of from software reset */
11167ee85054SArec Kao ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST,
11177ee85054SArec Kao OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST);
11187ee85054SArec Kao if (ret) {
11197ee85054SArec Kao dev_err(&client->dev, "%s failed to set powerup registers\n",
11207ee85054SArec Kao __func__);
11217ee85054SArec Kao return ret;
11227ee85054SArec Kao }
11237ee85054SArec Kao
11247ee85054SArec Kao link_freq_index = ov13b->cur_mode->link_freq_index;
11257ee85054SArec Kao reg_list = &link_freq_configs[link_freq_index].reg_list;
11267ee85054SArec Kao ret = ov13b10_write_reg_list(ov13b, reg_list);
11277ee85054SArec Kao if (ret) {
11287ee85054SArec Kao dev_err(&client->dev, "%s failed to set plls\n", __func__);
11297ee85054SArec Kao return ret;
11307ee85054SArec Kao }
11317ee85054SArec Kao
11327ee85054SArec Kao /* Apply default values of current mode */
11337ee85054SArec Kao reg_list = &ov13b->cur_mode->reg_list;
11347ee85054SArec Kao ret = ov13b10_write_reg_list(ov13b, reg_list);
11357ee85054SArec Kao if (ret) {
11367ee85054SArec Kao dev_err(&client->dev, "%s failed to set mode\n", __func__);
11377ee85054SArec Kao return ret;
11387ee85054SArec Kao }
11397ee85054SArec Kao
11407ee85054SArec Kao /* Apply customized values from user */
11417ee85054SArec Kao ret = __v4l2_ctrl_handler_setup(ov13b->sd.ctrl_handler);
11427ee85054SArec Kao if (ret)
11437ee85054SArec Kao return ret;
11447ee85054SArec Kao
11457ee85054SArec Kao return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT,
11467ee85054SArec Kao OV13B10_REG_VALUE_08BIT,
11477ee85054SArec Kao OV13B10_MODE_STREAMING);
11487ee85054SArec Kao }
11497ee85054SArec Kao
11507ee85054SArec Kao /* Stop streaming */
ov13b10_stop_streaming(struct ov13b10 * ov13b)11517ee85054SArec Kao static int ov13b10_stop_streaming(struct ov13b10 *ov13b)
11527ee85054SArec Kao {
11537ee85054SArec Kao return ov13b10_write_reg(ov13b, OV13B10_REG_MODE_SELECT,
11547ee85054SArec Kao OV13B10_REG_VALUE_08BIT, OV13B10_MODE_STANDBY);
11557ee85054SArec Kao }
11567ee85054SArec Kao
ov13b10_set_stream(struct v4l2_subdev * sd,int enable)11577ee85054SArec Kao static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable)
11587ee85054SArec Kao {
11597ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
11607ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(sd);
11617ee85054SArec Kao int ret = 0;
11627ee85054SArec Kao
11637ee85054SArec Kao mutex_lock(&ov13b->mutex);
11647ee85054SArec Kao if (ov13b->streaming == enable) {
11657ee85054SArec Kao mutex_unlock(&ov13b->mutex);
11667ee85054SArec Kao return 0;
11677ee85054SArec Kao }
11687ee85054SArec Kao
11697ee85054SArec Kao if (enable) {
11707ee85054SArec Kao ret = pm_runtime_resume_and_get(&client->dev);
11717ee85054SArec Kao if (ret < 0)
11727ee85054SArec Kao goto err_unlock;
11737ee85054SArec Kao
11747ee85054SArec Kao /*
11757ee85054SArec Kao * Apply default & customized values
11767ee85054SArec Kao * and then start streaming.
11777ee85054SArec Kao */
11787ee85054SArec Kao ret = ov13b10_start_streaming(ov13b);
11797ee85054SArec Kao if (ret)
11807ee85054SArec Kao goto err_rpm_put;
11817ee85054SArec Kao } else {
11827ee85054SArec Kao ov13b10_stop_streaming(ov13b);
11837ee85054SArec Kao pm_runtime_put(&client->dev);
11847ee85054SArec Kao }
11857ee85054SArec Kao
11867ee85054SArec Kao ov13b->streaming = enable;
11877ee85054SArec Kao mutex_unlock(&ov13b->mutex);
11887ee85054SArec Kao
11897ee85054SArec Kao return ret;
11907ee85054SArec Kao
11917ee85054SArec Kao err_rpm_put:
11927ee85054SArec Kao pm_runtime_put(&client->dev);
11937ee85054SArec Kao err_unlock:
11947ee85054SArec Kao mutex_unlock(&ov13b->mutex);
11957ee85054SArec Kao
11967ee85054SArec Kao return ret;
11977ee85054SArec Kao }
11987ee85054SArec Kao
ov13b10_suspend(struct device * dev)11996e28afd1SBingbu Cao static int ov13b10_suspend(struct device *dev)
12007ee85054SArec Kao {
12017ee85054SArec Kao struct v4l2_subdev *sd = dev_get_drvdata(dev);
12027ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
12037ee85054SArec Kao
12047ee85054SArec Kao if (ov13b->streaming)
12057ee85054SArec Kao ov13b10_stop_streaming(ov13b);
12067ee85054SArec Kao
12076e28afd1SBingbu Cao ov13b10_power_off(dev);
12086e28afd1SBingbu Cao
12097ee85054SArec Kao return 0;
12107ee85054SArec Kao }
12117ee85054SArec Kao
ov13b10_resume(struct device * dev)12126e28afd1SBingbu Cao static int ov13b10_resume(struct device *dev)
12137ee85054SArec Kao {
12147ee85054SArec Kao struct v4l2_subdev *sd = dev_get_drvdata(dev);
12157ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
12167ee85054SArec Kao int ret;
12177ee85054SArec Kao
12186e28afd1SBingbu Cao ret = ov13b10_power_on(dev);
12196e28afd1SBingbu Cao if (ret)
12206e28afd1SBingbu Cao goto pm_fail;
12216e28afd1SBingbu Cao
12227ee85054SArec Kao if (ov13b->streaming) {
12237ee85054SArec Kao ret = ov13b10_start_streaming(ov13b);
12247ee85054SArec Kao if (ret)
12256e28afd1SBingbu Cao goto stop_streaming;
12267ee85054SArec Kao }
12277ee85054SArec Kao
12287ee85054SArec Kao return 0;
12297ee85054SArec Kao
12306e28afd1SBingbu Cao stop_streaming:
12317ee85054SArec Kao ov13b10_stop_streaming(ov13b);
12326e28afd1SBingbu Cao ov13b10_power_off(dev);
12336e28afd1SBingbu Cao pm_fail:
12347ee85054SArec Kao ov13b->streaming = false;
12356e28afd1SBingbu Cao
12367ee85054SArec Kao return ret;
12377ee85054SArec Kao }
12387ee85054SArec Kao
12397ee85054SArec Kao static const struct v4l2_subdev_video_ops ov13b10_video_ops = {
12407ee85054SArec Kao .s_stream = ov13b10_set_stream,
12417ee85054SArec Kao };
12427ee85054SArec Kao
12437ee85054SArec Kao static const struct v4l2_subdev_pad_ops ov13b10_pad_ops = {
12447ee85054SArec Kao .enum_mbus_code = ov13b10_enum_mbus_code,
12457ee85054SArec Kao .get_fmt = ov13b10_get_pad_format,
12467ee85054SArec Kao .set_fmt = ov13b10_set_pad_format,
12477ee85054SArec Kao .enum_frame_size = ov13b10_enum_frame_size,
12487ee85054SArec Kao };
12497ee85054SArec Kao
12507ee85054SArec Kao static const struct v4l2_subdev_ops ov13b10_subdev_ops = {
12517ee85054SArec Kao .video = &ov13b10_video_ops,
12527ee85054SArec Kao .pad = &ov13b10_pad_ops,
12537ee85054SArec Kao };
12547ee85054SArec Kao
12557ee85054SArec Kao static const struct media_entity_operations ov13b10_subdev_entity_ops = {
12567ee85054SArec Kao .link_validate = v4l2_subdev_link_validate,
12577ee85054SArec Kao };
12587ee85054SArec Kao
12597ee85054SArec Kao static const struct v4l2_subdev_internal_ops ov13b10_internal_ops = {
12607ee85054SArec Kao .open = ov13b10_open,
12617ee85054SArec Kao };
12627ee85054SArec Kao
12637ee85054SArec Kao /* Initialize control handlers */
ov13b10_init_controls(struct ov13b10 * ov13b)12647ee85054SArec Kao static int ov13b10_init_controls(struct ov13b10 *ov13b)
12657ee85054SArec Kao {
12667ee85054SArec Kao struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd);
12677ee85054SArec Kao struct v4l2_fwnode_device_properties props;
12687ee85054SArec Kao struct v4l2_ctrl_handler *ctrl_hdlr;
12697ee85054SArec Kao s64 exposure_max;
12707ee85054SArec Kao s64 vblank_def;
12717ee85054SArec Kao s64 vblank_min;
12727ee85054SArec Kao s64 hblank;
12737ee85054SArec Kao s64 pixel_rate_min;
12747ee85054SArec Kao s64 pixel_rate_max;
12757ee85054SArec Kao const struct ov13b10_mode *mode;
12767ee85054SArec Kao u32 max;
12777ee85054SArec Kao int ret;
12787ee85054SArec Kao
12797ee85054SArec Kao ctrl_hdlr = &ov13b->ctrl_handler;
12807ee85054SArec Kao ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
12817ee85054SArec Kao if (ret)
12827ee85054SArec Kao return ret;
12837ee85054SArec Kao
12847ee85054SArec Kao mutex_init(&ov13b->mutex);
12857ee85054SArec Kao ctrl_hdlr->lock = &ov13b->mutex;
12867ee85054SArec Kao max = ARRAY_SIZE(link_freq_menu_items) - 1;
12877ee85054SArec Kao ov13b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
12887ee85054SArec Kao &ov13b10_ctrl_ops,
12897ee85054SArec Kao V4L2_CID_LINK_FREQ,
12907ee85054SArec Kao max,
12917ee85054SArec Kao 0,
12927ee85054SArec Kao link_freq_menu_items);
12937ee85054SArec Kao if (ov13b->link_freq)
12947ee85054SArec Kao ov13b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
12957ee85054SArec Kao
12967ee85054SArec Kao pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
12977ee85054SArec Kao pixel_rate_min = 0;
12987ee85054SArec Kao /* By default, PIXEL_RATE is read only */
12997ee85054SArec Kao ov13b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13007ee85054SArec Kao V4L2_CID_PIXEL_RATE,
13017ee85054SArec Kao pixel_rate_min, pixel_rate_max,
13027ee85054SArec Kao 1, pixel_rate_max);
13037ee85054SArec Kao
13047ee85054SArec Kao mode = ov13b->cur_mode;
13057ee85054SArec Kao vblank_def = mode->vts_def - mode->height;
13067ee85054SArec Kao vblank_min = mode->vts_min - mode->height;
13077ee85054SArec Kao ov13b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13087ee85054SArec Kao V4L2_CID_VBLANK,
13097ee85054SArec Kao vblank_min,
13107ee85054SArec Kao OV13B10_VTS_MAX - mode->height, 1,
13117ee85054SArec Kao vblank_def);
13127ee85054SArec Kao
13137ee85054SArec Kao hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
13147ee85054SArec Kao mode->width;
13157ee85054SArec Kao ov13b->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13167ee85054SArec Kao V4L2_CID_HBLANK,
13177ee85054SArec Kao hblank, hblank, 1, hblank);
13187ee85054SArec Kao if (ov13b->hblank)
13197ee85054SArec Kao ov13b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
13207ee85054SArec Kao
13217ee85054SArec Kao exposure_max = mode->vts_def - 8;
13227ee85054SArec Kao ov13b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13237ee85054SArec Kao V4L2_CID_EXPOSURE,
13247ee85054SArec Kao OV13B10_EXPOSURE_MIN,
13257ee85054SArec Kao exposure_max, OV13B10_EXPOSURE_STEP,
13267ee85054SArec Kao exposure_max);
13277ee85054SArec Kao
13287ee85054SArec Kao v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
13297ee85054SArec Kao OV13B10_ANA_GAIN_MIN, OV13B10_ANA_GAIN_MAX,
13307ee85054SArec Kao OV13B10_ANA_GAIN_STEP, OV13B10_ANA_GAIN_DEFAULT);
13317ee85054SArec Kao
13327ee85054SArec Kao /* Digital gain */
13337ee85054SArec Kao v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
13347ee85054SArec Kao OV13B10_DGTL_GAIN_MIN, OV13B10_DGTL_GAIN_MAX,
13357ee85054SArec Kao OV13B10_DGTL_GAIN_STEP, OV13B10_DGTL_GAIN_DEFAULT);
13367ee85054SArec Kao
13377ee85054SArec Kao v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov13b10_ctrl_ops,
13387ee85054SArec Kao V4L2_CID_TEST_PATTERN,
13397ee85054SArec Kao ARRAY_SIZE(ov13b10_test_pattern_menu) - 1,
13407ee85054SArec Kao 0, 0, ov13b10_test_pattern_menu);
13417ee85054SArec Kao
13427ee85054SArec Kao v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13437ee85054SArec Kao V4L2_CID_HFLIP, 0, 1, 1, 0);
13447ee85054SArec Kao v4l2_ctrl_new_std(ctrl_hdlr, &ov13b10_ctrl_ops,
13457ee85054SArec Kao V4L2_CID_VFLIP, 0, 1, 1, 0);
13467ee85054SArec Kao
13477ee85054SArec Kao if (ctrl_hdlr->error) {
13487ee85054SArec Kao ret = ctrl_hdlr->error;
13497ee85054SArec Kao dev_err(&client->dev, "%s control init failed (%d)\n",
13507ee85054SArec Kao __func__, ret);
13517ee85054SArec Kao goto error;
13527ee85054SArec Kao }
13537ee85054SArec Kao
13547ee85054SArec Kao ret = v4l2_fwnode_device_parse(&client->dev, &props);
13557ee85054SArec Kao if (ret)
13567ee85054SArec Kao goto error;
13577ee85054SArec Kao
13587ee85054SArec Kao ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov13b10_ctrl_ops,
13597ee85054SArec Kao &props);
13607ee85054SArec Kao if (ret)
13617ee85054SArec Kao goto error;
13627ee85054SArec Kao
13637ee85054SArec Kao ov13b->sd.ctrl_handler = ctrl_hdlr;
13647ee85054SArec Kao
13657ee85054SArec Kao return 0;
13667ee85054SArec Kao
13677ee85054SArec Kao error:
13687ee85054SArec Kao v4l2_ctrl_handler_free(ctrl_hdlr);
13697ee85054SArec Kao mutex_destroy(&ov13b->mutex);
13707ee85054SArec Kao
13717ee85054SArec Kao return ret;
13727ee85054SArec Kao }
13737ee85054SArec Kao
ov13b10_free_controls(struct ov13b10 * ov13b)13747ee85054SArec Kao static void ov13b10_free_controls(struct ov13b10 *ov13b)
13757ee85054SArec Kao {
13767ee85054SArec Kao v4l2_ctrl_handler_free(ov13b->sd.ctrl_handler);
13777ee85054SArec Kao mutex_destroy(&ov13b->mutex);
13787ee85054SArec Kao }
13797ee85054SArec Kao
ov13b10_get_pm_resources(struct device * dev)13806e28afd1SBingbu Cao static int ov13b10_get_pm_resources(struct device *dev)
13816e28afd1SBingbu Cao {
13826e28afd1SBingbu Cao struct v4l2_subdev *sd = dev_get_drvdata(dev);
13836e28afd1SBingbu Cao struct ov13b10 *ov13b = to_ov13b10(sd);
13846e28afd1SBingbu Cao int ret;
13856e28afd1SBingbu Cao
13866e28afd1SBingbu Cao ov13b->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
13876e28afd1SBingbu Cao if (IS_ERR(ov13b->reset))
13886e28afd1SBingbu Cao return dev_err_probe(dev, PTR_ERR(ov13b->reset),
13896e28afd1SBingbu Cao "failed to get reset gpio\n");
13906e28afd1SBingbu Cao
13916e28afd1SBingbu Cao ov13b->img_clk = devm_clk_get_optional(dev, NULL);
13926e28afd1SBingbu Cao if (IS_ERR(ov13b->img_clk))
13936e28afd1SBingbu Cao return dev_err_probe(dev, PTR_ERR(ov13b->img_clk),
13946e28afd1SBingbu Cao "failed to get imaging clock\n");
13956e28afd1SBingbu Cao
13966e28afd1SBingbu Cao ov13b->avdd = devm_regulator_get_optional(dev, "avdd");
13976e28afd1SBingbu Cao if (IS_ERR(ov13b->avdd)) {
13986e28afd1SBingbu Cao ret = PTR_ERR(ov13b->avdd);
13996e28afd1SBingbu Cao ov13b->avdd = NULL;
14006e28afd1SBingbu Cao if (ret != -ENODEV)
14016e28afd1SBingbu Cao return dev_err_probe(dev, ret,
14026e28afd1SBingbu Cao "failed to get avdd regulator\n");
14036e28afd1SBingbu Cao }
14046e28afd1SBingbu Cao
14056e28afd1SBingbu Cao return 0;
14066e28afd1SBingbu Cao }
14076e28afd1SBingbu Cao
ov13b10_check_hwcfg(struct device * dev)14087ee85054SArec Kao static int ov13b10_check_hwcfg(struct device *dev)
14097ee85054SArec Kao {
14107ee85054SArec Kao struct v4l2_fwnode_endpoint bus_cfg = {
14117ee85054SArec Kao .bus_type = V4L2_MBUS_CSI2_DPHY
14127ee85054SArec Kao };
14137ee85054SArec Kao struct fwnode_handle *ep;
14147ee85054SArec Kao struct fwnode_handle *fwnode = dev_fwnode(dev);
14157ee85054SArec Kao unsigned int i, j;
14167ee85054SArec Kao int ret;
14177ee85054SArec Kao u32 ext_clk;
14187ee85054SArec Kao
14197ee85054SArec Kao if (!fwnode)
14207ee85054SArec Kao return -ENXIO;
14217ee85054SArec Kao
1422b7602d62SBingbu Cao ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1423b7602d62SBingbu Cao if (!ep)
1424b7602d62SBingbu Cao return -EPROBE_DEFER;
1425b7602d62SBingbu Cao
14267ee85054SArec Kao ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
14277ee85054SArec Kao &ext_clk);
14287ee85054SArec Kao if (ret) {
14297ee85054SArec Kao dev_err(dev, "can't get clock frequency");
14307ee85054SArec Kao return ret;
14317ee85054SArec Kao }
14327ee85054SArec Kao
14337ee85054SArec Kao if (ext_clk != OV13B10_EXT_CLK) {
14347ee85054SArec Kao dev_err(dev, "external clock %d is not supported",
14357ee85054SArec Kao ext_clk);
14367ee85054SArec Kao return -EINVAL;
14377ee85054SArec Kao }
14387ee85054SArec Kao
14397ee85054SArec Kao ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
14407ee85054SArec Kao fwnode_handle_put(ep);
14417ee85054SArec Kao if (ret)
14427ee85054SArec Kao return ret;
14437ee85054SArec Kao
14447ee85054SArec Kao if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV13B10_DATA_LANES) {
14457ee85054SArec Kao dev_err(dev, "number of CSI2 data lanes %d is not supported",
14467ee85054SArec Kao bus_cfg.bus.mipi_csi2.num_data_lanes);
14477ee85054SArec Kao ret = -EINVAL;
14487ee85054SArec Kao goto out_err;
14497ee85054SArec Kao }
14507ee85054SArec Kao
14517ee85054SArec Kao if (!bus_cfg.nr_of_link_frequencies) {
14527ee85054SArec Kao dev_err(dev, "no link frequencies defined");
14537ee85054SArec Kao ret = -EINVAL;
14547ee85054SArec Kao goto out_err;
14557ee85054SArec Kao }
14567ee85054SArec Kao
14577ee85054SArec Kao for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
14587ee85054SArec Kao for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
14597ee85054SArec Kao if (link_freq_menu_items[i] ==
14607ee85054SArec Kao bus_cfg.link_frequencies[j])
14617ee85054SArec Kao break;
14627ee85054SArec Kao }
14637ee85054SArec Kao
14647ee85054SArec Kao if (j == bus_cfg.nr_of_link_frequencies) {
14657ee85054SArec Kao dev_err(dev, "no link frequency %lld supported",
14667ee85054SArec Kao link_freq_menu_items[i]);
14677ee85054SArec Kao ret = -EINVAL;
14687ee85054SArec Kao goto out_err;
14697ee85054SArec Kao }
14707ee85054SArec Kao }
14717ee85054SArec Kao
14727ee85054SArec Kao out_err:
14737ee85054SArec Kao v4l2_fwnode_endpoint_free(&bus_cfg);
14747ee85054SArec Kao
14757ee85054SArec Kao return ret;
14767ee85054SArec Kao }
14777ee85054SArec Kao
ov13b10_probe(struct i2c_client * client)14787ee85054SArec Kao static int ov13b10_probe(struct i2c_client *client)
14797ee85054SArec Kao {
14807ee85054SArec Kao struct ov13b10 *ov13b;
14811af2f618SArec Kao bool full_power;
14827ee85054SArec Kao int ret;
14837ee85054SArec Kao
14847ee85054SArec Kao /* Check HW config */
14857ee85054SArec Kao ret = ov13b10_check_hwcfg(&client->dev);
14867ee85054SArec Kao if (ret) {
14877ee85054SArec Kao dev_err(&client->dev, "failed to check hwcfg: %d", ret);
14887ee85054SArec Kao return ret;
14897ee85054SArec Kao }
14907ee85054SArec Kao
14917ee85054SArec Kao ov13b = devm_kzalloc(&client->dev, sizeof(*ov13b), GFP_KERNEL);
14927ee85054SArec Kao if (!ov13b)
14937ee85054SArec Kao return -ENOMEM;
14947ee85054SArec Kao
14957ee85054SArec Kao /* Initialize subdev */
14967ee85054SArec Kao v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops);
14977ee85054SArec Kao
14986e28afd1SBingbu Cao ret = ov13b10_get_pm_resources(&client->dev);
14996e28afd1SBingbu Cao if (ret)
15006e28afd1SBingbu Cao return ret;
15016e28afd1SBingbu Cao
15021af2f618SArec Kao full_power = acpi_dev_state_d0(&client->dev);
15031af2f618SArec Kao if (full_power) {
1504adf4abf7SDan Carpenter ret = ov13b10_power_on(&client->dev);
15056e28afd1SBingbu Cao if (ret) {
15066e28afd1SBingbu Cao dev_err(&client->dev, "failed to power on\n");
15076e28afd1SBingbu Cao return ret;
15086e28afd1SBingbu Cao }
15096e28afd1SBingbu Cao
15107ee85054SArec Kao /* Check module identity */
15117ee85054SArec Kao ret = ov13b10_identify_module(ov13b);
15127ee85054SArec Kao if (ret) {
15137ee85054SArec Kao dev_err(&client->dev, "failed to find sensor: %d\n", ret);
15146e28afd1SBingbu Cao goto error_power_off;
15157ee85054SArec Kao }
15161af2f618SArec Kao }
15177ee85054SArec Kao
15187ee85054SArec Kao /* Set default mode to max resolution */
15197ee85054SArec Kao ov13b->cur_mode = &supported_modes[0];
15207ee85054SArec Kao
15217ee85054SArec Kao ret = ov13b10_init_controls(ov13b);
15227ee85054SArec Kao if (ret)
15236e28afd1SBingbu Cao goto error_power_off;
15247ee85054SArec Kao
15257ee85054SArec Kao /* Initialize subdev */
15267ee85054SArec Kao ov13b->sd.internal_ops = &ov13b10_internal_ops;
15277ee85054SArec Kao ov13b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
15287ee85054SArec Kao ov13b->sd.entity.ops = &ov13b10_subdev_entity_ops;
15297ee85054SArec Kao ov13b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
15307ee85054SArec Kao
15317ee85054SArec Kao /* Initialize source pad */
15327ee85054SArec Kao ov13b->pad.flags = MEDIA_PAD_FL_SOURCE;
15337ee85054SArec Kao ret = media_entity_pads_init(&ov13b->sd.entity, 1, &ov13b->pad);
15347ee85054SArec Kao if (ret) {
15357ee85054SArec Kao dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
15367ee85054SArec Kao goto error_handler_free;
15377ee85054SArec Kao }
15387ee85054SArec Kao
15397ee85054SArec Kao
15407ee85054SArec Kao /*
15417ee85054SArec Kao * Device is already turned on by i2c-core with ACPI domain PM.
15427ee85054SArec Kao * Enable runtime PM and turn off the device.
15437ee85054SArec Kao */
15441af2f618SArec Kao /* Set the device's state to active if it's in D0 state. */
15451af2f618SArec Kao if (full_power)
15467ee85054SArec Kao pm_runtime_set_active(&client->dev);
15477ee85054SArec Kao pm_runtime_enable(&client->dev);
15487ee85054SArec Kao pm_runtime_idle(&client->dev);
15497ee85054SArec Kao
1550*000339cbSBingbu Cao ret = v4l2_async_register_subdev_sensor(&ov13b->sd);
1551*000339cbSBingbu Cao if (ret < 0)
1552*000339cbSBingbu Cao goto error_media_entity_runtime_pm;
1553*000339cbSBingbu Cao
15547ee85054SArec Kao return 0;
15557ee85054SArec Kao
1556*000339cbSBingbu Cao error_media_entity_runtime_pm:
1557*000339cbSBingbu Cao pm_runtime_disable(&client->dev);
1558*000339cbSBingbu Cao if (full_power)
1559*000339cbSBingbu Cao pm_runtime_set_suspended(&client->dev);
15607ee85054SArec Kao media_entity_cleanup(&ov13b->sd.entity);
15617ee85054SArec Kao
15627ee85054SArec Kao error_handler_free:
15637ee85054SArec Kao ov13b10_free_controls(ov13b);
15647ee85054SArec Kao dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
15657ee85054SArec Kao
15666e28afd1SBingbu Cao error_power_off:
15676e28afd1SBingbu Cao ov13b10_power_off(&client->dev);
15686e28afd1SBingbu Cao
15697ee85054SArec Kao return ret;
15707ee85054SArec Kao }
15717ee85054SArec Kao
ov13b10_remove(struct i2c_client * client)1572ed5c2f5fSUwe Kleine-König static void ov13b10_remove(struct i2c_client *client)
15737ee85054SArec Kao {
15747ee85054SArec Kao struct v4l2_subdev *sd = i2c_get_clientdata(client);
15757ee85054SArec Kao struct ov13b10 *ov13b = to_ov13b10(sd);
15767ee85054SArec Kao
15777ee85054SArec Kao v4l2_async_unregister_subdev(sd);
15787ee85054SArec Kao media_entity_cleanup(&sd->entity);
15797ee85054SArec Kao ov13b10_free_controls(ov13b);
15807ee85054SArec Kao
15817ee85054SArec Kao pm_runtime_disable(&client->dev);
1582*000339cbSBingbu Cao pm_runtime_set_suspended(&client->dev);
15837ee85054SArec Kao }
15847ee85054SArec Kao
15856e28afd1SBingbu Cao static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend,
15866e28afd1SBingbu Cao ov13b10_resume, NULL);
15877ee85054SArec Kao
15887ee85054SArec Kao #ifdef CONFIG_ACPI
15897ee85054SArec Kao static const struct acpi_device_id ov13b10_acpi_ids[] = {
15907ee85054SArec Kao {"OVTIDB10"},
15919f71a7baSBingbu Cao {"OVTI13B1"},
15927ee85054SArec Kao { /* sentinel */ }
15937ee85054SArec Kao };
15947ee85054SArec Kao
15957ee85054SArec Kao MODULE_DEVICE_TABLE(acpi, ov13b10_acpi_ids);
15967ee85054SArec Kao #endif
15977ee85054SArec Kao
15987ee85054SArec Kao static struct i2c_driver ov13b10_i2c_driver = {
15997ee85054SArec Kao .driver = {
16007ee85054SArec Kao .name = "ov13b10",
16016e28afd1SBingbu Cao .pm = pm_ptr(&ov13b10_pm_ops),
16027ee85054SArec Kao .acpi_match_table = ACPI_PTR(ov13b10_acpi_ids),
16037ee85054SArec Kao },
1604aaeb31c0SUwe Kleine-König .probe = ov13b10_probe,
16057ee85054SArec Kao .remove = ov13b10_remove,
16061af2f618SArec Kao .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
16077ee85054SArec Kao };
16087ee85054SArec Kao
16097ee85054SArec Kao module_i2c_driver(ov13b10_i2c_driver);
16107ee85054SArec Kao
16117ee85054SArec Kao MODULE_AUTHOR("Kao, Arec <arec.kao@intel.com>");
16127ee85054SArec Kao MODULE_DESCRIPTION("Omnivision ov13b10 sensor driver");
16137ee85054SArec Kao MODULE_LICENSE("GPL v2");
1614