// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2021 Intel Corporation
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <asm/unaligned.h>
#define IMX208_REG_MODE_SELECT 0x0100
#define IMX208_MODE_STANDBY 0x00
#define IMX208_MODE_STREAMING 0x01
/* Chip ID */
#define IMX208_REG_CHIP_ID 0x0000
#define IMX208_CHIP_ID 0x0208
/* V_TIMING internal */
#define IMX208_REG_VTS 0x0340
#define IMX208_VTS_60FPS 0x0472
#define IMX208_VTS_BINNING 0x0239
#define IMX208_VTS_60FPS_MIN 0x0458
#define IMX208_VTS_BINNING_MIN 0x0230
#define IMX208_VTS_MAX 0xffff
/* HBLANK control - read only */
#define IMX208_PPL_384MHZ 2248
#define IMX208_PPL_96MHZ 2248
/* Exposure control */
#define IMX208_REG_EXPOSURE 0x0202
#define IMX208_EXPOSURE_MIN 4
#define IMX208_EXPOSURE_STEP 1
#define IMX208_EXPOSURE_DEFAULT 0x190
#define IMX208_EXPOSURE_MAX 65535
/* Analog gain control */
#define IMX208_REG_ANALOG_GAIN 0x0204
#define IMX208_ANA_GAIN_MIN 0
#define IMX208_ANA_GAIN_MAX 0x00e0
#define IMX208_ANA_GAIN_STEP 1
#define IMX208_ANA_GAIN_DEFAULT 0x0
/* Digital gain control */
#define IMX208_REG_GR_DIGITAL_GAIN 0x020e
#define IMX208_REG_R_DIGITAL_GAIN 0x0210
#define IMX208_REG_B_DIGITAL_GAIN 0x0212
#define IMX208_REG_GB_DIGITAL_GAIN 0x0214
#define IMX208_DIGITAL_GAIN_SHIFT 8
/* Orientation */
#define IMX208_REG_ORIENTATION_CONTROL 0x0101
/* Test Pattern Control */
#define IMX208_REG_TEST_PATTERN_MODE 0x0600
#define IMX208_TEST_PATTERN_DISABLE 0x0
#define IMX208_TEST_PATTERN_SOLID_COLOR 0x1
#define IMX208_TEST_PATTERN_COLOR_BARS 0x2
#define IMX208_TEST_PATTERN_GREY_COLOR 0x3
#define IMX208_TEST_PATTERN_PN9 0x4
#define IMX208_TEST_PATTERN_FIX_1 0x100
#define IMX208_TEST_PATTERN_FIX_2 0x101
#define IMX208_TEST_PATTERN_FIX_3 0x102
#define IMX208_TEST_PATTERN_FIX_4 0x103
#define IMX208_TEST_PATTERN_FIX_5 0x104
#define IMX208_TEST_PATTERN_FIX_6 0x105
/* OTP Access */
#define IMX208_OTP_BASE 0x3500
#define IMX208_OTP_SIZE 40
struct imx208_reg {
u16 address;
u8 val;
};
struct imx208_reg_list {
u32 num_of_regs;
const struct imx208_reg *regs;
};
/* Link frequency config */
struct imx208_link_freq_config {
u32 pixels_per_line;
/* PLL registers for this link frequency */
struct imx208_reg_list reg_list;
};
/* Mode : resolution and related config&values */
struct imx208_mode {
/* Frame width */
u32 width;
/* Frame height */
u32 height;
/* V-timing */
u32 vts_def;
u32 vts_min;
/* Index of Link frequency config to be used */
u32 link_freq_index;
/* Default register values */
struct imx208_reg_list reg_list;
};
static const struct imx208_reg pll_ctrl_reg[] = {
{0x0305, 0x02},
{0x0307, 0x50},
{0x303C, 0x3C},
};
static const struct imx208_reg mode_1936x1096_60fps_regs[] = {
{0x0340, 0x04},
{0x0341, 0x72},
{0x0342, 0x04},
{0x0343, 0x64},
{0x034C, 0x07},
{0x034D, 0x90},
{0x034E, 0x04},
{0x034F, 0x48},
{0x0381, 0x01},
{0x0383, 0x01},
{0x0385, 0x01},
{0x0387, 0x01},
{0x3048, 0x00},
{0x3050, 0x01},
{0x30D5, 0x00},
{0x3301, 0x00},
{0x3318, 0x62},
{0x0202, 0x01},
{0x0203, 0x90},
{0x0205, 0x00},
};
static const struct imx208_reg mode_968_548_60fps_regs[] = {
{0x0340, 0x02},
{0x0341, 0x39},
{0x0342, 0x08},
{0x0343, 0xC8},
{0x034C, 0x03},
{0x034D, 0xC8},
{0x034E, 0x02},
{0x034F, 0x24},
{0x0381, 0x01},
{0x0383, 0x03},
{0x0385, 0x01},
{0x0387, 0x03},
{0x3048, 0x01},
{0x3050, 0x02},
{0x30D5, 0x03},
{0x3301, 0x10},
{0x3318, 0x75},
{0x0202, 0x01},
{0x0203, 0x90},
{0x0205, 0x00},
};
static const s64 imx208_discrete_digital_gain[] = {
1, 2, 4, 8, 16,
};
static const char * const imx208_test_pattern_menu[] = {
"Disabled",
"Solid Color",
"100% Color Bar",
"Fade to Grey Color Bar",
"PN9",
"Fixed Pattern1",
"Fixed Pattern2",
"Fixed Pattern3",
"Fixed Pattern4",
"Fixed Pattern5",
"Fixed Pattern6"
};
static const int imx208_test_pattern_val[] = {
IMX208_TEST_PATTERN_DISABLE,
IMX208_TEST_PATTERN_SOLID_COLOR,
IMX208_TEST_PATTERN_COLOR_BARS,
IMX208_TEST_PATTERN_GREY_COLOR,
IMX208_TEST_PATTERN_PN9,
IMX208_TEST_PATTERN_FIX_1,
IMX208_TEST_PATTERN_FIX_2,
IMX208_TEST_PATTERN_FIX_3,
IMX208_TEST_PATTERN_FIX_4,
IMX208_TEST_PATTERN_FIX_5,
IMX208_TEST_PATTERN_FIX_6,
};
/* Configurations for supported link frequencies */
#define IMX208_MHZ (1000 * 1000ULL)
#define IMX208_LINK_FREQ_384MHZ (384ULL * IMX208_MHZ)
#define IMX208_LINK_FREQ_96MHZ (96ULL * IMX208_MHZ)
#define IMX208_DATA_RATE_DOUBLE 2
#define IMX208_NUM_OF_LANES 2
#define IMX208_PIXEL_BITS 10
enum {
IMX208_LINK_FREQ_384MHZ_INDEX,
IMX208_LINK_FREQ_96MHZ_INDEX,
};
/*
* pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
* data rate => double data rate; number of lanes => 2; bits per pixel => 10
*/
static u64 link_freq_to_pixel_rate(u64 f)
{
f *= IMX208_DATA_RATE_DOUBLE * IMX208_NUM_OF_LANES;
do_div(f, IMX208_PIXEL_BITS);
return f;
}
/* Menu items for LINK_FREQ V4L2 control */
static const s64 link_freq_menu_items[] = {
[IMX208_LINK_FREQ_384MHZ_INDEX] = IMX208_LINK_FREQ_384MHZ,
[IMX208_LINK_FREQ_96MHZ_INDEX] = IMX208_LINK_FREQ_96MHZ,
};
/* Link frequency configs */
static const struct imx208_link_freq_config link_freq_configs[] = {
[IMX208_LINK_FREQ_384MHZ_INDEX] = {
.pixels_per_line = IMX208_PPL_38