2020-11-19 17:19:33 +01:00
// SPDX-License-Identifier: GPL-2.0
2017-03-22 09:30:27 -03:00
/*
* A V4L2 driver for OmniVision OV5647 cameras .
*
* Based on Samsung S5K6AAFX SXGA 1 / 6 " 1.3M CMOS Image Sensor driver
* Copyright ( C ) 2011 Sylwester Nawrocki < s . nawrocki @ samsung . com >
*
* Based on Omnivision OV7670 Camera Driver
* Copyright ( C ) 2006 - 7 Jonathan Corbet < corbet @ lwn . net >
*
* Copyright ( C ) 2016 , Synopsys , Inc .
*/
# include <linux/clk.h>
# include <linux/delay.h>
2020-11-19 17:19:28 +01:00
# include <linux/gpio/consumer.h>
2017-03-22 09:30:27 -03:00
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/module.h>
2016-08-26 20:17:25 -03:00
# include <linux/of_graph.h>
2020-11-19 17:35:45 +01:00
# include <linux/pm_runtime.h>
2017-03-22 09:30:27 -03:00
# include <linux/slab.h>
# include <linux/videodev2.h>
2020-11-19 17:32:31 +01:00
# include <media/v4l2-ctrls.h>
2017-03-22 09:30:27 -03:00
# include <media/v4l2-device.h>
2016-08-26 20:17:25 -03:00
# include <media/v4l2-fwnode.h>
2017-03-22 09:30:27 -03:00
# include <media/v4l2-image-sizes.h>
# include <media/v4l2-mediabus.h>
2020-11-19 17:19:28 +01:00
/*
* From the datasheet , " 20ms after PWDN goes low or 20ms after RESETB goes
* high if reset is inserted after PWDN goes high , host can access sensor ' s
* SCCB to initialize sensor . "
*/
# define PWDN_ACTIVE_DELAY_MS 20
2017-10-01 12:22:38 +02:00
# define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5)
2020-11-19 17:19:29 +01:00
# define MIPI_CTRL00_LINE_SYNC_ENABLE BIT(4)
2017-10-01 12:22:38 +02:00
# define MIPI_CTRL00_BUS_IDLE BIT(2)
# define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0)
# define OV5647_SW_STANDBY 0x0100
# define OV5647_SW_RESET 0x0103
2020-11-19 17:19:32 +01:00
# define OV5647_REG_CHIPID_H 0x300a
# define OV5647_REG_CHIPID_L 0x300b
# define OV5640_REG_PAD_OUT 0x300d
2020-11-19 17:32:31 +01:00
# define OV5647_REG_EXP_HI 0x3500
# define OV5647_REG_EXP_MID 0x3501
# define OV5647_REG_EXP_LO 0x3502
# define OV5647_REG_AEC_AGC 0x3503
# define OV5647_REG_GAIN_HI 0x350a
# define OV5647_REG_GAIN_LO 0x350b
2020-11-19 17:35:43 +01:00
# define OV5647_REG_VTS_HI 0x380e
# define OV5647_REG_VTS_LO 0x380f
2017-10-01 12:22:38 +02:00
# define OV5647_REG_FRAME_OFF_NUMBER 0x4202
# define OV5647_REG_MIPI_CTRL00 0x4800
# define OV5647_REG_MIPI_CTRL14 0x4814
2020-11-19 17:32:31 +01:00
# define OV5647_REG_AWB 0x5001
2017-03-22 09:30:27 -03:00
# define REG_TERM 0xfffe
# define VAL_TERM 0xfe
# define REG_DLY 0xffff
2020-11-19 17:32:34 +01:00
/* OV5647 native and active pixel array size */
# define OV5647_NATIVE_WIDTH 2624U
# define OV5647_NATIVE_HEIGHT 1956U
# define OV5647_PIXEL_ARRAY_LEFT 16U
# define OV5647_PIXEL_ARRAY_TOP 16U
# define OV5647_PIXEL_ARRAY_WIDTH 2592U
# define OV5647_PIXEL_ARRAY_HEIGHT 1944U
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:43 +01:00
# define OV5647_VBLANK_MIN 4
# define OV5647_VTS_MAX 32767
2020-11-19 17:35:44 +01:00
# define OV5647_EXPOSURE_MIN 4
# define OV5647_EXPOSURE_STEP 1
# define OV5647_EXPOSURE_DEFAULT 1000
# define OV5647_EXPOSURE_MAX 65535
2017-03-22 09:30:27 -03:00
struct regval_list {
u16 addr ;
u8 data ;
} ;
2020-11-19 17:32:33 +01:00
struct ov5647_mode {
struct v4l2_mbus_framefmt format ;
2020-11-19 17:32:34 +01:00
struct v4l2_rect crop ;
2020-11-19 17:35:41 +01:00
u64 pixel_rate ;
2020-11-19 17:35:42 +01:00
int hts ;
2020-11-19 17:35:43 +01:00
int vts ;
2020-11-19 17:32:33 +01:00
const struct regval_list * reg_list ;
unsigned int num_regs ;
} ;
struct ov5647_format_list {
unsigned int mbus_code ;
const struct ov5647_mode * modes ;
unsigned int num_modes ;
} ;
2017-03-22 09:30:27 -03:00
struct ov5647 {
struct v4l2_subdev sd ;
struct media_pad pad ;
struct mutex lock ;
struct clk * xclk ;
2020-11-19 17:19:28 +01:00
struct gpio_desc * pwdn ;
2020-11-19 17:19:29 +01:00
bool clock_ncont ;
2020-11-19 17:32:31 +01:00
struct v4l2_ctrl_handler ctrls ;
2020-11-19 17:32:33 +01:00
const struct ov5647_mode * mode ;
2020-11-19 17:35:41 +01:00
struct v4l2_ctrl * pixel_rate ;
2020-11-19 17:35:42 +01:00
struct v4l2_ctrl * hblank ;
2020-11-19 17:35:43 +01:00
struct v4l2_ctrl * vblank ;
2020-11-19 17:35:44 +01:00
struct v4l2_ctrl * exposure ;
2020-11-19 17:35:46 +01:00
bool streaming ;
2017-03-22 09:30:27 -03:00
} ;
2020-11-19 17:32:32 +01:00
static inline struct ov5647 * to_sensor ( struct v4l2_subdev * sd )
2017-03-22 09:30:27 -03:00
{
return container_of ( sd , struct ov5647 , sd ) ;
}
2020-11-19 17:35:48 +01:00
static const struct regval_list sensor_oe_disable_regs [ ] = {
2017-03-22 09:30:27 -03:00
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
} ;
2020-11-19 17:35:48 +01:00
static const struct regval_list sensor_oe_enable_regs [ ] = {
2017-03-22 09:30:27 -03:00
{ 0x3000 , 0x0f } ,
{ 0x3001 , 0xff } ,
{ 0x3002 , 0xe4 } ,
} ;
2020-11-19 17:32:35 +01:00
static const struct regval_list ov5647_640x480_8bpp [ ] = {
2017-03-22 09:30:27 -03:00
{ 0x0100 , 0x00 } ,
{ 0x0103 , 0x01 } ,
{ 0x3034 , 0x08 } ,
{ 0x3035 , 0x21 } ,
{ 0x3036 , 0x46 } ,
{ 0x303c , 0x11 } ,
{ 0x3106 , 0xf5 } ,
{ 0x3821 , 0x07 } ,
{ 0x3820 , 0x41 } ,
{ 0x3827 , 0xec } ,
{ 0x370c , 0x0f } ,
{ 0x3612 , 0x59 } ,
{ 0x3618 , 0x00 } ,
{ 0x5000 , 0x06 } ,
{ 0x5002 , 0x41 } ,
{ 0x5003 , 0x08 } ,
{ 0x5a00 , 0x08 } ,
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
{ 0x3016 , 0x08 } ,
{ 0x3017 , 0xe0 } ,
{ 0x3018 , 0x44 } ,
{ 0x301c , 0xf8 } ,
{ 0x301d , 0xf0 } ,
{ 0x3a18 , 0x00 } ,
{ 0x3a19 , 0xf8 } ,
{ 0x3c01 , 0x80 } ,
{ 0x3b07 , 0x0c } ,
{ 0x380c , 0x07 } ,
{ 0x380d , 0x68 } ,
{ 0x3814 , 0x31 } ,
{ 0x3815 , 0x31 } ,
{ 0x3708 , 0x64 } ,
{ 0x3709 , 0x52 } ,
{ 0x3808 , 0x02 } ,
{ 0x3809 , 0x80 } ,
{ 0x380a , 0x01 } ,
2020-11-19 17:19:32 +01:00
{ 0x380b , 0xe0 } ,
2017-03-22 09:30:27 -03:00
{ 0x3801 , 0x00 } ,
{ 0x3802 , 0x00 } ,
{ 0x3803 , 0x00 } ,
{ 0x3804 , 0x0a } ,
{ 0x3805 , 0x3f } ,
{ 0x3806 , 0x07 } ,
{ 0x3807 , 0xa1 } ,
{ 0x3811 , 0x08 } ,
{ 0x3813 , 0x02 } ,
{ 0x3630 , 0x2e } ,
{ 0x3632 , 0xe2 } ,
{ 0x3633 , 0x23 } ,
{ 0x3634 , 0x44 } ,
{ 0x3636 , 0x06 } ,
{ 0x3620 , 0x64 } ,
{ 0x3621 , 0xe0 } ,
{ 0x3600 , 0x37 } ,
{ 0x3704 , 0xa0 } ,
{ 0x3703 , 0x5a } ,
{ 0x3715 , 0x78 } ,
{ 0x3717 , 0x01 } ,
{ 0x3731 , 0x02 } ,
{ 0x370b , 0x60 } ,
{ 0x3705 , 0x1a } ,
{ 0x3f05 , 0x02 } ,
{ 0x3f06 , 0x10 } ,
{ 0x3f01 , 0x0a } ,
{ 0x3a08 , 0x01 } ,
{ 0x3a09 , 0x27 } ,
{ 0x3a0a , 0x00 } ,
{ 0x3a0b , 0xf6 } ,
{ 0x3a0d , 0x04 } ,
{ 0x3a0e , 0x03 } ,
{ 0x3a0f , 0x58 } ,
{ 0x3a10 , 0x50 } ,
{ 0x3a1b , 0x58 } ,
{ 0x3a1e , 0x50 } ,
{ 0x3a11 , 0x60 } ,
{ 0x3a1f , 0x28 } ,
{ 0x4001 , 0x02 } ,
{ 0x4004 , 0x02 } ,
{ 0x4000 , 0x09 } ,
{ 0x4837 , 0x24 } ,
{ 0x4050 , 0x6e } ,
{ 0x4051 , 0x8f } ,
{ 0x0100 , 0x01 } ,
} ;
2020-11-19 17:32:36 +01:00
static struct regval_list ov5647_2592x1944_10bpp [ ] = {
{ 0x0100 , 0x00 } ,
{ 0x0103 , 0x01 } ,
{ 0x3034 , 0x1a } ,
{ 0x3035 , 0x21 } ,
{ 0x3036 , 0x69 } ,
{ 0x303c , 0x11 } ,
{ 0x3106 , 0xf5 } ,
{ 0x3821 , 0x06 } ,
{ 0x3820 , 0x00 } ,
{ 0x3827 , 0xec } ,
{ 0x370c , 0x03 } ,
{ 0x3612 , 0x5b } ,
{ 0x3618 , 0x04 } ,
{ 0x5000 , 0x06 } ,
{ 0x5002 , 0x41 } ,
{ 0x5003 , 0x08 } ,
{ 0x5a00 , 0x08 } ,
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
{ 0x3016 , 0x08 } ,
{ 0x3017 , 0xe0 } ,
{ 0x3018 , 0x44 } ,
{ 0x301c , 0xf8 } ,
{ 0x301d , 0xf0 } ,
{ 0x3a18 , 0x00 } ,
{ 0x3a19 , 0xf8 } ,
{ 0x3c01 , 0x80 } ,
{ 0x3b07 , 0x0c } ,
{ 0x380c , 0x0b } ,
{ 0x380d , 0x1c } ,
{ 0x3814 , 0x11 } ,
{ 0x3815 , 0x11 } ,
{ 0x3708 , 0x64 } ,
{ 0x3709 , 0x12 } ,
{ 0x3808 , 0x0a } ,
{ 0x3809 , 0x20 } ,
{ 0x380a , 0x07 } ,
{ 0x380b , 0x98 } ,
{ 0x3800 , 0x00 } ,
{ 0x3801 , 0x00 } ,
{ 0x3802 , 0x00 } ,
{ 0x3803 , 0x00 } ,
{ 0x3804 , 0x0a } ,
{ 0x3805 , 0x3f } ,
{ 0x3806 , 0x07 } ,
{ 0x3807 , 0xa3 } ,
{ 0x3811 , 0x10 } ,
{ 0x3813 , 0x06 } ,
{ 0x3630 , 0x2e } ,
{ 0x3632 , 0xe2 } ,
{ 0x3633 , 0x23 } ,
{ 0x3634 , 0x44 } ,
{ 0x3636 , 0x06 } ,
{ 0x3620 , 0x64 } ,
{ 0x3621 , 0xe0 } ,
{ 0x3600 , 0x37 } ,
{ 0x3704 , 0xa0 } ,
{ 0x3703 , 0x5a } ,
{ 0x3715 , 0x78 } ,
{ 0x3717 , 0x01 } ,
{ 0x3731 , 0x02 } ,
{ 0x370b , 0x60 } ,
{ 0x3705 , 0x1a } ,
{ 0x3f05 , 0x02 } ,
{ 0x3f06 , 0x10 } ,
{ 0x3f01 , 0x0a } ,
{ 0x3a08 , 0x01 } ,
{ 0x3a09 , 0x28 } ,
{ 0x3a0a , 0x00 } ,
{ 0x3a0b , 0xf6 } ,
{ 0x3a0d , 0x08 } ,
{ 0x3a0e , 0x06 } ,
{ 0x3a0f , 0x58 } ,
{ 0x3a10 , 0x50 } ,
{ 0x3a1b , 0x58 } ,
{ 0x3a1e , 0x50 } ,
{ 0x3a11 , 0x60 } ,
{ 0x3a1f , 0x28 } ,
{ 0x4001 , 0x02 } ,
{ 0x4004 , 0x04 } ,
{ 0x4000 , 0x09 } ,
{ 0x4837 , 0x19 } ,
{ 0x4800 , 0x24 } ,
{ 0x3503 , 0x03 } ,
{ 0x0100 , 0x01 } ,
} ;
static struct regval_list ov5647_1080p30_10bpp [ ] = {
{ 0x0100 , 0x00 } ,
{ 0x0103 , 0x01 } ,
{ 0x3034 , 0x1a } ,
{ 0x3035 , 0x21 } ,
{ 0x3036 , 0x62 } ,
{ 0x303c , 0x11 } ,
{ 0x3106 , 0xf5 } ,
{ 0x3821 , 0x06 } ,
{ 0x3820 , 0x00 } ,
{ 0x3827 , 0xec } ,
{ 0x370c , 0x03 } ,
{ 0x3612 , 0x5b } ,
{ 0x3618 , 0x04 } ,
{ 0x5000 , 0x06 } ,
{ 0x5002 , 0x41 } ,
{ 0x5003 , 0x08 } ,
{ 0x5a00 , 0x08 } ,
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
{ 0x3016 , 0x08 } ,
{ 0x3017 , 0xe0 } ,
{ 0x3018 , 0x44 } ,
{ 0x301c , 0xf8 } ,
{ 0x301d , 0xf0 } ,
{ 0x3a18 , 0x00 } ,
{ 0x3a19 , 0xf8 } ,
{ 0x3c01 , 0x80 } ,
{ 0x3b07 , 0x0c } ,
{ 0x380c , 0x09 } ,
{ 0x380d , 0x70 } ,
{ 0x3814 , 0x11 } ,
{ 0x3815 , 0x11 } ,
{ 0x3708 , 0x64 } ,
{ 0x3709 , 0x12 } ,
{ 0x3808 , 0x07 } ,
{ 0x3809 , 0x80 } ,
{ 0x380a , 0x04 } ,
{ 0x380b , 0x38 } ,
{ 0x3800 , 0x01 } ,
{ 0x3801 , 0x5c } ,
{ 0x3802 , 0x01 } ,
{ 0x3803 , 0xb2 } ,
{ 0x3804 , 0x08 } ,
{ 0x3805 , 0xe3 } ,
{ 0x3806 , 0x05 } ,
{ 0x3807 , 0xf1 } ,
{ 0x3811 , 0x04 } ,
{ 0x3813 , 0x02 } ,
{ 0x3630 , 0x2e } ,
{ 0x3632 , 0xe2 } ,
{ 0x3633 , 0x23 } ,
{ 0x3634 , 0x44 } ,
{ 0x3636 , 0x06 } ,
{ 0x3620 , 0x64 } ,
{ 0x3621 , 0xe0 } ,
{ 0x3600 , 0x37 } ,
{ 0x3704 , 0xa0 } ,
{ 0x3703 , 0x5a } ,
{ 0x3715 , 0x78 } ,
{ 0x3717 , 0x01 } ,
{ 0x3731 , 0x02 } ,
{ 0x370b , 0x60 } ,
{ 0x3705 , 0x1a } ,
{ 0x3f05 , 0x02 } ,
{ 0x3f06 , 0x10 } ,
{ 0x3f01 , 0x0a } ,
{ 0x3a08 , 0x01 } ,
{ 0x3a09 , 0x4b } ,
{ 0x3a0a , 0x01 } ,
{ 0x3a0b , 0x13 } ,
{ 0x3a0d , 0x04 } ,
{ 0x3a0e , 0x03 } ,
{ 0x3a0f , 0x58 } ,
{ 0x3a10 , 0x50 } ,
{ 0x3a1b , 0x58 } ,
{ 0x3a1e , 0x50 } ,
{ 0x3a11 , 0x60 } ,
{ 0x3a1f , 0x28 } ,
{ 0x4001 , 0x02 } ,
{ 0x4004 , 0x04 } ,
{ 0x4000 , 0x09 } ,
{ 0x4837 , 0x19 } ,
{ 0x4800 , 0x34 } ,
{ 0x3503 , 0x03 } ,
{ 0x0100 , 0x01 } ,
} ;
static struct regval_list ov5647_2x2binned_10bpp [ ] = {
{ 0x0100 , 0x00 } ,
{ 0x0103 , 0x01 } ,
{ 0x3034 , 0x1a } ,
{ 0x3035 , 0x21 } ,
{ 0x3036 , 0x62 } ,
{ 0x303c , 0x11 } ,
{ 0x3106 , 0xf5 } ,
{ 0x3827 , 0xec } ,
{ 0x370c , 0x03 } ,
{ 0x3612 , 0x59 } ,
{ 0x3618 , 0x00 } ,
{ 0x5000 , 0x06 } ,
{ 0x5002 , 0x41 } ,
{ 0x5003 , 0x08 } ,
{ 0x5a00 , 0x08 } ,
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
{ 0x3016 , 0x08 } ,
{ 0x3017 , 0xe0 } ,
{ 0x3018 , 0x44 } ,
{ 0x301c , 0xf8 } ,
{ 0x301d , 0xf0 } ,
{ 0x3a18 , 0x00 } ,
{ 0x3a19 , 0xf8 } ,
{ 0x3c01 , 0x80 } ,
{ 0x3b07 , 0x0c } ,
{ 0x3800 , 0x00 } ,
{ 0x3801 , 0x00 } ,
{ 0x3802 , 0x00 } ,
{ 0x3803 , 0x00 } ,
{ 0x3804 , 0x0a } ,
{ 0x3805 , 0x3f } ,
{ 0x3806 , 0x07 } ,
{ 0x3807 , 0xa3 } ,
{ 0x3808 , 0x05 } ,
{ 0x3809 , 0x10 } ,
{ 0x380a , 0x03 } ,
{ 0x380b , 0xcc } ,
{ 0x380c , 0x07 } ,
{ 0x380d , 0x68 } ,
{ 0x3811 , 0x0c } ,
{ 0x3813 , 0x06 } ,
{ 0x3814 , 0x31 } ,
{ 0x3815 , 0x31 } ,
{ 0x3630 , 0x2e } ,
{ 0x3632 , 0xe2 } ,
{ 0x3633 , 0x23 } ,
{ 0x3634 , 0x44 } ,
{ 0x3636 , 0x06 } ,
{ 0x3620 , 0x64 } ,
{ 0x3621 , 0xe0 } ,
{ 0x3600 , 0x37 } ,
{ 0x3704 , 0xa0 } ,
{ 0x3703 , 0x5a } ,
{ 0x3715 , 0x78 } ,
{ 0x3717 , 0x01 } ,
{ 0x3731 , 0x02 } ,
{ 0x370b , 0x60 } ,
{ 0x3705 , 0x1a } ,
{ 0x3f05 , 0x02 } ,
{ 0x3f06 , 0x10 } ,
{ 0x3f01 , 0x0a } ,
{ 0x3a08 , 0x01 } ,
{ 0x3a09 , 0x28 } ,
{ 0x3a0a , 0x00 } ,
{ 0x3a0b , 0xf6 } ,
{ 0x3a0d , 0x08 } ,
{ 0x3a0e , 0x06 } ,
{ 0x3a0f , 0x58 } ,
{ 0x3a10 , 0x50 } ,
{ 0x3a1b , 0x58 } ,
{ 0x3a1e , 0x50 } ,
{ 0x3a11 , 0x60 } ,
{ 0x3a1f , 0x28 } ,
{ 0x4001 , 0x02 } ,
{ 0x4004 , 0x04 } ,
{ 0x4000 , 0x09 } ,
{ 0x4837 , 0x16 } ,
{ 0x4800 , 0x24 } ,
{ 0x3503 , 0x03 } ,
{ 0x3820 , 0x41 } ,
{ 0x3821 , 0x07 } ,
{ 0x350a , 0x00 } ,
{ 0x350b , 0x10 } ,
{ 0x3500 , 0x00 } ,
{ 0x3501 , 0x1a } ,
{ 0x3502 , 0xf0 } ,
{ 0x3212 , 0xa0 } ,
{ 0x0100 , 0x01 } ,
} ;
static struct regval_list ov5647_640x480_10bpp [ ] = {
{ 0x0100 , 0x00 } ,
{ 0x0103 , 0x01 } ,
{ 0x3035 , 0x11 } ,
{ 0x3036 , 0x46 } ,
{ 0x303c , 0x11 } ,
{ 0x3821 , 0x07 } ,
{ 0x3820 , 0x41 } ,
{ 0x370c , 0x03 } ,
{ 0x3612 , 0x59 } ,
{ 0x3618 , 0x00 } ,
{ 0x5000 , 0x06 } ,
{ 0x5003 , 0x08 } ,
{ 0x5a00 , 0x08 } ,
{ 0x3000 , 0xff } ,
{ 0x3001 , 0xff } ,
{ 0x3002 , 0xff } ,
{ 0x301d , 0xf0 } ,
{ 0x3a18 , 0x00 } ,
{ 0x3a19 , 0xf8 } ,
{ 0x3c01 , 0x80 } ,
{ 0x3b07 , 0x0c } ,
{ 0x380c , 0x07 } ,
{ 0x380d , 0x3c } ,
{ 0x3814 , 0x35 } ,
{ 0x3815 , 0x35 } ,
{ 0x3708 , 0x64 } ,
{ 0x3709 , 0x52 } ,
{ 0x3808 , 0x02 } ,
{ 0x3809 , 0x80 } ,
{ 0x380a , 0x01 } ,
{ 0x380b , 0xe0 } ,
{ 0x3800 , 0x00 } ,
{ 0x3801 , 0x10 } ,
{ 0x3802 , 0x00 } ,
{ 0x3803 , 0x00 } ,
{ 0x3804 , 0x0a } ,
{ 0x3805 , 0x2f } ,
{ 0x3806 , 0x07 } ,
{ 0x3807 , 0x9f } ,
{ 0x3630 , 0x2e } ,
{ 0x3632 , 0xe2 } ,
{ 0x3633 , 0x23 } ,
{ 0x3634 , 0x44 } ,
{ 0x3620 , 0x64 } ,
{ 0x3621 , 0xe0 } ,
{ 0x3600 , 0x37 } ,
{ 0x3704 , 0xa0 } ,
{ 0x3703 , 0x5a } ,
{ 0x3715 , 0x78 } ,
{ 0x3717 , 0x01 } ,
{ 0x3731 , 0x02 } ,
{ 0x370b , 0x60 } ,
{ 0x3705 , 0x1a } ,
{ 0x3f05 , 0x02 } ,
{ 0x3f06 , 0x10 } ,
{ 0x3f01 , 0x0a } ,
{ 0x3a08 , 0x01 } ,
{ 0x3a09 , 0x2e } ,
{ 0x3a0a , 0x00 } ,
{ 0x3a0b , 0xfb } ,
{ 0x3a0d , 0x02 } ,
{ 0x3a0e , 0x01 } ,
{ 0x3a0f , 0x58 } ,
{ 0x3a10 , 0x50 } ,
{ 0x3a1b , 0x58 } ,
{ 0x3a1e , 0x50 } ,
{ 0x3a11 , 0x60 } ,
{ 0x3a1f , 0x28 } ,
{ 0x4001 , 0x02 } ,
{ 0x4004 , 0x02 } ,
{ 0x4000 , 0x09 } ,
{ 0x3000 , 0x00 } ,
{ 0x3001 , 0x00 } ,
{ 0x3002 , 0x00 } ,
{ 0x3017 , 0xe0 } ,
{ 0x301c , 0xfc } ,
{ 0x3636 , 0x06 } ,
{ 0x3016 , 0x08 } ,
{ 0x3827 , 0xec } ,
{ 0x3018 , 0x44 } ,
{ 0x3035 , 0x21 } ,
{ 0x3106 , 0xf5 } ,
{ 0x3034 , 0x1a } ,
{ 0x301c , 0xf8 } ,
{ 0x4800 , 0x34 } ,
{ 0x3503 , 0x03 } ,
{ 0x0100 , 0x01 } ,
} ;
2020-11-19 17:32:35 +01:00
static const struct ov5647_mode ov5647_8bpp_modes [ ] = {
/* 8-bit VGA mode: Uncentred crop 2x2 binned 1296x972 image. */
2020-11-19 17:32:33 +01:00
{
. format = {
. code = MEDIA_BUS_FMT_SBGGR8_1X8 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. field = V4L2_FIELD_NONE ,
. width = 640 ,
. height = 480
} ,
2020-11-19 17:32:34 +01:00
. crop = {
. left = OV5647_PIXEL_ARRAY_LEFT ,
. top = OV5647_PIXEL_ARRAY_TOP ,
. width = 1280 ,
. height = 960 ,
} ,
2020-11-19 17:35:41 +01:00
. pixel_rate = 77291670 ,
2020-11-19 17:35:42 +01:00
. hts = 1896 ,
2020-11-19 17:35:43 +01:00
. vts = 0x3d8 ,
2020-11-19 17:32:35 +01:00
. reg_list = ov5647_640x480_8bpp ,
. num_regs = ARRAY_SIZE ( ov5647_640x480_8bpp )
2020-11-19 17:32:33 +01:00
} ,
} ;
2020-11-19 17:32:36 +01:00
static const struct ov5647_mode ov5647_10bpp_modes [ ] = {
/* 2592x1944 full resolution full FOV 10-bit mode. */
{
. format = {
. code = MEDIA_BUS_FMT_SBGGR10_1X10 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. field = V4L2_FIELD_NONE ,
. width = 2592 ,
. height = 1944
} ,
. crop = {
. left = OV5647_PIXEL_ARRAY_LEFT ,
. top = OV5647_PIXEL_ARRAY_TOP ,
. width = 2592 ,
. height = 1944
} ,
2020-11-19 17:35:41 +01:00
. pixel_rate = 87500000 ,
2020-11-19 17:35:42 +01:00
. hts = 2844 ,
2020-11-19 17:35:43 +01:00
. vts = 0x7b0 ,
2020-11-19 17:32:36 +01:00
. reg_list = ov5647_2592x1944_10bpp ,
. num_regs = ARRAY_SIZE ( ov5647_2592x1944_10bpp )
} ,
/* 1080p30 10-bit mode. Full resolution centre-cropped down to 1080p. */
{
. format = {
. code = MEDIA_BUS_FMT_SBGGR10_1X10 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. field = V4L2_FIELD_NONE ,
. width = 1920 ,
. height = 1080
} ,
. crop = {
. left = 348 + OV5647_PIXEL_ARRAY_LEFT ,
. top = 434 + OV5647_PIXEL_ARRAY_TOP ,
. width = 1928 ,
. height = 1080 ,
} ,
2020-11-19 17:35:41 +01:00
. pixel_rate = 81666700 ,
2020-11-19 17:35:42 +01:00
. hts = 2416 ,
2020-11-19 17:35:43 +01:00
. vts = 0x450 ,
2020-11-19 17:32:36 +01:00
. reg_list = ov5647_1080p30_10bpp ,
. num_regs = ARRAY_SIZE ( ov5647_1080p30_10bpp )
} ,
/* 2x2 binned full FOV 10-bit mode. */
{
. format = {
. code = MEDIA_BUS_FMT_SBGGR10_1X10 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. field = V4L2_FIELD_NONE ,
. width = 1296 ,
. height = 972
} ,
. crop = {
. left = OV5647_PIXEL_ARRAY_LEFT ,
. top = OV5647_PIXEL_ARRAY_TOP ,
. width = 2592 ,
. height = 1944 ,
} ,
2020-11-19 17:35:41 +01:00
. pixel_rate = 81666700 ,
2020-11-19 17:35:42 +01:00
. hts = 1896 ,
2020-11-19 17:35:43 +01:00
. vts = 0x59b ,
2020-11-19 17:32:36 +01:00
. reg_list = ov5647_2x2binned_10bpp ,
. num_regs = ARRAY_SIZE ( ov5647_2x2binned_10bpp )
} ,
/* 10-bit VGA full FOV 60fps. 2x2 binned and subsampled down to VGA. */
{
. format = {
. code = MEDIA_BUS_FMT_SBGGR10_1X10 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. field = V4L2_FIELD_NONE ,
. width = 640 ,
. height = 480
} ,
. crop = {
. left = 16 + OV5647_PIXEL_ARRAY_LEFT ,
. top = OV5647_PIXEL_ARRAY_TOP ,
. width = 2560 ,
. height = 1920 ,
} ,
2020-11-19 17:35:41 +01:00
. pixel_rate = 55000000 ,
2020-11-19 17:35:42 +01:00
. hts = 1852 ,
2020-11-19 17:35:43 +01:00
. vts = 0x1f8 ,
2020-11-19 17:32:36 +01:00
. reg_list = ov5647_640x480_10bpp ,
. num_regs = ARRAY_SIZE ( ov5647_640x480_10bpp )
} ,
} ;
2020-11-19 17:32:33 +01:00
static const struct ov5647_format_list ov5647_formats [ ] = {
{
. mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8 ,
2020-11-19 17:32:35 +01:00
. modes = ov5647_8bpp_modes ,
. num_modes = ARRAY_SIZE ( ov5647_8bpp_modes ) ,
2020-11-19 17:32:33 +01:00
} ,
2020-11-19 17:32:36 +01:00
{
. mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10 ,
. modes = ov5647_10bpp_modes ,
. num_modes = ARRAY_SIZE ( ov5647_10bpp_modes ) ,
} ,
2020-11-19 17:32:33 +01:00
} ;
# define OV5647_NUM_FORMATS (ARRAY_SIZE(ov5647_formats))
2020-11-19 17:32:37 +01:00
/* Default sensor mode is 2x2 binned 640x480 SBGGR10_1X10. */
# define OV5647_DEFAULT_MODE (&ov5647_formats[1].modes[3])
# define OV5647_DEFAULT_FORMAT (ov5647_formats[1].modes[3].format)
2020-11-19 17:32:33 +01:00
2020-11-19 17:35:43 +01:00
static int ov5647_write16 ( struct v4l2_subdev * sd , u16 reg , u16 val )
{
unsigned char data [ 4 ] = { reg > > 8 , reg & 0xff , val > > 8 , val & 0xff } ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
int ret ;
ret = i2c_master_send ( client , data , 4 ) ;
if ( ret < 0 ) {
dev_dbg ( & client - > dev , " %s: i2c write error, reg: %x \n " ,
__func__ , reg ) ;
return ret ;
}
return 0 ;
}
2017-03-22 09:30:27 -03:00
static int ov5647_write ( struct v4l2_subdev * sd , u16 reg , u8 val )
{
unsigned char data [ 3 ] = { reg > > 8 , reg & 0xff , val } ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:19:32 +01:00
int ret ;
2017-03-22 09:30:27 -03:00
ret = i2c_master_send ( client , data , 3 ) ;
2020-11-19 17:19:34 +01:00
if ( ret < 0 ) {
2017-03-22 09:30:27 -03:00
dev_dbg ( & client - > dev , " %s: i2c write error, reg: %x \n " ,
__func__ , reg ) ;
2020-11-19 17:19:34 +01:00
return ret ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:19:34 +01:00
return 0 ;
2017-03-22 09:30:27 -03:00
}
static int ov5647_read ( struct v4l2_subdev * sd , u16 reg , u8 * val )
{
unsigned char data_w [ 2 ] = { reg > > 8 , reg & 0xff } ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:19:32 +01:00
int ret ;
2017-03-22 09:30:27 -03:00
ret = i2c_master_send ( client , data_w , 2 ) ;
if ( ret < 0 ) {
dev_dbg ( & client - > dev , " %s: i2c write error, reg: %x \n " ,
__func__ , reg ) ;
return ret ;
}
ret = i2c_master_recv ( client , val , 1 ) ;
2020-11-19 17:19:34 +01:00
if ( ret < 0 ) {
2017-03-22 09:30:27 -03:00
dev_dbg ( & client - > dev , " %s: i2c read error, reg: %x \n " ,
__func__ , reg ) ;
2020-11-19 17:19:34 +01:00
return ret ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:19:34 +01:00
return 0 ;
2017-03-22 09:30:27 -03:00
}
static int ov5647_write_array ( struct v4l2_subdev * sd ,
2020-11-19 17:32:33 +01:00
const struct regval_list * regs , int array_size )
2017-03-22 09:30:27 -03:00
{
int i , ret ;
for ( i = 0 ; i < array_size ; i + + ) {
ret = ov5647_write ( sd , regs [ i ] . addr , regs [ i ] . data ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
static int ov5647_set_virtual_channel ( struct v4l2_subdev * sd , int channel )
{
u8 channel_id ;
int ret ;
2017-10-01 12:22:38 +02:00
ret = ov5647_read ( sd , OV5647_REG_MIPI_CTRL14 , & channel_id ) ;
2017-03-22 09:30:27 -03:00
if ( ret < 0 )
return ret ;
channel_id & = ~ ( 3 < < 6 ) ;
2020-11-19 17:19:32 +01:00
return ov5647_write ( sd , OV5647_REG_MIPI_CTRL14 ,
channel_id | ( channel < < 6 ) ) ;
2017-03-22 09:30:27 -03:00
}
2020-11-19 17:19:35 +01:00
static int ov5647_set_mode ( struct v4l2_subdev * sd )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:32:33 +01:00
struct ov5647 * sensor = to_sensor ( sd ) ;
2020-11-19 17:19:35 +01:00
u8 resetval , rdval ;
int ret ;
ret = ov5647_read ( sd , OV5647_SW_STANDBY , & rdval ) ;
if ( ret < 0 )
return ret ;
2020-11-19 17:32:33 +01:00
ret = ov5647_write_array ( sd , sensor - > mode - > reg_list ,
sensor - > mode - > num_regs ) ;
2020-11-19 17:19:35 +01:00
if ( ret < 0 ) {
dev_err ( & client - > dev , " write sensor default regs error \n " ) ;
return ret ;
}
ret = ov5647_set_virtual_channel ( sd , 0 ) ;
if ( ret < 0 )
return ret ;
ret = ov5647_read ( sd , OV5647_SW_STANDBY , & resetval ) ;
if ( ret < 0 )
return ret ;
if ( ! ( resetval & 0x01 ) ) {
dev_err ( & client - > dev , " Device was in SW standby " ) ;
ret = ov5647_write ( sd , OV5647_SW_STANDBY , 0x01 ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2017-03-22 09:30:27 -03:00
static int ov5647_stream_on ( struct v4l2_subdev * sd )
{
2020-11-19 17:19:35 +01:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:32:32 +01:00
struct ov5647 * sensor = to_sensor ( sd ) ;
2020-11-19 17:19:29 +01:00
u8 val = MIPI_CTRL00_BUS_IDLE ;
2017-03-22 09:30:27 -03:00
int ret ;
2020-11-19 17:19:35 +01:00
ret = ov5647_set_mode ( sd ) ;
if ( ret ) {
dev_err ( & client - > dev , " Failed to program sensor mode: %d \n " , ret ) ;
return ret ;
}
2020-11-19 17:32:31 +01:00
/* Apply customized values from user when stream starts. */
ret = __v4l2_ctrl_handler_setup ( sd - > ctrl_handler ) ;
if ( ret )
return ret ;
2020-11-19 17:32:32 +01:00
if ( sensor - > clock_ncont )
2020-11-19 17:19:29 +01:00
val | = MIPI_CTRL00_CLOCK_LANE_GATE |
MIPI_CTRL00_LINE_SYNC_ENABLE ;
ret = ov5647_write ( sd , OV5647_REG_MIPI_CTRL00 , val ) ;
2017-10-01 12:22:37 +02:00
if ( ret < 0 )
return ret ;
2017-10-01 12:22:38 +02:00
ret = ov5647_write ( sd , OV5647_REG_FRAME_OFF_NUMBER , 0x00 ) ;
2017-03-22 09:30:27 -03:00
if ( ret < 0 )
return ret ;
2017-10-01 12:22:38 +02:00
return ov5647_write ( sd , OV5640_REG_PAD_OUT , 0x00 ) ;
2017-03-22 09:30:27 -03:00
}
static int ov5647_stream_off ( struct v4l2_subdev * sd )
{
int ret ;
2020-11-19 17:19:32 +01:00
ret = ov5647_write ( sd , OV5647_REG_MIPI_CTRL00 ,
MIPI_CTRL00_CLOCK_LANE_GATE | MIPI_CTRL00_BUS_IDLE |
MIPI_CTRL00_CLOCK_LANE_DISABLE ) ;
2017-10-01 12:22:37 +02:00
if ( ret < 0 )
return ret ;
2017-10-01 12:22:38 +02:00
ret = ov5647_write ( sd , OV5647_REG_FRAME_OFF_NUMBER , 0x0f ) ;
2017-03-22 09:30:27 -03:00
if ( ret < 0 )
return ret ;
2017-10-01 12:22:38 +02:00
return ov5647_write ( sd , OV5640_REG_PAD_OUT , 0x01 ) ;
2017-03-22 09:30:27 -03:00
}
2020-11-19 17:35:45 +01:00
static int ov5647_power_on ( struct device * dev )
2017-03-22 09:30:27 -03:00
{
2020-11-19 17:35:45 +01:00
struct ov5647 * sensor = dev_get_drvdata ( dev ) ;
2017-03-22 09:30:27 -03:00
int ret ;
2020-11-19 17:35:45 +01:00
dev_dbg ( dev , " OV5647 power on \n " ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
if ( sensor - > pwdn ) {
gpiod_set_value_cansleep ( sensor - > pwdn , 0 ) ;
msleep ( PWDN_ACTIVE_DELAY_MS ) ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
ret = clk_prepare_enable ( sensor - > xclk ) ;
if ( ret < 0 ) {
dev_err ( dev , " clk prepare enable failed \n " ) ;
goto error_pwdn ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
ret = ov5647_write_array ( & sensor - > sd , sensor_oe_enable_regs ,
ARRAY_SIZE ( sensor_oe_enable_regs ) ) ;
if ( ret < 0 ) {
dev_err ( dev , " write sensor_oe_enable_regs error \n " ) ;
goto error_clk_disable ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
/* Stream off to coax lanes into LP-11 state. */
ret = ov5647_stream_off ( & sensor - > sd ) ;
if ( ret < 0 ) {
dev_err ( dev , " camera not available, check power \n " ) ;
goto error_clk_disable ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
return 0 ;
2020-11-19 17:19:28 +01:00
2020-11-19 17:35:45 +01:00
error_clk_disable :
clk_disable_unprepare ( sensor - > xclk ) ;
error_pwdn :
gpiod_set_value_cansleep ( sensor - > pwdn , 1 ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
return ret ;
}
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
static int ov5647_power_off ( struct device * dev )
{
struct ov5647 * sensor = dev_get_drvdata ( dev ) ;
u8 rdval ;
int ret ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
dev_dbg ( dev , " OV5647 power off \n " ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
ret = ov5647_write_array ( & sensor - > sd , sensor_oe_disable_regs ,
ARRAY_SIZE ( sensor_oe_disable_regs ) ) ;
if ( ret < 0 )
dev_dbg ( dev , " disable oe failed \n " ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
/* Enter software standby */
ret = ov5647_read ( & sensor - > sd , OV5647_SW_STANDBY , & rdval ) ;
if ( ret < 0 )
dev_dbg ( dev , " software standby failed \n " ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
rdval & = ~ 0x01 ;
ret = ov5647_write ( & sensor - > sd , OV5647_SW_STANDBY , rdval ) ;
if ( ret < 0 )
dev_dbg ( dev , " software standby failed \n " ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
clk_disable_unprepare ( sensor - > xclk ) ;
gpiod_set_value_cansleep ( sensor - > pwdn , 1 ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
return 0 ;
2017-03-22 09:30:27 -03:00
}
# ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov5647_sensor_get_register ( struct v4l2_subdev * sd ,
2020-11-19 17:19:32 +01:00
struct v4l2_dbg_register * reg )
2017-03-22 09:30:27 -03:00
{
int ret ;
2020-11-19 17:19:32 +01:00
u8 val ;
2017-03-22 09:30:27 -03:00
ret = ov5647_read ( sd , reg - > reg & 0xff , & val ) ;
if ( ret < 0 )
return ret ;
reg - > val = val ;
reg - > size = 1 ;
return 0 ;
}
static int ov5647_sensor_set_register ( struct v4l2_subdev * sd ,
2020-11-19 17:19:32 +01:00
const struct v4l2_dbg_register * reg )
2017-03-22 09:30:27 -03:00
{
return ov5647_write ( sd , reg - > reg & 0xff , reg - > val & 0xff ) ;
}
# endif
2020-11-19 17:19:32 +01:00
/* Subdev core operations registration */
2017-03-22 09:30:27 -03:00
static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
# ifdef CONFIG_VIDEO_ADV_DEBUG
. g_register = ov5647_sensor_get_register ,
. s_register = ov5647_sensor_set_register ,
# endif
} ;
2020-11-19 17:32:34 +01:00
static const struct v4l2_rect *
__ov5647_get_pad_crop ( struct ov5647 * ov5647 , struct v4l2_subdev_pad_config * cfg ,
unsigned int pad , enum v4l2_subdev_format_whence which )
{
switch ( which ) {
case V4L2_SUBDEV_FORMAT_TRY :
return v4l2_subdev_get_try_crop ( & ov5647 - > sd , cfg , pad ) ;
case V4L2_SUBDEV_FORMAT_ACTIVE :
return & ov5647 - > mode - > crop ;
}
return NULL ;
}
2017-03-22 09:30:27 -03:00
static int ov5647_s_stream ( struct v4l2_subdev * sd , int enable )
{
2020-11-19 17:35:46 +01:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:32:32 +01:00
struct ov5647 * sensor = to_sensor ( sd ) ;
2020-11-19 17:32:30 +01:00
int ret ;
mutex_lock ( & sensor - > lock ) ;
2020-11-19 17:35:46 +01:00
if ( sensor - > streaming = = enable ) {
mutex_unlock ( & sensor - > lock ) ;
return 0 ;
}
if ( enable ) {
ret = pm_runtime_get_sync ( & client - > dev ) ;
if ( ret < 0 )
goto error_unlock ;
2020-11-19 17:32:30 +01:00
ret = ov5647_stream_on ( sd ) ;
2020-11-19 17:35:46 +01:00
if ( ret < 0 ) {
dev_err ( & client - > dev , " stream start failed: %d \n " , ret ) ;
goto error_unlock ;
}
} else {
2020-11-19 17:32:30 +01:00
ret = ov5647_stream_off ( sd ) ;
2020-11-19 17:35:46 +01:00
if ( ret < 0 ) {
dev_err ( & client - > dev , " stream stop failed: %d \n " , ret ) ;
goto error_unlock ;
}
pm_runtime_put ( & client - > dev ) ;
}
sensor - > streaming = enable ;
mutex_unlock ( & sensor - > lock ) ;
return 0 ;
error_unlock :
pm_runtime_put ( & client - > dev ) ;
2020-11-19 17:32:30 +01:00
mutex_unlock ( & sensor - > lock ) ;
return ret ;
2017-03-22 09:30:27 -03:00
}
static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
. s_stream = ov5647_s_stream ,
} ;
static int ov5647_enum_mbus_code ( struct v4l2_subdev * sd ,
2020-11-19 17:19:32 +01:00
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_mbus_code_enum * code )
2017-03-22 09:30:27 -03:00
{
2020-11-19 17:32:33 +01:00
if ( code - > index > = OV5647_NUM_FORMATS )
2017-03-22 09:30:27 -03:00
return - EINVAL ;
2020-11-19 17:32:33 +01:00
code - > code = ov5647_formats [ code - > index ] . mbus_code ;
2017-03-22 09:30:27 -03:00
return 0 ;
}
2020-11-19 17:32:29 +01:00
static int ov5647_enum_frame_size ( struct v4l2_subdev * sd ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_frame_size_enum * fse )
{
2020-11-19 17:32:33 +01:00
const struct v4l2_mbus_framefmt * fmt ;
unsigned int i = 0 ;
for ( ; i < OV5647_NUM_FORMATS ; + + i ) {
if ( ov5647_formats [ i ] . mbus_code = = fse - > code )
break ;
}
if ( i = = OV5647_NUM_FORMATS )
2020-11-19 17:32:29 +01:00
return - EINVAL ;
2020-11-19 17:32:33 +01:00
if ( fse - > index > = ov5647_formats [ i ] . num_modes )
2020-11-19 17:32:29 +01:00
return - EINVAL ;
2020-11-19 17:32:33 +01:00
fmt = & ov5647_formats [ i ] . modes [ fse - > index ] . format ;
fse - > min_width = fmt - > width ;
fse - > max_width = fmt - > width ;
fse - > min_height = fmt - > height ;
fse - > max_height = fmt - > height ;
2020-11-19 17:32:29 +01:00
return 0 ;
}
2020-11-19 17:32:38 +01:00
static int ov5647_get_pad_fmt ( struct v4l2_subdev * sd ,
2020-11-19 17:19:30 +01:00
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_format * format )
{
struct v4l2_mbus_framefmt * fmt = & format - > format ;
2020-11-19 17:32:38 +01:00
const struct v4l2_mbus_framefmt * sensor_format ;
struct ov5647 * sensor = to_sensor ( sd ) ;
mutex_lock ( & sensor - > lock ) ;
switch ( format - > which ) {
case V4L2_SUBDEV_FORMAT_TRY :
sensor_format = v4l2_subdev_get_try_format ( sd , cfg , format - > pad ) ;
break ;
default :
sensor_format = & sensor - > mode - > format ;
break ;
}
* fmt = * sensor_format ;
mutex_unlock ( & sensor - > lock ) ;
2020-11-19 17:19:30 +01:00
2020-11-19 17:32:38 +01:00
return 0 ;
}
static int ov5647_set_pad_fmt ( struct v4l2_subdev * sd ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_format * format )
{
struct v4l2_mbus_framefmt * fmt = & format - > format ;
const struct ov5647_mode * ov5647_mode_list ;
struct ov5647 * sensor = to_sensor ( sd ) ;
2020-11-19 17:35:44 +01:00
2020-11-19 17:32:38 +01:00
const struct ov5647_mode * mode ;
unsigned int num_modes ;
unsigned int i ;
for ( i = 0 ; i < OV5647_NUM_FORMATS ; + + i ) {
if ( ov5647_formats [ i ] . mbus_code ! = fmt - > code )
continue ;
ov5647_mode_list = ov5647_formats [ i ] . modes ;
num_modes = ov5647_formats [ i ] . num_modes ;
break ;
}
/*
* Default mbus code MEDIA_BUS_FMT_SBGGR10_1X10 if the requested one is
* not supported .
*/
if ( i = = OV5647_NUM_FORMATS ) {
ov5647_mode_list = ov5647_10bpp_modes ;
num_modes = ARRAY_SIZE ( ov5647_10bpp_modes ) ;
}
mode = v4l2_find_nearest_size ( ov5647_mode_list , num_modes ,
format . width , format . height ,
fmt - > width , fmt - > height ) ;
/* Update the sensor mode and apply at it at streamon time. */
mutex_lock ( & sensor - > lock ) ;
2020-11-19 17:35:41 +01:00
if ( format - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
2020-11-19 17:32:38 +01:00
* v4l2_subdev_get_try_format ( sd , cfg , format - > pad ) = mode - > format ;
2020-11-19 17:35:41 +01:00
} else {
2020-11-19 17:35:44 +01:00
int exposure_max , exposure_def ;
2020-11-19 17:35:43 +01:00
int hblank , vblank ;
2020-11-19 17:35:42 +01:00
2020-11-19 17:32:38 +01:00
sensor - > mode = mode ;
2020-11-19 17:35:41 +01:00
__v4l2_ctrl_modify_range ( sensor - > pixel_rate , mode - > pixel_rate ,
mode - > pixel_rate , 1 , mode - > pixel_rate ) ;
2020-11-19 17:35:42 +01:00
hblank = mode - > hts - mode - > format . width ;
__v4l2_ctrl_modify_range ( sensor - > hblank , hblank , hblank , 1 ,
hblank ) ;
2020-11-19 17:35:43 +01:00
vblank = mode - > vts - mode - > format . height ;
__v4l2_ctrl_modify_range ( sensor - > vblank , OV5647_VBLANK_MIN ,
OV5647_VTS_MAX - mode - > format . height ,
1 , vblank ) ;
__v4l2_ctrl_s_ctrl ( sensor - > vblank , vblank ) ;
2020-11-19 17:35:44 +01:00
exposure_max = mode - > vts - 4 ;
exposure_def = min ( exposure_max , OV5647_EXPOSURE_DEFAULT ) ;
__v4l2_ctrl_modify_range ( sensor - > exposure ,
sensor - > exposure - > minimum ,
exposure_max , sensor - > exposure - > step ,
exposure_def ) ;
2020-11-19 17:35:41 +01:00
}
2020-11-19 17:32:38 +01:00
* fmt = mode - > format ;
mutex_unlock ( & sensor - > lock ) ;
2020-11-19 17:19:30 +01:00
return 0 ;
}
2020-11-19 17:32:34 +01:00
static int ov5647_get_selection ( struct v4l2_subdev * sd ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_selection * sel )
{
switch ( sel - > target ) {
case V4L2_SEL_TGT_CROP : {
struct ov5647 * sensor = to_sensor ( sd ) ;
mutex_lock ( & sensor - > lock ) ;
sel - > r = * __ov5647_get_pad_crop ( sensor , cfg , sel - > pad ,
sel - > which ) ;
mutex_unlock ( & sensor - > lock ) ;
return 0 ;
}
case V4L2_SEL_TGT_NATIVE_SIZE :
sel - > r . top = 0 ;
sel - > r . left = 0 ;
sel - > r . width = OV5647_NATIVE_WIDTH ;
sel - > r . height = OV5647_NATIVE_HEIGHT ;
return 0 ;
case V4L2_SEL_TGT_CROP_DEFAULT :
case V4L2_SEL_TGT_CROP_BOUNDS :
sel - > r . top = OV5647_PIXEL_ARRAY_TOP ;
sel - > r . left = OV5647_PIXEL_ARRAY_LEFT ;
sel - > r . width = OV5647_PIXEL_ARRAY_WIDTH ;
sel - > r . height = OV5647_PIXEL_ARRAY_HEIGHT ;
return 0 ;
}
return - EINVAL ;
}
2017-03-22 09:30:27 -03:00
static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
2020-11-19 17:32:29 +01:00
. enum_mbus_code = ov5647_enum_mbus_code ,
. enum_frame_size = ov5647_enum_frame_size ,
2020-11-19 17:32:38 +01:00
. set_fmt = ov5647_set_pad_fmt ,
. get_fmt = ov5647_get_pad_fmt ,
2020-11-19 17:32:34 +01:00
. get_selection = ov5647_get_selection ,
2017-03-22 09:30:27 -03:00
} ;
static const struct v4l2_subdev_ops ov5647_subdev_ops = {
. core = & ov5647_subdev_core_ops ,
. video = & ov5647_subdev_video_ops ,
. pad = & ov5647_subdev_pad_ops ,
} ;
static int ov5647_detect ( struct v4l2_subdev * sd )
{
2020-11-19 17:19:32 +01:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2017-03-22 09:30:27 -03:00
u8 read ;
int ret ;
ret = ov5647_write ( sd , OV5647_SW_RESET , 0x01 ) ;
if ( ret < 0 )
return ret ;
ret = ov5647_read ( sd , OV5647_REG_CHIPID_H , & read ) ;
if ( ret < 0 )
return ret ;
if ( read ! = 0x56 ) {
dev_err ( & client - > dev , " ID High expected 0x56 got %x " , read ) ;
return - ENODEV ;
}
ret = ov5647_read ( sd , OV5647_REG_CHIPID_L , & read ) ;
if ( ret < 0 )
return ret ;
if ( read ! = 0x47 ) {
dev_err ( & client - > dev , " ID Low expected 0x47 got %x " , read ) ;
return - ENODEV ;
}
return ov5647_write ( sd , OV5647_SW_RESET , 0x00 ) ;
}
static int ov5647_open ( struct v4l2_subdev * sd , struct v4l2_subdev_fh * fh )
{
struct v4l2_mbus_framefmt * format =
v4l2_subdev_get_try_format ( sd , fh - > pad , 0 ) ;
2020-11-19 17:19:32 +01:00
struct v4l2_rect * crop = v4l2_subdev_get_try_crop ( sd , fh - > pad , 0 ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:32:34 +01:00
crop - > left = OV5647_PIXEL_ARRAY_LEFT ;
crop - > top = OV5647_PIXEL_ARRAY_TOP ;
crop - > width = OV5647_PIXEL_ARRAY_WIDTH ;
crop - > height = OV5647_PIXEL_ARRAY_HEIGHT ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:32:33 +01:00
* format = OV5647_DEFAULT_FORMAT ;
2017-03-22 09:30:27 -03:00
return 0 ;
}
static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
. open = ov5647_open ,
} ;
2020-11-19 17:32:31 +01:00
static int ov5647_s_auto_white_balance ( struct v4l2_subdev * sd , u32 val )
{
return ov5647_write ( sd , OV5647_REG_AWB , val ? 1 : 0 ) ;
}
static int ov5647_s_autogain ( struct v4l2_subdev * sd , u32 val )
{
int ret ;
u8 reg ;
/* Non-zero turns on AGC by clearing bit 1.*/
ret = ov5647_read ( sd , OV5647_REG_AEC_AGC , & reg ) ;
if ( ret )
return ret ;
return ov5647_write ( sd , OV5647_REG_AEC_AGC , val ? reg & ~ BIT ( 1 )
: reg | BIT ( 1 ) ) ;
}
static int ov5647_s_exposure_auto ( struct v4l2_subdev * sd , u32 val )
{
int ret ;
u8 reg ;
/*
* Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
* clearing bit 0.
*/
ret = ov5647_read ( sd , OV5647_REG_AEC_AGC , & reg ) ;
if ( ret )
return ret ;
return ov5647_write ( sd , OV5647_REG_AEC_AGC ,
val = = V4L2_EXPOSURE_MANUAL ? reg | BIT ( 0 )
: reg & ~ BIT ( 0 ) ) ;
}
static int ov5647_s_analogue_gain ( struct v4l2_subdev * sd , u32 val )
{
int ret ;
/* 10 bits of gain, 2 in the high register. */
ret = ov5647_write ( sd , OV5647_REG_GAIN_HI , ( val > > 8 ) & 3 ) ;
if ( ret )
return ret ;
return ov5647_write ( sd , OV5647_REG_GAIN_LO , val & 0xff ) ;
}
static int ov5647_s_exposure ( struct v4l2_subdev * sd , u32 val )
{
int ret ;
/*
* Sensor has 20 bits , but the bottom 4 bits are fractions of a line
* which we leave as zero ( and don ' t receive in " val " ) .
*/
ret = ov5647_write ( sd , OV5647_REG_EXP_HI , ( val > > 12 ) & 0xf ) ;
if ( ret )
return ret ;
ret = ov5647_write ( sd , OV5647_REG_EXP_MID , ( val > > 4 ) & 0xff ) ;
if ( ret )
return ret ;
return ov5647_write ( sd , OV5647_REG_EXP_LO , ( val & 0xf ) < < 4 ) ;
}
static int ov5647_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct ov5647 * sensor = container_of ( ctrl - > handler ,
struct ov5647 , ctrls ) ;
struct v4l2_subdev * sd = & sensor - > sd ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2020-11-19 17:35:47 +01:00
int ret = 0 ;
2020-11-19 17:32:31 +01:00
/* v4l2_ctrl_lock() locks our own mutex */
2020-11-19 17:35:44 +01:00
if ( ctrl - > id = = V4L2_CID_VBLANK ) {
int exposure_max , exposure_def ;
/* Update max exposure while meeting expected vblanking */
exposure_max = sensor - > mode - > format . height + ctrl - > val - 4 ;
exposure_def = min ( exposure_max , OV5647_EXPOSURE_DEFAULT ) ;
__v4l2_ctrl_modify_range ( sensor - > exposure ,
sensor - > exposure - > minimum ,
exposure_max , sensor - > exposure - > step ,
exposure_def ) ;
}
2020-11-19 17:32:31 +01:00
/*
2020-11-19 17:35:47 +01:00
* If the device is not powered up do not apply any controls
* to H / W at this time . Instead the controls will be restored
* at s_stream ( 1 ) time .
2020-11-19 17:32:31 +01:00
*/
2020-11-19 17:35:47 +01:00
if ( pm_runtime_get_if_in_use ( & client - > dev ) = = 0 )
2020-11-19 17:32:31 +01:00
return 0 ;
switch ( ctrl - > id ) {
case V4L2_CID_AUTO_WHITE_BALANCE :
2020-11-19 17:35:47 +01:00
ret = ov5647_s_auto_white_balance ( sd , ctrl - > val ) ;
break ;
2020-11-19 17:32:31 +01:00
case V4L2_CID_AUTOGAIN :
2020-11-19 17:35:47 +01:00
ret = ov5647_s_autogain ( sd , ctrl - > val ) ;
break ;
2020-11-19 17:32:31 +01:00
case V4L2_CID_EXPOSURE_AUTO :
2020-11-19 17:35:47 +01:00
ret = ov5647_s_exposure_auto ( sd , ctrl - > val ) ;
break ;
2020-11-19 17:32:31 +01:00
case V4L2_CID_ANALOGUE_GAIN :
2020-11-19 17:35:47 +01:00
ret = ov5647_s_analogue_gain ( sd , ctrl - > val ) ;
break ;
2020-11-19 17:32:31 +01:00
case V4L2_CID_EXPOSURE :
2020-11-19 17:35:47 +01:00
ret = ov5647_s_exposure ( sd , ctrl - > val ) ;
break ;
case V4L2_CID_VBLANK :
ret = ov5647_write16 ( sd , OV5647_REG_VTS_HI ,
sensor - > mode - > format . height + ctrl - > val ) ;
break ;
/* Read-only, but we adjust it based on mode. */
2020-11-19 17:35:41 +01:00
case V4L2_CID_PIXEL_RATE :
2020-11-19 17:35:42 +01:00
case V4L2_CID_HBLANK :
/* Read-only, but we adjust it based on mode. */
2020-11-19 17:35:47 +01:00
break ;
2020-11-19 17:32:31 +01:00
default :
dev_info ( & client - > dev ,
" Control (id:0x%x, val:0x%x) not supported \n " ,
ctrl - > id , ctrl - > val ) ;
return - EINVAL ;
}
2020-11-19 17:35:47 +01:00
pm_runtime_put ( & client - > dev ) ;
return ret ;
2020-11-19 17:32:31 +01:00
}
static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
. s_ctrl = ov5647_s_ctrl ,
} ;
static int ov5647_init_controls ( struct ov5647 * sensor )
{
struct i2c_client * client = v4l2_get_subdevdata ( & sensor - > sd ) ;
2020-11-19 17:35:44 +01:00
int hblank , exposure_max , exposure_def ;
2020-11-19 17:32:31 +01:00
2020-11-19 17:35:43 +01:00
v4l2_ctrl_handler_init ( & sensor - > ctrls , 8 ) ;
2020-11-19 17:32:31 +01:00
v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_AUTOGAIN , 0 , 1 , 1 , 0 ) ;
v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_AUTO_WHITE_BALANCE , 0 , 1 , 1 , 0 ) ;
v4l2_ctrl_new_std_menu ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_EXPOSURE_AUTO , V4L2_EXPOSURE_MANUAL ,
0 , V4L2_EXPOSURE_MANUAL ) ;
2020-11-19 17:35:44 +01:00
exposure_max = sensor - > mode - > vts - 4 ;
exposure_def = min ( exposure_max , OV5647_EXPOSURE_DEFAULT ) ;
sensor - > exposure = v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_EXPOSURE ,
OV5647_EXPOSURE_MIN ,
exposure_max , OV5647_EXPOSURE_STEP ,
exposure_def ) ;
2020-11-19 17:32:31 +01:00
/* min: 16 = 1.0x; max (10 bits); default: 32 = 2.0x. */
v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_ANALOGUE_GAIN , 16 , 1023 , 1 , 32 ) ;
2020-11-19 17:35:41 +01:00
/* By default, PIXEL_RATE is read only, but it does change per mode */
sensor - > pixel_rate = v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_PIXEL_RATE ,
sensor - > mode - > pixel_rate ,
sensor - > mode - > pixel_rate , 1 ,
sensor - > mode - > pixel_rate ) ;
2020-11-19 17:35:42 +01:00
/* By default, HBLANK is read only, but it does change per mode. */
hblank = sensor - > mode - > hts - sensor - > mode - > format . width ;
sensor - > hblank = v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_HBLANK , hblank , hblank , 1 ,
hblank ) ;
2020-11-19 17:35:43 +01:00
sensor - > vblank = v4l2_ctrl_new_std ( & sensor - > ctrls , & ov5647_ctrl_ops ,
V4L2_CID_VBLANK , OV5647_VBLANK_MIN ,
OV5647_VTS_MAX -
sensor - > mode - > format . height , 1 ,
sensor - > mode - > vts -
sensor - > mode - > format . height ) ;
2020-11-19 17:35:41 +01:00
if ( sensor - > ctrls . error )
goto handler_free ;
2020-11-19 17:32:31 +01:00
2020-11-19 17:35:41 +01:00
sensor - > pixel_rate - > flags | = V4L2_CTRL_FLAG_READ_ONLY ;
2020-11-19 17:35:42 +01:00
sensor - > hblank - > flags | = V4L2_CTRL_FLAG_READ_ONLY ;
2020-11-19 17:32:31 +01:00
sensor - > sd . ctrl_handler = & sensor - > ctrls ;
return 0 ;
2020-11-19 17:35:41 +01:00
handler_free :
dev_err ( & client - > dev , " %s Controls initialization failed (%d) \n " ,
__func__ , sensor - > ctrls . error ) ;
v4l2_ctrl_handler_free ( & sensor - > ctrls ) ;
return sensor - > ctrls . error ;
2020-11-19 17:32:31 +01:00
}
2020-11-19 17:19:29 +01:00
static int ov5647_parse_dt ( struct ov5647 * sensor , struct device_node * np )
2017-03-22 09:30:27 -03:00
{
2020-11-19 17:19:29 +01:00
struct v4l2_fwnode_endpoint bus_cfg = {
. bus_type = V4L2_MBUS_CSI2_DPHY ,
} ;
2017-03-22 09:30:27 -03:00
struct device_node * ep ;
int ret ;
ep = of_graph_get_next_endpoint ( np , NULL ) ;
if ( ! ep )
return - EINVAL ;
2016-08-26 20:17:25 -03:00
ret = v4l2_fwnode_endpoint_parse ( of_fwnode_handle ( ep ) , & bus_cfg ) ;
2020-11-19 17:19:29 +01:00
if ( ret )
goto out ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:19:29 +01:00
sensor - > clock_ncont = bus_cfg . bus . mipi_csi2 . flags &
V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK ;
out :
2017-03-22 09:30:27 -03:00
of_node_put ( ep ) ;
2020-11-19 17:19:32 +01:00
2017-03-22 09:30:27 -03:00
return ret ;
}
2019-07-10 18:51:49 -03:00
static int ov5647_probe ( struct i2c_client * client )
2017-03-22 09:30:27 -03:00
{
2020-11-19 17:19:32 +01:00
struct device_node * np = client - > dev . of_node ;
2017-03-22 09:30:27 -03:00
struct device * dev = & client - > dev ;
struct ov5647 * sensor ;
struct v4l2_subdev * sd ;
u32 xclk_freq ;
2020-11-19 17:19:32 +01:00
int ret ;
2017-03-22 09:30:27 -03:00
sensor = devm_kzalloc ( dev , sizeof ( * sensor ) , GFP_KERNEL ) ;
if ( ! sensor )
return - ENOMEM ;
if ( IS_ENABLED ( CONFIG_OF ) & & np ) {
2020-11-19 17:19:29 +01:00
ret = ov5647_parse_dt ( sensor , np ) ;
2017-03-22 09:30:27 -03:00
if ( ret ) {
dev_err ( dev , " DT parsing error: %d \n " , ret ) ;
return ret ;
}
}
sensor - > xclk = devm_clk_get ( dev , NULL ) ;
if ( IS_ERR ( sensor - > xclk ) ) {
dev_err ( dev , " could not get xclk " ) ;
return PTR_ERR ( sensor - > xclk ) ;
}
xclk_freq = clk_get_rate ( sensor - > xclk ) ;
if ( xclk_freq ! = 25000000 ) {
dev_err ( dev , " Unsupported clock frequency: %u \n " , xclk_freq ) ;
return - EINVAL ;
}
2020-11-19 17:19:32 +01:00
/* Request the power down GPIO asserted. */
sensor - > pwdn = devm_gpiod_get_optional ( dev , " pwdn " , GPIOD_OUT_HIGH ) ;
2020-11-19 17:19:28 +01:00
if ( IS_ERR ( sensor - > pwdn ) ) {
dev_err ( dev , " Failed to get 'pwdn' gpio \n " ) ;
return - EINVAL ;
}
2017-03-22 09:30:27 -03:00
mutex_init ( & sensor - > lock ) ;
2020-11-19 17:32:33 +01:00
sensor - > mode = OV5647_DEFAULT_MODE ;
2020-11-19 17:32:31 +01:00
ret = ov5647_init_controls ( sensor ) ;
if ( ret )
goto mutex_destroy ;
2017-03-22 09:30:27 -03:00
sd = & sensor - > sd ;
v4l2_i2c_subdev_init ( sd , client , & ov5647_subdev_ops ) ;
2020-11-19 17:19:32 +01:00
sd - > internal_ops = & ov5647_subdev_internal_ops ;
2020-11-19 17:35:40 +01:00
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS ;
2017-03-22 09:30:27 -03:00
sensor - > pad . flags = MEDIA_PAD_FL_SOURCE ;
sd - > entity . function = MEDIA_ENT_F_CAM_SENSOR ;
ret = media_entity_pads_init ( & sd - > entity , 1 , & sensor - > pad ) ;
if ( ret < 0 )
2020-11-19 17:32:31 +01:00
goto ctrl_handler_free ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:35:45 +01:00
ret = ov5647_power_on ( dev ) ;
if ( ret )
goto entity_cleanup ;
2020-11-19 17:19:28 +01:00
2017-03-22 09:30:27 -03:00
ret = ov5647_detect ( sd ) ;
if ( ret < 0 )
2020-11-19 17:35:45 +01:00
goto power_off ;
2017-03-22 09:30:27 -03:00
ret = v4l2_async_register_subdev ( sd ) ;
if ( ret < 0 )
2020-11-19 17:35:45 +01:00
goto power_off ;
/* Enable runtime PM and turn off the device */
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
pm_runtime_idle ( dev ) ;
2017-03-22 09:30:27 -03:00
dev_dbg ( dev , " OmniVision OV5647 camera driver probed \n " ) ;
2020-11-19 17:19:32 +01:00
2017-03-22 09:30:27 -03:00
return 0 ;
2020-11-19 17:19:32 +01:00
2020-11-19 17:35:45 +01:00
power_off :
ov5647_power_off ( dev ) ;
2020-11-19 17:19:32 +01:00
entity_cleanup :
2017-03-22 09:30:27 -03:00
media_entity_cleanup ( & sd - > entity ) ;
2020-11-19 17:32:31 +01:00
ctrl_handler_free :
v4l2_ctrl_handler_free ( & sensor - > ctrls ) ;
2020-11-19 17:19:32 +01:00
mutex_destroy :
2017-03-22 09:30:27 -03:00
mutex_destroy ( & sensor - > lock ) ;
2020-11-19 17:19:32 +01:00
2017-03-22 09:30:27 -03:00
return ret ;
}
static int ov5647_remove ( struct i2c_client * client )
{
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
2020-11-19 17:32:32 +01:00
struct ov5647 * sensor = to_sensor ( sd ) ;
2017-03-22 09:30:27 -03:00
2020-11-19 17:32:32 +01:00
v4l2_async_unregister_subdev ( & sensor - > sd ) ;
media_entity_cleanup ( & sensor - > sd . entity ) ;
v4l2_ctrl_handler_free ( & sensor - > ctrls ) ;
2017-03-22 09:30:27 -03:00
v4l2_device_unregister_subdev ( sd ) ;
2020-11-19 17:35:45 +01:00
pm_runtime_disable ( & client - > dev ) ;
2020-11-19 17:32:32 +01:00
mutex_destroy ( & sensor - > lock ) ;
2017-03-22 09:30:27 -03:00
return 0 ;
}
2020-11-19 17:35:45 +01:00
static const struct dev_pm_ops ov5647_pm_ops = {
SET_RUNTIME_PM_OPS ( ov5647_power_off , ov5647_power_on , NULL )
} ;
2017-03-22 09:30:27 -03:00
static const struct i2c_device_id ov5647_id [ ] = {
{ " ov5647 " , 0 } ,
2020-11-19 17:19:32 +01:00
{ /* sentinel */ }
2017-03-22 09:30:27 -03:00
} ;
MODULE_DEVICE_TABLE ( i2c , ov5647_id ) ;
# if IS_ENABLED(CONFIG_OF)
static const struct of_device_id ov5647_of_match [ ] = {
{ . compatible = " ovti,ov5647 " } ,
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , ov5647_of_match ) ;
# endif
static struct i2c_driver ov5647_driver = {
. driver = {
. of_match_table = of_match_ptr ( ov5647_of_match ) ,
2020-11-19 17:19:32 +01:00
. name = " ov5647 " ,
2020-11-19 17:35:45 +01:00
. pm = & ov5647_pm_ops ,
2017-03-22 09:30:27 -03:00
} ,
2019-07-10 18:51:49 -03:00
. probe_new = ov5647_probe ,
2017-03-22 09:30:27 -03:00
. remove = ov5647_remove ,
. id_table = ov5647_id ,
} ;
module_i2c_driver ( ov5647_driver ) ;
MODULE_AUTHOR ( " Ramiro Oliveira <roliveir@synopsys.com> " ) ;
MODULE_DESCRIPTION ( " A low-level driver for OmniVision ov5647 sensors " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;