// SPDX-License-Identifier: GPL-2.0
/*
* Driver for GalaxyCore gc05a2 image sensor
*
* Copyright 2024 MediaTek
*
* Zhi Mao <zhi.mao@mediatek.com>
*/
#include <linux/array_size.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/units.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#define GC05A2_REG_TEST_PATTERN_EN CCI_REG8(0x008c)
#define GC05A2_REG_TEST_PATTERN_IDX CCI_REG8(0x008d)
#define GC05A2_TEST_PATTERN_EN 0x01
#define GC05A2_STREAMING_REG CCI_REG8(0x0100)
#define GC05A2_FLIP_REG CCI_REG8(0x0101)
#define GC05A2_FLIP_H_MASK BIT(0)
#define GC05A2_FLIP_V_MASK BIT(1)
#define GC05A2_EXP_REG CCI_REG16(0x0202)
#define GC05A2_EXP_MARGIN 16
#define GC05A2_EXP_MIN 4
#define GC05A2_EXP_STEP 1
#define GC05A2_AGAIN_REG CCI_REG16(0x0204)
#define GC05A2_AGAIN_MIN 1024
#define GC05A2_AGAIN_MAX (1024 * 16)
#define GC05A2_AGAIN_STEP 1
#define GC05A2_FRAME_LENGTH_REG CCI_REG16(0x0340)
#define GC05A2_VTS_MAX 0xffff
#define GC05A2_REG_CHIP_ID CCI_REG16(0x03f0)
#define GC05A2_CHIP_ID 0x05a2
#define GC05A2_NATIVE_WIDTH 2592
#define GC05A2_NATIVE_HEIGHT 1944
#define GC05A2_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ)
#define GC05A2_MBUS_CODE MEDIA_BUS_FMT_SGRBG10_1X10
#define GC05A2_DATA_LANES 2
#define GC05A2_RGB_DEPTH 10
#define GC05A2_SLEEP_US (2 * USEC_PER_MSEC)
static const char *const gc05a2_test_pattern_menu[] = {
"No Pattern", "Fade_to_gray_Color Bar", "Color Bar",
"PN9", "Horizontal_gradient", "Checkboard Pattern",
"Slant", "Resolution", "Solid Black",
"Solid White",
};
static const s64 gc05a2_link_freq_menu_items[] = {
(448 * HZ_PER_MHZ),
(224 * HZ_PER_MHZ),
};
static const char *const gc05a2_supply_name[] = {
"avdd",
"dvdd",
"dovdd",
};
struct gc05a2 {
struct device *dev;
struct v4l2_subdev sd;
struct media_pad pad;
struct clk *xclk;
struct regulator_bulk_data supplies[ARRAY_SIZE(gc05a2_supply_name)];
struct gpio_desc *reset_gpio;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct regmap *regmap;
unsigned long link_freq_bitmap;
/* True if the device has been identified */
bool identified;
const struct gc05a2_mode *cur_mode;
};
struct gc05a2_reg_list {
u32 num_of_regs;
const struct cci_reg_sequence *regs;
};
static const struct cci_reg_sequence mode_2592x1944[] = {
/* system */
{ CCI_REG8(0x0135), 0x01 },
{ CCI_REG8(<