// SPDX-License-Identifier: GPL-2.0
/*
* Omnivision OV2680 CMOS Image Sensor driver
*
* Copyright (C) 2018 Linaro Ltd
*
* Based on OV5640 Sensor Driver
* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2014-2017 Mentor Graphics Inc.
*
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#define OV2680_CHIP_ID 0x2680
#define OV2680_REG_STREAM_CTRL CCI_REG8(0x0100)
#define OV2680_REG_SOFT_RESET CCI_REG8(0x0103)
#define OV2680_REG_CHIP_ID CCI_REG16(0x300a)
#define OV2680_REG_SC_CMMN_SUB_ID CCI_REG8(0x302a)
#define OV2680_REG_PLL_MULTIPLIER CCI_REG16(0x3081)
#define OV2680_REG_EXPOSURE_PK CCI_REG24(0x3500)
#define OV2680_REG_R_MANUAL CCI_REG8(0x3503)
#define OV2680_REG_GAIN_PK CCI_REG16(0x350a)
#define OV2680_REG_SENSOR_CTRL_0A CCI_REG8(0x370a)
#define OV2680_REG_HORIZONTAL_START CCI_REG16(0x3800)
#define OV2680_REG_VERTICAL_START CCI_REG16(0x3802)
#define OV2680_REG_HORIZONTAL_END CCI_REG16(0x3804)
#define OV2680_REG_VERTICAL_END CCI_REG16(0x3806)
#define OV2680_REG_HORIZONTAL_OUTPUT_SIZE CCI_REG16(0x3808)
#define OV2680_REG_VERTICAL_OUTPUT_SIZE CCI_REG16(0x380a)
#define OV2680_REG_TIMING_HTS CCI_REG16(0x380c)
#define OV2680_REG_TIMING_VTS CCI_REG16(0x380e)
#define OV2680_REG_ISP_X_WIN CCI_REG16(0x3810)
#define OV2680_REG_ISP_Y_WIN CCI_REG16(0x3812)
#define OV2680_REG_X_INC CCI_REG8(0x3814)
#define OV2680_REG_Y_INC CCI_REG8(0x3815)
#define OV2680_REG_FORMAT1 CCI_REG8(0x3820)
#define OV2680_REG_FORMAT2 CCI_REG8(0x3821)
#define OV2680_REG_ISP_CTRL00 CCI_REG8(0x5080)
#define OV2680_REG_X_WIN CCI_REG16(0x5704)
#define OV2680_REG_Y_WIN CCI_REG16(0x5706)
#define OV2680_FRAME_RATE 30
#define OV2680_NATIVE_WIDTH 1616
#define OV2680_NATIVE_HEIGHT 1216
#define OV2680_NATIVE_START_LEFT 0
#define OV2680_NATIVE_START_TOP 0
#define OV2680_ACTIVE_WIDTH 1600
#define OV2680_ACTIVE_HEIGHT 1200
#define OV2680_ACTIVE_START_LEFT 8
#define OV2680_ACTIVE_START_TOP 8
#define OV2680_MIN_CROP_WIDTH 2
#define OV2680_MIN_CROP_HEIGHT 2
/* Fixed pre-div of 1/2 */
#define OV2680_PLL_PREDIV0 2
/* Pre-div configurable through reg 0x3080, left at its default of 0x02 : 1/2 */
#define OV2680_PLL_PREDIV 2
/* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */
#define OV2680_PIXELS_PER_LINE 1704
#define OV2680_LINES_PER_FRAME 1294
/* If possible send 16 extra rows / lines to the ISP as padding */
#define OV2680_END_MARGIN 16
/* Max exposure time is VTS - 8 */
#define OV2680_INTEGRATION_TIME_MARGIN 8
#define OV2680_DEFAULT_WIDTH 800
#define OV2680_DEFAULT_HEIGHT 600
/* For enum_frame_size() full-size + binned-/quarter-size */
#define OV2680_FRAME_SIZES 2
static const char * const ov2680_supply_name[] = {
"DOVDD",
"DVDD",
"AVDD",
};
#define OV2680_NUM_SUPPLIES ARRAY_SIZE(ov2680_supply_name)
enum {
OV2680_19_2_MHZ,
OV2680_24_MHZ,
};
static const unsigned long ov2680_xvclk_freqs[] = {
[OV2680_19_2_MHZ] = 19200000,
[OV2680_24_MHZ] = 24000000,
};
static const u8 ov2680_pll_multipliers[] = {
[OV2680_19_2_MHZ] = 69,
[OV2680_24_MHZ] = 55,
};
struct ov2680_ctrls {
struct v4l2_ctrl_handler handler;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *gain;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *test_pattern;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate;
};
struct ov2680_mode {
struct v4l2_rect crop;
struct v4l2_mbus_framefmt fmt;
struct v4l2_fract frame_interval;
bool binning;
u16 h_start;
u16 v_start;
u16 h_end;
u16 v_end;
u16 h_output_size;
u16 v_output_size;
u16 hts;
u16 vts;
};
struct ov2680_dev {
struct device *dev;
struct regmap *regmap;
struct v4l2_subdev sd;
struct media_pad pad;
struct clk *xvclk;
u32 xvclk_freq;
u8 pll_mult;
s64 link_freq[1];
u64 pixel_rate;
struct regulator_bulk_data supplies[OV2680_NUM_SUPPLIES];