// SPDX-License-Identifier: GPL-2.0
/*
* 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>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-mediabus.h>
/*
* 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
#define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5)
#define MIPI_CTRL00_LINE_SYNC_ENABLE BIT(4)
#define MIPI_CTRL00_BUS_IDLE BIT(2)
#define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0)
#define OV5647_SW_STANDBY CCI_REG8(0x0100)
#define OV5647_SW_RESET CCI_REG8(0x0103)
#define OV5647_REG_CHIPID CCI_REG16(0x300a)
#define OV5640_REG_PAD_OUT CCI_REG8(0x300d)
#define OV5647_REG_EXPOSURE CCI_REG24(0x3500)
#define OV5647_REG_AEC_AGC CCI_REG8(0x3503)
#define OV5647_REG_GAIN CCI_REG16(0x350a)
#define OV5647_REG_HTS CCI_REG16(0x380c)
#define OV5647_REG_VTS CCI_REG16(0x380e)
#define OV5647_REG_TIMING_TC_V CCI_REG8(0x3820)
#define OV5647_REG_TIMING_TC_H CCI_REG8(0x3821)
#define OV5647_REG_FRAME_OFF_NUMBER CCI_REG8(0x4202)
#define OV5647_REG_MIPI_CTRL00 CCI_REG8(0x4800)
#define OV5647_REG_MIPI_CTRL14 CCI_REG8(0x4814)
#define OV5647_REG_MIPI_CTRL14_CHANNEL_MASK GENMASK(7, 6)
#define OV5647_REG_MIPI_CTRL14_CHANNEL_SHIFT 6
#define OV5647_REG_AWB CCI_REG8(0x5001)
#define OV5647_REG_ISPCTRL3D CCI_REG8(0x503d)
#define OV5647_CHIP_ID 0x5647
#define REG_TERM 0xfffe
#define VAL_TERM 0xfe
#define REG_DLY 0xffff
/* 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 6U
#define OV5647_PIXEL_ARRAY_WIDTH 2592U
#define OV5647_PIXEL_ARRAY_HEIGHT 1944U
#define OV5647_VBLANK_MIN 24
#define OV5647_VTS_MAX 32767
#define OV5647_HTS_MAX 0x1fff
#define OV5647_EXPOSURE_MIN 4
#define OV5647_EXPOSURE_STEP 1
#define OV5647_EXPOSURE_DEFAULT 1000
#define OV5647_EXPOSURE_MAX 65535
/* regulator supplies */
static const char * const ov5647_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
"dvdd", /* Digital core power */
};
#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names)
#define FREQ_INDEX_FULL 0
#define FREQ_INDEX_VGA 1
static const s64 ov5647_link_freqs[] = {
[FREQ_INDEX_FULL] = 218750000,
[FREQ_INDEX_VGA] = 145833300,
};
struct ov5647_mode {
struct v4l2_mbus_framefmt format;
struct v4l2_rect crop;
u64 pixel_rate;
unsigned int link_freq_index;
int hts;
int vts;
const struct reg_sequence *reg_list;
unsigned int num_regs;
};
struct ov5647 {
struct v4l2_subdev sd;
struct regmap *regmap;
struct media_pad pad;
struct clk *xclk;
struct gpio_desc *pwdn;
struct regulator_bulk_data supplies[OV5647_NUM_SUPPLIES];
bool clock_ncont