// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Microchip Corporation.
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
#define REG_OUTSIZE_LSB 0x34
/* OV7740 register tables */
#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
#define REG_BGAIN 0x01 /* blue gain */
#define REG_RGAIN 0x02 /* red gain */
#define REG_GGAIN 0x03 /* green gain */
#define REG_REG04 0x04 /* analog setting, don't change*/
#define REG_BAVG 0x05 /* b channel average */
#define REG_GAVG 0x06 /* g channel average */
#define REG_RAVG 0x07 /* r channel average */
#define REG_REG0C 0x0C /* filp enable */
#define REG0C_IMG_FLIP 0x80
#define REG0C_IMG_MIRROR 0x40
#define REG_REG0E 0x0E /* blc line */
#define REG_HAEC 0x0F /* auto exposure cntrl */
#define REG_AEC 0x10 /* auto exposure cntrl */
#define REG_CLK 0x11 /* Clock control */
#define REG_REG55 0x55 /* Clock PLL DIV/PreDiv */
#define REG_REG12 0x12
#define REG_REG13 0x13 /* auto/manual AGC, AEC, Write Balance*/
#define REG13_AEC_EN 0x01
#define REG13_AGC_EN 0x04
#define REG_REG14 0x14
#define REG_CTRL15 0x15
#define REG15_GAIN_MSB 0x03
#define REG_REG16 0x16
#define REG_MIDH 0x1C /* manufacture id byte */
#define REG_MIDL 0x1D /* manufacture id byre */
#define REG_PIDH 0x0A /* Product ID MSB */
#define REG_PIDL 0x0B /* Product ID LSB */
#define REG_84 0x84 /* lots of stuff */
#define REG_REG38 0x38 /* sub-addr */
#define REG_AHSTART 0x17 /* Horiz start high bits */
#define REG_AHSIZE 0x18
#define REG_AVSTART 0x19 /* Vert start high bits */
#define REG_AVSIZE 0x1A
#define REG_PSHFT 0x1b /* Pixel delay after HREF */
#define REG_HOUTSIZE 0x31
#define REG_VOUTSIZE 0x32
#define REG_HVSIZEOFF 0x33
#define REG_REG34 0x34 /* DSP output size H/V LSB*/
#define REG_ISP_CTRL00 0x80
#define ISPCTRL00_AWB_EN 0x10
#define ISPCTRL00_AWB_GAIN_EN 0x04
#define REG_YGAIN 0xE2 /* ygain for contrast control */
#define REG_YBRIGHT 0xE3
#define REG_SGNSET 0xE4
#define SGNSET_YBRIGHT_MASK 0x08
#define REG_USAT 0xDD
#define REG_VSAT 0xDE
struct ov7740 {
struct v4l2_subdev subdev;
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_pad pad;
#endif
struct v4l2_mbus_framefmt format;
const struct ov7740_pixfmt *fmt; /* Current format */
const struct ov7740_framesize *frmsize;
struct regmap *regmap;
struct clk *xvclk;
struct v4l2_ctrl_handler ctrl_handler;
struct {
/* gain cluster */
struct v4l2_ctrl *auto_gain;
struct v4l2_ctrl *gain;
};
struct {
struct v4l2_ctrl *auto_wb;
struct v4l2_ctrl *blue_balance;
struct v4l2_ctrl *red_balance;
};
struct {
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
};
struct {
/* exposure cluster */
struct v4l2_ctrl *auto_exposure;
struct v4l2_ctrl *exposure;
};
struct {
/* saturation/hue cluster */
struct v4l2_ctrl *saturation;
struct v4l2_ctrl *hue;
};
struct v4l2_ctrl *brightness;
struct v4l2_ctrl *contrast;
struct mutex mutex; /* To serialize asynchronus callbacks */
bool streaming; /* Streaming on/off */
struct gpio_desc *resetb_gpio;
struct gpio_desc *pwdn_gpio;
};
struct ov7740_pixfmt {
u32 mbus_code;
enum v4l2_colorspace colorspace;
const struct reg_sequence *regs;
u32 reg_num;
};
struct ov7740_framesize {
u16 width;
u16 height;
const struct reg_sequence *regs;
u32 reg_num;
};
static const struct reg_sequence ov7740_vga[] = {
{0x55, 0x40},
{0x11, 0x02},
{0xd5, 0x10},
{0x0c, 0x12},
{0x0d, 0x34},
{0x17, 0x25},
{0x18, 0xa0},
{0x19, 0x03},
{0x1a, 0xf0},
{0x1b, 0x89},
{0x22, 0x03},
{0x29, 0x18},
{0x2b, 0xf8},
{0x2c, 0x01},
{REG_HOUTSIZE, 0xa0},
{REG_VOUTSIZE, 0xf0},
{0x33