13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * gc2093 sensor driver
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (C) 2020 Rockchip Electronics Co., Ltd.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * V0.0X01.0X00 first version.
83d0407baSopenharmony_ci * V0.0X01.0X01 Add HDR support.
93d0407baSopenharmony_ci * V0.0X01.0X02 update sensor driver
103d0407baSopenharmony_ci * 1. fix linear mode ae flicker issue.
113d0407baSopenharmony_ci * 2. add hdr mode exposure limit issue.
123d0407baSopenharmony_ci * 3. fix hdr mode highlighting pink issue.
133d0407baSopenharmony_ci * 4. add some debug info.
143d0407baSopenharmony_ci */
153d0407baSopenharmony_ci
163d0407baSopenharmony_ci#include <linux/clk.h>
173d0407baSopenharmony_ci#include <linux/delay.h>
183d0407baSopenharmony_ci#include <linux/gpio/consumer.h>
193d0407baSopenharmony_ci#include <linux/i2c.h>
203d0407baSopenharmony_ci#include <linux/module.h>
213d0407baSopenharmony_ci#include <linux/pm_runtime.h>
223d0407baSopenharmony_ci#include <linux/of_graph.h>
233d0407baSopenharmony_ci#include <linux/regmap.h>
243d0407baSopenharmony_ci#include <linux/regulator/consumer.h>
253d0407baSopenharmony_ci#include <linux/version.h>
263d0407baSopenharmony_ci#include <linux/rk-camera-module.h>
273d0407baSopenharmony_ci#include <linux/rk-preisp.h>
283d0407baSopenharmony_ci
293d0407baSopenharmony_ci#include <media/v4l2-async.h>
303d0407baSopenharmony_ci#include <media/media-entity.h>
313d0407baSopenharmony_ci#include <media/v4l2-ctrls.h>
323d0407baSopenharmony_ci#include <media/v4l2-device.h>
333d0407baSopenharmony_ci#include <media/v4l2-fwnode.h>
343d0407baSopenharmony_ci#include <media/v4l2-subdev.h>
353d0407baSopenharmony_ci
363d0407baSopenharmony_ci#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
373d0407baSopenharmony_ci#define GC2093_NAME "gc2093"
383d0407baSopenharmony_ci#define GC2093_MEDIA_BUS_FMT MEDIA_BUS_FMT_SRGGB10_1X10
393d0407baSopenharmony_ci
403d0407baSopenharmony_ci#define MIPI_FREQ_150M 150000000
413d0407baSopenharmony_ci#define MIPI_FREQ_300M 300000000
423d0407baSopenharmony_ci#define MIPI_FREQ_594M 594000000
433d0407baSopenharmony_ci
443d0407baSopenharmony_ci#define GC2093_XVCLK_FREQ 27000000
453d0407baSopenharmony_ci
463d0407baSopenharmony_ci#define GC2093_REG_CHIP_ID_H 0x03F0
473d0407baSopenharmony_ci#define GC2093_REG_CHIP_ID_L 0x03F1
483d0407baSopenharmony_ci
493d0407baSopenharmony_ci#define GC2093_REG_EXP_SHORT_H 0x0001
503d0407baSopenharmony_ci#define GC2093_REG_EXP_SHORT_L 0x0002
513d0407baSopenharmony_ci#define GC2093_REG_EXP_LONG_H 0x0003
523d0407baSopenharmony_ci#define GC2093_REG_EXP_LONG_L 0x0004
533d0407baSopenharmony_ci
543d0407baSopenharmony_ci#define GC2093_REG_VB_H 0x0007
553d0407baSopenharmony_ci#define GC2093_REG_VB_L 0x0008
563d0407baSopenharmony_ci
573d0407baSopenharmony_ci#define GC2093_MIRROR_FLIP_REG 0x0017
583d0407baSopenharmony_ci#define MIRROR_MASK BIT(0)
593d0407baSopenharmony_ci#define FLIP_MASK BIT(1)
603d0407baSopenharmony_ci
613d0407baSopenharmony_ci#define GC2093_REG_CTRL_MODE 0x003E
623d0407baSopenharmony_ci#define GC2093_MODE_SW_STANDBY 0x11
633d0407baSopenharmony_ci#define GC2093_MODE_STREAMING 0x91
643d0407baSopenharmony_ci
653d0407baSopenharmony_ci#define GC2093_CHIP_ID 0x2093
663d0407baSopenharmony_ci
673d0407baSopenharmony_ci#define GC2093_VTS_MAX 0x3FFF
683d0407baSopenharmony_ci#define GC2093_HTS_MAX 0xFFF
693d0407baSopenharmony_ci
703d0407baSopenharmony_ci#define GC2093_EXPOSURE_MAX 0x3FFF
713d0407baSopenharmony_ci#define GC2093_EXPOSURE_MIN 1
723d0407baSopenharmony_ci#define GC2093_EXPOSURE_STEP 1
733d0407baSopenharmony_ci
743d0407baSopenharmony_ci#define GC2093_GAIN_MIN 0x40
753d0407baSopenharmony_ci#define GC2093_GAIN_MAX 0x2000
763d0407baSopenharmony_ci#define GC2093_GAIN_STEP 1
773d0407baSopenharmony_ci#define GC2093_GAIN_DEFAULT 64
783d0407baSopenharmony_ci#define REG_NULL 0xFFFF
793d0407baSopenharmony_ci
803d0407baSopenharmony_ci#define GC2093_LANES 2
813d0407baSopenharmony_ci#define PI_REG_VALUE_FO 4
823d0407baSopenharmony_ci#define PI_REG_VALUE_SI 6
833d0407baSopenharmony_ci#define PI_REG_VALUE_EI 8
843d0407baSopenharmony_ci#define PI_RATE_VALUE 10
853d0407baSopenharmony_ci#define PI_OFFSET_VALUE 16
863d0407baSopenharmony_ci#define PRE_GIN_COUNT 64
873d0407baSopenharmony_ci#define SLEEP_LOW_VALUE 1000
883d0407baSopenharmony_ci#define SLEEP_HIGH_VALUE 2000
893d0407baSopenharmony_ci#define SLEEP_SLOW_VALUE 10000
903d0407baSopenharmony_ci#define SLEEP_SHIGH_VALUE 20000
913d0407baSopenharmony_ci
923d0407baSopenharmony_cistatic const char *const gc2093_supply_names[] = {
933d0407baSopenharmony_ci    "dovdd", /* Digital I/O power */
943d0407baSopenharmony_ci    "avdd",  /* Analog power */
953d0407baSopenharmony_ci    "dvdd",  /* Digital power */
963d0407baSopenharmony_ci};
973d0407baSopenharmony_ci
983d0407baSopenharmony_ci#define GC2093_NUM_SUPPLIES ARRAY_SIZE(gc2093_supply_names)
993d0407baSopenharmony_ci
1003d0407baSopenharmony_ci#define to_gc2093(sd) container_of(sd, struct gc2093, subdev)
1013d0407baSopenharmony_ci
1023d0407baSopenharmony_cienum {
1033d0407baSopenharmony_ci    LINK_FREQ_150M_INDEX,
1043d0407baSopenharmony_ci    LINK_FREQ_300M_INDEX,
1053d0407baSopenharmony_ci};
1063d0407baSopenharmony_ci
1073d0407baSopenharmony_cistruct gain_reg_config {
1083d0407baSopenharmony_ci    u32 value;
1093d0407baSopenharmony_ci    u16 analog_gain;
1103d0407baSopenharmony_ci    u16 col_gain;
1113d0407baSopenharmony_ci    u16 analog_sw;
1123d0407baSopenharmony_ci    u16 ram_width;
1133d0407baSopenharmony_ci};
1143d0407baSopenharmony_ci
1153d0407baSopenharmony_cistruct gc2093_mode {
1163d0407baSopenharmony_ci    u32 width;
1173d0407baSopenharmony_ci    u32 height;
1183d0407baSopenharmony_ci    struct v4l2_fract max_fps;
1193d0407baSopenharmony_ci    u32 hts_def;
1203d0407baSopenharmony_ci    u32 vts_def;
1213d0407baSopenharmony_ci    u32 exp_def;
1223d0407baSopenharmony_ci    u32 link_freq_index;
1233d0407baSopenharmony_ci    const struct reg_sequence *reg_list;
1243d0407baSopenharmony_ci    u32 reg_num;
1253d0407baSopenharmony_ci    u32 hdr_mode;
1263d0407baSopenharmony_ci    u32 vc[PAD_MAX];
1273d0407baSopenharmony_ci};
1283d0407baSopenharmony_ci
1293d0407baSopenharmony_cistruct gc2093 {
1303d0407baSopenharmony_ci    struct device *dev;
1313d0407baSopenharmony_ci    struct clk *xvclk;
1323d0407baSopenharmony_ci    struct regmap *regmap;
1333d0407baSopenharmony_ci    struct gpio_desc *reset_gpio;
1343d0407baSopenharmony_ci    struct gpio_desc *pwdn_gpio;
1353d0407baSopenharmony_ci    struct regulator_bulk_data supplies[GC2093_NUM_SUPPLIES];
1363d0407baSopenharmony_ci
1373d0407baSopenharmony_ci    struct v4l2_subdev subdev;
1383d0407baSopenharmony_ci    struct media_pad pad;
1393d0407baSopenharmony_ci    struct v4l2_ctrl_handler ctrl_handler;
1403d0407baSopenharmony_ci    struct v4l2_ctrl *exposure;
1413d0407baSopenharmony_ci    struct v4l2_ctrl *anal_gain;
1423d0407baSopenharmony_ci    struct v4l2_ctrl *hblank;
1433d0407baSopenharmony_ci    struct v4l2_ctrl *vblank;
1443d0407baSopenharmony_ci    struct v4l2_ctrl *h_flip;
1453d0407baSopenharmony_ci    struct v4l2_ctrl *v_flip;
1463d0407baSopenharmony_ci    struct v4l2_ctrl *link_freq;
1473d0407baSopenharmony_ci    struct v4l2_ctrl *pixel_rate;
1483d0407baSopenharmony_ci
1493d0407baSopenharmony_ci    struct mutex lock;
1503d0407baSopenharmony_ci    bool streaming;
1513d0407baSopenharmony_ci    bool power_on;
1523d0407baSopenharmony_ci    unsigned int cfg_num;
1533d0407baSopenharmony_ci    const struct gc2093_mode *cur_mode;
1543d0407baSopenharmony_ci
1553d0407baSopenharmony_ci    u32 module_index;
1563d0407baSopenharmony_ci    const char *module_facing;
1573d0407baSopenharmony_ci    const char *module_name;
1583d0407baSopenharmony_ci    const char *len_name;
1593d0407baSopenharmony_ci    u32 cur_vts;
1603d0407baSopenharmony_ci
1613d0407baSopenharmony_ci    bool has_init_exp;
1623d0407baSopenharmony_ci    struct preisp_hdrae_exp_s init_hdrae_exp;
1633d0407baSopenharmony_ci};
1643d0407baSopenharmony_ci
1653d0407baSopenharmony_cistatic const struct regmap_config gc2093_regmap_config = {
1663d0407baSopenharmony_ci    .reg_bits = 16,
1673d0407baSopenharmony_ci    .val_bits = 8,
1683d0407baSopenharmony_ci    .max_register = 0x04f0,
1693d0407baSopenharmony_ci};
1703d0407baSopenharmony_ci
1713d0407baSopenharmony_cistatic const s64 link_freq_menu_items[] = {
1723d0407baSopenharmony_ci    //    MIPI_FREQ_150M,
1733d0407baSopenharmony_ci    MIPI_FREQ_594M,
1743d0407baSopenharmony_ci};
1753d0407baSopenharmony_ci
1763d0407baSopenharmony_ci/*
1773d0407baSopenharmony_ci * window size=1920*1080 mipi@2lane
1783d0407baSopenharmony_ci * mclk=27M mipi_clk=594Mbps
1793d0407baSopenharmony_ci * pixel_line_total=2200 line_frame_total=1125
1803d0407baSopenharmony_ci * row_time=29.62us frame_rate=30fps
1813d0407baSopenharmony_ci */
1823d0407baSopenharmony_cistatic const struct reg_sequence gc2093_1080p_liner_settings[] = {
1833d0407baSopenharmony_ci    /* System */
1843d0407baSopenharmony_ci    {0x03fe, 0x80},
1853d0407baSopenharmony_ci    {0x03fe, 0x80},
1863d0407baSopenharmony_ci    {0x03fe, 0x80},
1873d0407baSopenharmony_ci    {0x03fe, 0x00},
1883d0407baSopenharmony_ci    {0x03f2, 0x00},
1893d0407baSopenharmony_ci    {0x03f3, 0x00},
1903d0407baSopenharmony_ci    {0x03f4, 0x36},
1913d0407baSopenharmony_ci    {0x03f5, 0xc0},
1923d0407baSopenharmony_ci    {0x03f6, 0x0a},
1933d0407baSopenharmony_ci    {0x03f7, 0x01},
1943d0407baSopenharmony_ci    {0x03f8, 0x2c},
1953d0407baSopenharmony_ci    {0x03f9, 0x10},
1963d0407baSopenharmony_ci    {0x03fc, 0x8e},
1973d0407baSopenharmony_ci    /* Cisctl & Analog */
1983d0407baSopenharmony_ci    {0x0087, 0x18},
1993d0407baSopenharmony_ci    {0x00ee, 0x30},
2003d0407baSopenharmony_ci    {0x00d0, 0xb7},
2013d0407baSopenharmony_ci    {0x01a0, 0x00},
2023d0407baSopenharmony_ci    {0x01a4, 0x40},
2033d0407baSopenharmony_ci    {0x01a5, 0x40},
2043d0407baSopenharmony_ci    {0x01a6, 0x40},
2053d0407baSopenharmony_ci    {0x01af, 0x09},
2063d0407baSopenharmony_ci    {0x0001, 0x00},
2073d0407baSopenharmony_ci    {0x0002, 0x02},
2083d0407baSopenharmony_ci    {0x0003, 0x00},
2093d0407baSopenharmony_ci    {0x0004, 0x02},
2103d0407baSopenharmony_ci    {0x0005, 0x04},
2113d0407baSopenharmony_ci    {0x0006, 0x4c},
2123d0407baSopenharmony_ci    {0x0007, 0x00},
2133d0407baSopenharmony_ci    {0x0008, 0x11},
2143d0407baSopenharmony_ci    {0x0009, 0x00},
2153d0407baSopenharmony_ci    {0x000a, 0x02},
2163d0407baSopenharmony_ci    {0x000b, 0x00},
2173d0407baSopenharmony_ci    {0x000c, 0x04},
2183d0407baSopenharmony_ci    {0x000d, 0x04},
2193d0407baSopenharmony_ci    {0x000e, 0x40},
2203d0407baSopenharmony_ci    {0x000f, 0x07},
2213d0407baSopenharmony_ci    {0x0010, 0x8c},
2223d0407baSopenharmony_ci    {0x0013, 0x15},
2233d0407baSopenharmony_ci    {0x0019, 0x0c},
2243d0407baSopenharmony_ci    {0x0041, 0x04},
2253d0407baSopenharmony_ci    {0x0042, 0x65},
2263d0407baSopenharmony_ci    {0x0053, 0x60},
2273d0407baSopenharmony_ci    {0x008d, 0x92},
2283d0407baSopenharmony_ci    {0x0090, 0x00},
2293d0407baSopenharmony_ci    {0x00c7, 0xe1},
2303d0407baSopenharmony_ci    {0x001b, 0x73},
2313d0407baSopenharmony_ci    {0x0028, 0x0d},
2323d0407baSopenharmony_ci    {0x0029, 0x24},
2333d0407baSopenharmony_ci    {0x002b, 0x04},
2343d0407baSopenharmony_ci    {0x002e, 0x23},
2353d0407baSopenharmony_ci    {0x0037, 0x03},
2363d0407baSopenharmony_ci    {0x0043, 0x04},
2373d0407baSopenharmony_ci    {0x0044, 0x38},
2383d0407baSopenharmony_ci    {0x004a, 0x01},
2393d0407baSopenharmony_ci    {0x004b, 0x28},
2403d0407baSopenharmony_ci    {0x0055, 0x38},
2413d0407baSopenharmony_ci    {0x006b, 0x44},
2423d0407baSopenharmony_ci    {0x0077, 0x00},
2433d0407baSopenharmony_ci    {0x0078, 0x20},
2443d0407baSopenharmony_ci    {0x007c, 0xa1},
2453d0407baSopenharmony_ci    {0x00d3, 0xd4},
2463d0407baSopenharmony_ci    {0x00e6, 0x50},
2473d0407baSopenharmony_ci    /* Gain */
2483d0407baSopenharmony_ci    {0x00b6, 0xc0},
2493d0407baSopenharmony_ci    {0x00b0, 0x60},
2503d0407baSopenharmony_ci    /* Isp */
2513d0407baSopenharmony_ci    {0x0102, 0x89},
2523d0407baSopenharmony_ci    {0x0104, 0x01},
2533d0407baSopenharmony_ci    {0x010f, 0x00},
2543d0407baSopenharmony_ci    {0x0158, 0x00},
2553d0407baSopenharmony_ci    {0x0123, 0x08},
2563d0407baSopenharmony_ci    {0x0123, 0x00},
2573d0407baSopenharmony_ci    {0x0120, 0x01},
2583d0407baSopenharmony_ci    {0x0121, 0x00},
2593d0407baSopenharmony_ci    {0x0122, 0x10},
2603d0407baSopenharmony_ci    {0x0124, 0x03},
2613d0407baSopenharmony_ci    {0x0125, 0xff},
2623d0407baSopenharmony_ci    {0x0126, 0x3c},
2633d0407baSopenharmony_ci    {0x001a, 0x8c},
2643d0407baSopenharmony_ci    {0x00c6, 0xe0},
2653d0407baSopenharmony_ci    /* Blk */
2663d0407baSopenharmony_ci    {0x0026, 0x30},
2673d0407baSopenharmony_ci    {0x0142, 0x00},
2683d0407baSopenharmony_ci    {0x0149, 0x1e},
2693d0407baSopenharmony_ci    {0x014a, 0x07},
2703d0407baSopenharmony_ci    {0x014b, 0x80},
2713d0407baSopenharmony_ci    {0x0155, 0x00},
2723d0407baSopenharmony_ci    {0x0414, 0x78},
2733d0407baSopenharmony_ci    {0x0415, 0x78},
2743d0407baSopenharmony_ci    {0x0416, 0x78},
2753d0407baSopenharmony_ci    {0x0417, 0x78},
2763d0407baSopenharmony_ci    /* Window */
2773d0407baSopenharmony_ci    {0x0192, 0x02},
2783d0407baSopenharmony_ci    {0x0194, 0x03},
2793d0407baSopenharmony_ci    {0x0195, 0x04},
2803d0407baSopenharmony_ci    {0x0196, 0x38},
2813d0407baSopenharmony_ci    {0x0197, 0x07},
2823d0407baSopenharmony_ci    {0x0198, 0x80},
2833d0407baSopenharmony_ci    /* MIPI */
2843d0407baSopenharmony_ci    {0x019a, 0x06},
2853d0407baSopenharmony_ci    {0x007b, 0x2a},
2863d0407baSopenharmony_ci    {0x0023, 0x2d},
2873d0407baSopenharmony_ci    {0x0201, 0x27},
2883d0407baSopenharmony_ci    {0x0202, 0x56},
2893d0407baSopenharmony_ci    {0x0203, 0xce},
2903d0407baSopenharmony_ci    {0x0212, 0x80},
2913d0407baSopenharmony_ci    {0x0213, 0x07},
2923d0407baSopenharmony_ci    {0x003e, 0x91},
2933d0407baSopenharmony_ci};
2943d0407baSopenharmony_ci
2953d0407baSopenharmony_ci/*
2963d0407baSopenharmony_ci * window size=1920*1080 mipi@2lane
2973d0407baSopenharmony_ci * mclk=27M mipi_clk=792Mbps
2983d0407baSopenharmony_ci * pixel_line_total=2640 line_frame_total=1250
2993d0407baSopenharmony_ci * row_time=13.33us frame_rate=60fps
3003d0407baSopenharmony_ci */
3013d0407baSopenharmony_cistatic const struct reg_sequence gc2093_1080p_hdr_settings[] = {
3023d0407baSopenharmony_ci    /* System */
3033d0407baSopenharmony_ci    {0x03fe, 0x80},
3043d0407baSopenharmony_ci    {0x03fe, 0x80},
3053d0407baSopenharmony_ci    {0x03fe, 0x80},
3063d0407baSopenharmony_ci    {0x03fe, 0x00},
3073d0407baSopenharmony_ci    {0x03f2, 0x00},
3083d0407baSopenharmony_ci    {0x03f3, 0x00},
3093d0407baSopenharmony_ci    {0x03f4, 0x36},
3103d0407baSopenharmony_ci    {0x03f5, 0xc0},
3113d0407baSopenharmony_ci    {0x03f6, 0x0B},
3123d0407baSopenharmony_ci    {0x03f7, 0x01},
3133d0407baSopenharmony_ci    {0x03f8, 0x58},
3143d0407baSopenharmony_ci    {0x03f9, 0x40},
3153d0407baSopenharmony_ci    {0x03fc, 0x8e},
3163d0407baSopenharmony_ci    /* Cisctl & Analog */
3173d0407baSopenharmony_ci    {0x0087, 0x18},
3183d0407baSopenharmony_ci    {0x00ee, 0x30},
3193d0407baSopenharmony_ci    {0x00d0, 0xbf},
3203d0407baSopenharmony_ci    {0x01a0, 0x00},
3213d0407baSopenharmony_ci    {0x01a4, 0x40},
3223d0407baSopenharmony_ci    {0x01a5, 0x40},
3233d0407baSopenharmony_ci    {0x01a6, 0x40},
3243d0407baSopenharmony_ci    {0x01af, 0x09},
3253d0407baSopenharmony_ci    {0x0001, 0x00},
3263d0407baSopenharmony_ci    {0x0002, 0x02},
3273d0407baSopenharmony_ci    {0x0003, 0x04},
3283d0407baSopenharmony_ci    {0x0004, 0x02},
3293d0407baSopenharmony_ci    {0x0005, 0x02},
3303d0407baSopenharmony_ci    {0x0006, 0x94},
3313d0407baSopenharmony_ci    {0x0007, 0x00},
3323d0407baSopenharmony_ci    {0x0008, 0x11},
3333d0407baSopenharmony_ci    {0x0009, 0x00},
3343d0407baSopenharmony_ci    {0x000a, 0x02},
3353d0407baSopenharmony_ci    {0x000b, 0x00},
3363d0407baSopenharmony_ci    {0x000c, 0x04},
3373d0407baSopenharmony_ci    {0x000d, 0x04},
3383d0407baSopenharmony_ci    {0x000e, 0x40},
3393d0407baSopenharmony_ci    {0x000f, 0x07},
3403d0407baSopenharmony_ci    {0x0010, 0x8c},
3413d0407baSopenharmony_ci    {0x0013, 0x15},
3423d0407baSopenharmony_ci    {0x0019, 0x0c},
3433d0407baSopenharmony_ci    {0x0041, 0x04},
3443d0407baSopenharmony_ci    {0x0042, 0xe2},
3453d0407baSopenharmony_ci    {0x0053, 0x60},
3463d0407baSopenharmony_ci    {0x008d, 0x92},
3473d0407baSopenharmony_ci    {0x0090, 0x00},
3483d0407baSopenharmony_ci    {0x00c7, 0xe1},
3493d0407baSopenharmony_ci    {0x001b, 0x73},
3503d0407baSopenharmony_ci    {0x0028, 0x0d},
3513d0407baSopenharmony_ci    {0x0029, 0x24},
3523d0407baSopenharmony_ci    {0x002b, 0x04},
3533d0407baSopenharmony_ci    {0x002e, 0x23},
3543d0407baSopenharmony_ci    {0x0037, 0x03},
3553d0407baSopenharmony_ci    {0x0043, 0x04},
3563d0407baSopenharmony_ci    {0x0044, 0x20},
3573d0407baSopenharmony_ci    {0x004a, 0x01},
3583d0407baSopenharmony_ci    {0x004b, 0x20},
3593d0407baSopenharmony_ci    {0x0055, 0x30},
3603d0407baSopenharmony_ci    {0x006b, 0x44},
3613d0407baSopenharmony_ci    {0x0077, 0x00},
3623d0407baSopenharmony_ci    {0x0078, 0x20},
3633d0407baSopenharmony_ci    {0x007c, 0xa1},
3643d0407baSopenharmony_ci    {0x00d3, 0xd4},
3653d0407baSopenharmony_ci    {0x00e6, 0x50},
3663d0407baSopenharmony_ci    /* Gain */
3673d0407baSopenharmony_ci    {0x00b6, 0xc0},
3683d0407baSopenharmony_ci    {0x00b0, 0x60},
3693d0407baSopenharmony_ci    /* Isp */
3703d0407baSopenharmony_ci    {0x0102, 0x89},
3713d0407baSopenharmony_ci    {0x0104, 0x01},
3723d0407baSopenharmony_ci    {0x010e, 0x01},
3733d0407baSopenharmony_ci    {0x0158, 0x00},
3743d0407baSopenharmony_ci    /* Dark sun */
3753d0407baSopenharmony_ci    {0x0123, 0x08},
3763d0407baSopenharmony_ci    {0x0123, 0x00},
3773d0407baSopenharmony_ci    {0x0120, 0x01},
3783d0407baSopenharmony_ci    {0x0121, 0x00},
3793d0407baSopenharmony_ci    {0x0122, 0x10},
3803d0407baSopenharmony_ci    {0x0124, 0x03},
3813d0407baSopenharmony_ci    {0x0125, 0xff},
3823d0407baSopenharmony_ci    {0x0126, 0x3c},
3833d0407baSopenharmony_ci    {0x001a, 0x8c},
3843d0407baSopenharmony_ci    {0x00c6, 0xe0},
3853d0407baSopenharmony_ci    /* Blk */
3863d0407baSopenharmony_ci    {0x0026, 0x30},
3873d0407baSopenharmony_ci    {0x0142, 0x00},
3883d0407baSopenharmony_ci    {0x0149, 0x1e},
3893d0407baSopenharmony_ci    {0x014a, 0x0f},
3903d0407baSopenharmony_ci    {0x014b, 0x00},
3913d0407baSopenharmony_ci    {0x0155, 0x00},
3923d0407baSopenharmony_ci    {0x0414, 0x78},
3933d0407baSopenharmony_ci    {0x0415, 0x78},
3943d0407baSopenharmony_ci    {0x0416, 0x78},
3953d0407baSopenharmony_ci    {0x0417, 0x78},
3963d0407baSopenharmony_ci    {0x0454, 0x78},
3973d0407baSopenharmony_ci    {0x0455, 0x78},
3983d0407baSopenharmony_ci    {0x0456, 0x78},
3993d0407baSopenharmony_ci    {0x0457, 0x78},
4003d0407baSopenharmony_ci    {0x04e0, 0x18},
4013d0407baSopenharmony_ci    /* Window */
4023d0407baSopenharmony_ci    {0x0192, 0x02},
4033d0407baSopenharmony_ci    {0x0194, 0x03},
4043d0407baSopenharmony_ci    {0x0195, 0x04},
4053d0407baSopenharmony_ci    {0x0196, 0x38},
4063d0407baSopenharmony_ci    {0x0197, 0x07},
4073d0407baSopenharmony_ci    {0x0198, 0x80},
4083d0407baSopenharmony_ci    /* MIPI */
4093d0407baSopenharmony_ci    {0x019a, 0x06},
4103d0407baSopenharmony_ci    {0x007b, 0x2a},
4113d0407baSopenharmony_ci    {0x0023, 0x2d},
4123d0407baSopenharmony_ci    {0x0201, 0x27},
4133d0407baSopenharmony_ci    {0x0202, 0x56},
4143d0407baSopenharmony_ci    {0x0203, 0xb6},
4153d0407baSopenharmony_ci    {0x0212, 0x80},
4163d0407baSopenharmony_ci    {0x0213, 0x07},
4173d0407baSopenharmony_ci    {0x0215, 0x12},
4183d0407baSopenharmony_ci    {0x003e, 0x91},
4193d0407baSopenharmony_ci    /* HDR En */
4203d0407baSopenharmony_ci    {0x0027, 0x71},
4213d0407baSopenharmony_ci    {0x0215, 0x92},
4223d0407baSopenharmony_ci    {0x024d, 0x01},
4233d0407baSopenharmony_ci};
4243d0407baSopenharmony_ci
4253d0407baSopenharmony_cistatic const struct gc2093_mode supported_modes[] = {
4263d0407baSopenharmony_ci    {
4273d0407baSopenharmony_ci        .width = 1920,
4283d0407baSopenharmony_ci        .height = 1080,
4293d0407baSopenharmony_ci        .max_fps =
4303d0407baSopenharmony_ci            {
4313d0407baSopenharmony_ci                .numerator = 10000,
4323d0407baSopenharmony_ci                .denominator = 300000,
4333d0407baSopenharmony_ci            },
4343d0407baSopenharmony_ci        .exp_def = 0x460,
4353d0407baSopenharmony_ci        .hts_def = 0x898,
4363d0407baSopenharmony_ci        .vts_def = 0x465,
4373d0407baSopenharmony_ci        .link_freq_index = LINK_FREQ_150M_INDEX,
4383d0407baSopenharmony_ci        .reg_list = gc2093_1080p_liner_settings,
4393d0407baSopenharmony_ci        .reg_num = ARRAY_SIZE(gc2093_1080p_liner_settings),
4403d0407baSopenharmony_ci        .hdr_mode = NO_HDR,
4413d0407baSopenharmony_ci        .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
4423d0407baSopenharmony_ci    },
4433d0407baSopenharmony_ci    {
4443d0407baSopenharmony_ci        .width = 1920,
4453d0407baSopenharmony_ci        .height = 1080,
4463d0407baSopenharmony_ci        .max_fps =
4473d0407baSopenharmony_ci            {
4483d0407baSopenharmony_ci                .numerator = 10000,
4493d0407baSopenharmony_ci                .denominator = 300000,
4503d0407baSopenharmony_ci            },
4513d0407baSopenharmony_ci        .exp_def = 0x460,
4523d0407baSopenharmony_ci        .hts_def = 0xa50,
4533d0407baSopenharmony_ci        .vts_def = 0x4e2,
4543d0407baSopenharmony_ci        .link_freq_index = LINK_FREQ_300M_INDEX,
4553d0407baSopenharmony_ci        .reg_list = gc2093_1080p_hdr_settings,
4563d0407baSopenharmony_ci        .reg_num = ARRAY_SIZE(gc2093_1080p_hdr_settings),
4573d0407baSopenharmony_ci        .hdr_mode = HDR_X2,
4583d0407baSopenharmony_ci        .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1,
4593d0407baSopenharmony_ci        .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0, // L->csi wr0
4603d0407baSopenharmony_ci        .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1,
4613d0407baSopenharmony_ci        .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1, // M->csi wr2
4623d0407baSopenharmony_ci    },
4633d0407baSopenharmony_ci};
4643d0407baSopenharmony_ci
4653d0407baSopenharmony_ci/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
4663d0407baSopenharmony_ci/* * 2, to match suitable isp freq */
4673d0407baSopenharmony_cistatic u64 to_pixel_rate(u32 index)
4683d0407baSopenharmony_ci{
4693d0407baSopenharmony_ci    u64 pixel_rate = link_freq_menu_items[index] * 2 * GC2093_LANES * 2;
4703d0407baSopenharmony_ci
4713d0407baSopenharmony_ci    do_div(pixel_rate, PI_RATE_VALUE);
4723d0407baSopenharmony_ci
4733d0407baSopenharmony_ci    return pixel_rate;
4743d0407baSopenharmony_ci}
4753d0407baSopenharmony_ci
4763d0407baSopenharmony_cistatic inline int gc2093_read_reg(struct gc2093 *gc2093, u16 addr, u8 *value)
4773d0407baSopenharmony_ci{
4783d0407baSopenharmony_ci    unsigned int val;
4793d0407baSopenharmony_ci    int ret;
4803d0407baSopenharmony_ci
4813d0407baSopenharmony_ci    ret = regmap_read(gc2093->regmap, addr, &val);
4823d0407baSopenharmony_ci    if (ret) {
4833d0407baSopenharmony_ci        dev_err(gc2093->dev, "i2c read failed at addr: %x\n", addr);
4843d0407baSopenharmony_ci        return ret;
4853d0407baSopenharmony_ci    }
4863d0407baSopenharmony_ci
4873d0407baSopenharmony_ci    *value = val & 0xff;
4883d0407baSopenharmony_ci
4893d0407baSopenharmony_ci    return 0;
4903d0407baSopenharmony_ci}
4913d0407baSopenharmony_ci
4923d0407baSopenharmony_cistatic inline int gc2093_write_reg(struct gc2093 *gc2093, u16 addr, u8 value)
4933d0407baSopenharmony_ci{
4943d0407baSopenharmony_ci    int ret;
4953d0407baSopenharmony_ci
4963d0407baSopenharmony_ci    ret = regmap_write(gc2093->regmap, addr, value);
4973d0407baSopenharmony_ci    if (ret) {
4983d0407baSopenharmony_ci        dev_err(gc2093->dev, "i2c write failed at addr: %x\n", addr);
4993d0407baSopenharmony_ci        return ret;
5003d0407baSopenharmony_ci    }
5013d0407baSopenharmony_ci
5023d0407baSopenharmony_ci    return ret;
5033d0407baSopenharmony_ci}
5043d0407baSopenharmony_ci
5053d0407baSopenharmony_cistatic const struct gain_reg_config gain_reg_configs[] = {
5063d0407baSopenharmony_ci    {64, 0x0000, 0x0100, 0x6807, 0x00f8},   {75, 0x0010, 0x010c, 0x6807, 0x00f8},
5073d0407baSopenharmony_ci    {90, 0x0020, 0x011b, 0x6c08, 0x00f9},   {105, 0x0030, 0x012c, 0x6c0a, 0x00fa},
5083d0407baSopenharmony_ci    {122, 0x0040, 0x013f, 0x7c0b, 0x00fb},  {142, 0x0050, 0x0216, 0x7c0d, 0x00fe},
5093d0407baSopenharmony_ci    {167, 0x0060, 0x0235, 0x7c0e, 0x00ff},  {193, 0x0070, 0x0316, 0x7c10, 0x0801},
5103d0407baSopenharmony_ci    {223, 0x0080, 0x0402, 0x7c12, 0x0802},  {257, 0x0090, 0x0431, 0x7c13, 0x0803},
5113d0407baSopenharmony_ci    {299, 0x00a0, 0x0532, 0x7c15, 0x0805},  {346, 0x00b0, 0x0635, 0x7c17, 0x0807},
5123d0407baSopenharmony_ci    {397, 0x00c0, 0x0804, 0x7c18, 0x0808},  {444, 0x005a, 0x0919, 0x7c17, 0x0807},
5133d0407baSopenharmony_ci    {523, 0x0083, 0x0b0f, 0x7c17, 0x0807},  {607, 0x0093, 0x0d12, 0x7c19, 0x0809},
5143d0407baSopenharmony_ci    {700, 0x0084, 0x1000, 0x7c1b, 0x080c},  {817, 0x0094, 0x123a, 0x7c1e, 0x080f},
5153d0407baSopenharmony_ci    {1131, 0x005d, 0x1a02, 0x7c23, 0x0814}, {1142, 0x009b, 0x1b20, 0x7c25, 0x0816},
5163d0407baSopenharmony_ci    {1334, 0x008c, 0x200f, 0x7c27, 0x0818}, {1568, 0x009c, 0x2607, 0x7c2a, 0x081b},
5173d0407baSopenharmony_ci    {2195, 0x00b6, 0x3621, 0x7c32, 0x0823}, {2637, 0x00ad, 0x373a, 0x7c36, 0x0827},
5183d0407baSopenharmony_ci    {3121, 0x00bd, 0x3d02, 0x7c3a, 0x082b},
5193d0407baSopenharmony_ci};
5203d0407baSopenharmony_ci
5213d0407baSopenharmony_cistatic int gc2093_set_gain(struct gc2093 *gc2093, u32 gain)
5223d0407baSopenharmony_ci{
5233d0407baSopenharmony_ci    int ret, i = 0;
5243d0407baSopenharmony_ci    u16 pre_gain = 0;
5253d0407baSopenharmony_ci
5263d0407baSopenharmony_ci    for (i = 0; i < ARRAY_SIZE(gain_reg_configs) - 1; i++) {
5273d0407baSopenharmony_ci        if ((gain_reg_configs[i].value <= gain) && (gain < gain_reg_configs[i + 1].value)) {
5283d0407baSopenharmony_ci            break;
5293d0407baSopenharmony_ci        }
5303d0407baSopenharmony_ci    }
5313d0407baSopenharmony_ci
5323d0407baSopenharmony_ci    ret = gc2093_write_reg(gc2093, 0x00b4, gain_reg_configs[i].analog_gain >> PI_REG_VALUE_EI);
5333d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00b3, gain_reg_configs[i].analog_gain & 0xff);
5343d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00b8, gain_reg_configs[i].col_gain >> PI_REG_VALUE_EI);
5353d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00b9, gain_reg_configs[i].col_gain & 0xff);
5363d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00ce, gain_reg_configs[i].analog_sw >> PI_REG_VALUE_EI);
5373d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00c2, gain_reg_configs[i].analog_sw & 0xff);
5383d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00cf, gain_reg_configs[i].ram_width >> PI_REG_VALUE_EI);
5393d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00d9, gain_reg_configs[i].ram_width & 0xff);
5403d0407baSopenharmony_ci
5413d0407baSopenharmony_ci    pre_gain = PRE_GIN_COUNT * gain / gain_reg_configs[i].value;
5423d0407baSopenharmony_ci
5433d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00b1, (pre_gain >> PI_REG_VALUE_SI));
5443d0407baSopenharmony_ci    ret |= gc2093_write_reg(gc2093, 0x00b2, ((pre_gain & 0x3f) << GC2093_LANES));
5453d0407baSopenharmony_ci
5463d0407baSopenharmony_ci    return ret;
5473d0407baSopenharmony_ci}
5483d0407baSopenharmony_ci
5493d0407baSopenharmony_cistatic int gc2093_set_ctrl(struct v4l2_ctrl *ctrl)
5503d0407baSopenharmony_ci{
5513d0407baSopenharmony_ci    struct gc2093 *gc2093 = container_of(ctrl->handler, struct gc2093, ctrl_handler);
5523d0407baSopenharmony_ci    s64 max;
5533d0407baSopenharmony_ci    int ret = 0;
5543d0407baSopenharmony_ci
5553d0407baSopenharmony_ci    /* Propagate change of current control to all related controls */
5563d0407baSopenharmony_ci    switch (ctrl->id) {
5573d0407baSopenharmony_ci        case V4L2_CID_VBLANK:
5583d0407baSopenharmony_ci            /* Update max exposure while meeting expected vblanking */
5593d0407baSopenharmony_ci            max = gc2093->cur_mode->height + ctrl->val - PI_REG_VALUE_FO;
5603d0407baSopenharmony_ci            __v4l2_ctrl_modify_range(gc2093->exposure, gc2093->exposure->minimum, max, gc2093->exposure->step,
5613d0407baSopenharmony_ci                                     gc2093->exposure->default_value);
5623d0407baSopenharmony_ci            break;
5633d0407baSopenharmony_ci        default:
5643d0407baSopenharmony_ci            break;
5653d0407baSopenharmony_ci    }
5663d0407baSopenharmony_ci    if (!pm_runtime_get_if_in_use(gc2093->dev)) {
5673d0407baSopenharmony_ci        return 0;
5683d0407baSopenharmony_ci    }
5693d0407baSopenharmony_ci
5703d0407baSopenharmony_ci    switch (ctrl->id) {
5713d0407baSopenharmony_ci        case V4L2_CID_EXPOSURE:
5723d0407baSopenharmony_ci            dev_dbg(gc2093->dev, "set exposure value 0x%x\n", ctrl->val);
5733d0407baSopenharmony_ci            ret = gc2093_write_reg(gc2093, GC2093_REG_EXP_LONG_H, (ctrl->val >> PI_REG_VALUE_EI) & 0x3f);
5743d0407baSopenharmony_ci            ret |= gc2093_write_reg(gc2093, GC2093_REG_EXP_LONG_L, ctrl->val & 0xff);
5753d0407baSopenharmony_ci            break;
5763d0407baSopenharmony_ci        case V4L2_CID_ANALOGUE_GAIN:
5773d0407baSopenharmony_ci            dev_dbg(gc2093->dev, "set gain value 0x%x\n", ctrl->val);
5783d0407baSopenharmony_ci            gc2093_set_gain(gc2093, ctrl->val);
5793d0407baSopenharmony_ci            break;
5803d0407baSopenharmony_ci        case V4L2_CID_VBLANK:
5813d0407baSopenharmony_ci            /* The exposure goes up and reduces the frame rate, no need to write vb */
5823d0407baSopenharmony_ci            dev_dbg(gc2093->dev, " set blank value 0x%x\n", ctrl->val);
5833d0407baSopenharmony_ci            break;
5843d0407baSopenharmony_ci        case V4L2_CID_HFLIP:
5853d0407baSopenharmony_ci            regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG, MIRROR_MASK, ctrl->val ? MIRROR_MASK : 0);
5863d0407baSopenharmony_ci            break;
5873d0407baSopenharmony_ci        case V4L2_CID_VFLIP:
5883d0407baSopenharmony_ci            regmap_update_bits(gc2093->regmap, GC2093_MIRROR_FLIP_REG, FLIP_MASK, ctrl->val ? FLIP_MASK : 0);
5893d0407baSopenharmony_ci            break;
5903d0407baSopenharmony_ci        default:
5913d0407baSopenharmony_ci            dev_warn(gc2093->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val);
5923d0407baSopenharmony_ci            break;
5933d0407baSopenharmony_ci    }
5943d0407baSopenharmony_ci
5953d0407baSopenharmony_ci    pm_runtime_put(gc2093->dev);
5963d0407baSopenharmony_ci    return ret;
5973d0407baSopenharmony_ci}
5983d0407baSopenharmony_ci
5993d0407baSopenharmony_cistatic const struct v4l2_ctrl_ops gc2093_ctrl_ops = {
6003d0407baSopenharmony_ci    .s_ctrl = gc2093_set_ctrl,
6013d0407baSopenharmony_ci};
6023d0407baSopenharmony_ci
6033d0407baSopenharmony_cistatic int gc2093_get_regulators(struct gc2093 *gc2093)
6043d0407baSopenharmony_ci{
6053d0407baSopenharmony_ci    unsigned int i;
6063d0407baSopenharmony_ci
6073d0407baSopenharmony_ci    for (i = 0; i < GC2093_NUM_SUPPLIES; i++) {
6083d0407baSopenharmony_ci        gc2093->supplies[i].supply = gc2093_supply_names[i];
6093d0407baSopenharmony_ci    }
6103d0407baSopenharmony_ci
6113d0407baSopenharmony_ci    return devm_regulator_bulk_get(gc2093->dev, GC2093_NUM_SUPPLIES, gc2093->supplies);
6123d0407baSopenharmony_ci}
6133d0407baSopenharmony_ci
6143d0407baSopenharmony_cistatic int gc2093_initialize_controls(struct gc2093 *gc2093)
6153d0407baSopenharmony_ci{
6163d0407baSopenharmony_ci    const struct gc2093_mode *mode;
6173d0407baSopenharmony_ci    struct v4l2_ctrl_handler *handler;
6183d0407baSopenharmony_ci    s64 exposure_max, vblank_def;
6193d0407baSopenharmony_ci    u32 h_blank;
6203d0407baSopenharmony_ci    int ret;
6213d0407baSopenharmony_ci
6223d0407baSopenharmony_ci    handler = &gc2093->ctrl_handler;
6233d0407baSopenharmony_ci    mode = gc2093->cur_mode;
6243d0407baSopenharmony_ci    ret = v4l2_ctrl_handler_init(handler, PI_REG_VALUE_EI);
6253d0407baSopenharmony_ci    if (ret) {
6263d0407baSopenharmony_ci        return ret;
6273d0407baSopenharmony_ci    }
6283d0407baSopenharmony_ci    handler->lock = &gc2093->lock;
6293d0407baSopenharmony_ci
6303d0407baSopenharmony_ci    gc2093->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, ARRAY_SIZE(link_freq_menu_items) - 1,
6313d0407baSopenharmony_ci                                               0, link_freq_menu_items);
6323d0407baSopenharmony_ci    if (gc2093->link_freq) {
6333d0407baSopenharmony_ci        gc2093->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
6343d0407baSopenharmony_ci    }
6353d0407baSopenharmony_ci
6363d0407baSopenharmony_ci    gc2093->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, to_pixel_rate(LINK_FREQ_150M_INDEX),
6373d0407baSopenharmony_ci                                           1, to_pixel_rate(LINK_FREQ_150M_INDEX));
6383d0407baSopenharmony_ci
6393d0407baSopenharmony_ci    h_blank = mode->hts_def - mode->width;
6403d0407baSopenharmony_ci    gc2093->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank);
6413d0407baSopenharmony_ci    if (gc2093->hblank) {
6423d0407baSopenharmony_ci        gc2093->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
6433d0407baSopenharmony_ci    }
6443d0407baSopenharmony_ci
6453d0407baSopenharmony_ci    vblank_def = mode->vts_def - mode->height;
6463d0407baSopenharmony_ci    gc2093->vblank = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops, V4L2_CID_VBLANK, vblank_def,
6473d0407baSopenharmony_ci                                       GC2093_VTS_MAX - mode->height, 1, vblank_def);
6483d0407baSopenharmony_ci
6493d0407baSopenharmony_ci    exposure_max = mode->vts_def - PI_REG_VALUE_FO;
6503d0407baSopenharmony_ci    gc2093->exposure = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops, V4L2_CID_EXPOSURE, GC2093_EXPOSURE_MIN,
6513d0407baSopenharmony_ci                                         exposure_max, GC2093_EXPOSURE_STEP, mode->exp_def);
6523d0407baSopenharmony_ci
6533d0407baSopenharmony_ci    gc2093->anal_gain = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, GC2093_GAIN_MIN,
6543d0407baSopenharmony_ci                                          GC2093_GAIN_MAX, GC2093_GAIN_STEP, GC2093_GAIN_DEFAULT);
6553d0407baSopenharmony_ci
6563d0407baSopenharmony_ci    gc2093->h_flip = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
6573d0407baSopenharmony_ci
6583d0407baSopenharmony_ci    gc2093->v_flip = v4l2_ctrl_new_std(handler, &gc2093_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
6593d0407baSopenharmony_ci
6603d0407baSopenharmony_ci    if (handler->error) {
6613d0407baSopenharmony_ci        ret = handler->error;
6623d0407baSopenharmony_ci        dev_err(gc2093->dev, "Failed to init controls(%d)\n", ret);
6633d0407baSopenharmony_ci        goto err_free_handler;
6643d0407baSopenharmony_ci    }
6653d0407baSopenharmony_ci
6663d0407baSopenharmony_ci    gc2093->subdev.ctrl_handler = handler;
6673d0407baSopenharmony_ci    gc2093->has_init_exp = false;
6683d0407baSopenharmony_ci
6693d0407baSopenharmony_ci    return 0;
6703d0407baSopenharmony_ci
6713d0407baSopenharmony_cierr_free_handler:
6723d0407baSopenharmony_ci    v4l2_ctrl_handler_free(handler);
6733d0407baSopenharmony_ci    return ret;
6743d0407baSopenharmony_ci}
6753d0407baSopenharmony_ci
6763d0407baSopenharmony_cistatic int __gc2093_power_on(struct gc2093 *gc2093)
6773d0407baSopenharmony_ci{
6783d0407baSopenharmony_ci    int ret;
6793d0407baSopenharmony_ci    struct device *dev = gc2093->dev;
6803d0407baSopenharmony_ci
6813d0407baSopenharmony_ci    ret = clk_set_rate(gc2093->xvclk, GC2093_XVCLK_FREQ);
6823d0407baSopenharmony_ci    if (ret < 0) {
6833d0407baSopenharmony_ci        dev_warn(dev, "Failed to set xvclk rate\n");
6843d0407baSopenharmony_ci    }
6853d0407baSopenharmony_ci
6863d0407baSopenharmony_ci    if (clk_get_rate(gc2093->xvclk) != GC2093_XVCLK_FREQ) {
6873d0407baSopenharmony_ci        dev_warn(dev, "xvclk mismatched, modes are based on 27MHz\n");
6883d0407baSopenharmony_ci    }
6893d0407baSopenharmony_ci
6903d0407baSopenharmony_ci    ret = clk_prepare_enable(gc2093->xvclk);
6913d0407baSopenharmony_ci    if (ret < 0) {
6923d0407baSopenharmony_ci        dev_err(dev, "Failed to enable xvclk\n");
6933d0407baSopenharmony_ci        return ret;
6943d0407baSopenharmony_ci    }
6953d0407baSopenharmony_ci
6963d0407baSopenharmony_ci    ret = regulator_bulk_enable(GC2093_NUM_SUPPLIES, gc2093->supplies);
6973d0407baSopenharmony_ci    if (ret < 0) {
6983d0407baSopenharmony_ci        dev_err(dev, "Failed to enable regulators\n");
6993d0407baSopenharmony_ci        goto disable_clk;
7003d0407baSopenharmony_ci    }
7013d0407baSopenharmony_ci
7023d0407baSopenharmony_ci    if (!IS_ERR(gc2093->reset_gpio)) {
7033d0407baSopenharmony_ci        gpiod_set_value_cansleep(gc2093->reset_gpio, 1);
7043d0407baSopenharmony_ci    }
7053d0407baSopenharmony_ci
7063d0407baSopenharmony_ci    usleep_range(SLEEP_LOW_VALUE, SLEEP_HIGH_VALUE);
7073d0407baSopenharmony_ci
7083d0407baSopenharmony_ci    if (!IS_ERR(gc2093->pwdn_gpio)) {
7093d0407baSopenharmony_ci        gpiod_set_value_cansleep(gc2093->pwdn_gpio, 1);
7103d0407baSopenharmony_ci    }
7113d0407baSopenharmony_ci    if (!IS_ERR(gc2093->reset_gpio)) {
7123d0407baSopenharmony_ci        gpiod_set_value_cansleep(gc2093->reset_gpio, 0);
7133d0407baSopenharmony_ci    }
7143d0407baSopenharmony_ci
7153d0407baSopenharmony_ci    usleep_range(SLEEP_SLOW_VALUE, SLEEP_SHIGH_VALUE);
7163d0407baSopenharmony_ci
7173d0407baSopenharmony_ci    return 0;
7183d0407baSopenharmony_ci
7193d0407baSopenharmony_cidisable_clk:
7203d0407baSopenharmony_ci    clk_disable_unprepare(gc2093->xvclk);
7213d0407baSopenharmony_ci    return ret;
7223d0407baSopenharmony_ci}
7233d0407baSopenharmony_ci
7243d0407baSopenharmony_cistatic void __gc2093_power_off(struct gc2093 *gc2093)
7253d0407baSopenharmony_ci{
7263d0407baSopenharmony_ci    if (!IS_ERR(gc2093->reset_gpio)) {
7273d0407baSopenharmony_ci        gpiod_set_value_cansleep(gc2093->reset_gpio, 1);
7283d0407baSopenharmony_ci    }
7293d0407baSopenharmony_ci    if (!IS_ERR(gc2093->pwdn_gpio)) {
7303d0407baSopenharmony_ci        gpiod_set_value_cansleep(gc2093->pwdn_gpio, 0);
7313d0407baSopenharmony_ci    }
7323d0407baSopenharmony_ci
7333d0407baSopenharmony_ci    regulator_bulk_disable(GC2093_NUM_SUPPLIES, gc2093->supplies);
7343d0407baSopenharmony_ci    clk_disable_unprepare(gc2093->xvclk);
7353d0407baSopenharmony_ci}
7363d0407baSopenharmony_ci
7373d0407baSopenharmony_cistatic int gc2093_check_sensor_id(struct gc2093 *gc2093)
7383d0407baSopenharmony_ci{
7393d0407baSopenharmony_ci    u8 id_h = 0, id_l = 0;
7403d0407baSopenharmony_ci    u16 id = 0;
7413d0407baSopenharmony_ci    int ret = 0;
7423d0407baSopenharmony_ci
7433d0407baSopenharmony_ci    ret = gc2093_read_reg(gc2093, GC2093_REG_CHIP_ID_H, &id_h);
7443d0407baSopenharmony_ci    ret |= gc2093_read_reg(gc2093, GC2093_REG_CHIP_ID_L, &id_l);
7453d0407baSopenharmony_ci    if (ret) {
7463d0407baSopenharmony_ci        dev_err(gc2093->dev, "Failed to read sensor id, (%d)\n", ret);
7473d0407baSopenharmony_ci        return ret;
7483d0407baSopenharmony_ci    }
7493d0407baSopenharmony_ci
7503d0407baSopenharmony_ci    id = (id_h << PI_REG_VALUE_EI) | id_l;
7513d0407baSopenharmony_ci    if (id != GC2093_CHIP_ID) {
7523d0407baSopenharmony_ci        dev_err(gc2093->dev, "sensor id: %04X mismatched\n", id);
7533d0407baSopenharmony_ci        return -ENODEV;
7543d0407baSopenharmony_ci    }
7553d0407baSopenharmony_ci
7563d0407baSopenharmony_ci    dev_info(gc2093->dev, "Detected GC2093 sensor\n");
7573d0407baSopenharmony_ci    return 0;
7583d0407baSopenharmony_ci}
7593d0407baSopenharmony_ci
7603d0407baSopenharmony_cistatic void gc2093_get_module_inf(struct gc2093 *gc2093, struct rkmodule_inf *inf)
7613d0407baSopenharmony_ci{
7623d0407baSopenharmony_ci    memset(inf, 0, sizeof(*inf));
7633d0407baSopenharmony_ci    strlcpy(inf->base.lens, gc2093->len_name, sizeof(inf->base.lens));
7643d0407baSopenharmony_ci    strlcpy(inf->base.sensor, GC2093_NAME, sizeof(inf->base.sensor));
7653d0407baSopenharmony_ci    strlcpy(inf->base.module, gc2093->module_name, sizeof(inf->base.module));
7663d0407baSopenharmony_ci}
7673d0407baSopenharmony_ci
7683d0407baSopenharmony_cistatic long gc2093_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
7693d0407baSopenharmony_ci{
7703d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
7713d0407baSopenharmony_ci    struct preisp_hdrae_exp_s *hdrae_exp = arg;
7723d0407baSopenharmony_ci    struct rkmodule_hdr_cfg *hdr_cfg;
7733d0407baSopenharmony_ci    long ret = 0;
7743d0407baSopenharmony_ci    u32 i, h, w;
7753d0407baSopenharmony_ci    u32 stream = 0;
7763d0407baSopenharmony_ci    u8 vb_h = 0, vb_l = 0;
7773d0407baSopenharmony_ci    u16 vb = 0, cur_vts = 0, short_exp = 0, middle_exp = 0;
7783d0407baSopenharmony_ci
7793d0407baSopenharmony_ci    switch (cmd) {
7803d0407baSopenharmony_ci        case PREISP_CMD_SET_HDRAE_EXP:
7813d0407baSopenharmony_ci            if (!gc2093->has_init_exp && !gc2093->streaming) {
7823d0407baSopenharmony_ci                gc2093->init_hdrae_exp = *hdrae_exp;
7833d0407baSopenharmony_ci                gc2093->has_init_exp = true;
7843d0407baSopenharmony_ci                dev_info(gc2093->dev, "don't streaming, record hdrae\n");
7853d0407baSopenharmony_ci                break;
7863d0407baSopenharmony_ci            }
7873d0407baSopenharmony_ci
7883d0407baSopenharmony_ci            dev_dbg(gc2093->dev, "%s short_gain_reg: 0x%x\n", __func__, hdrae_exp->short_gain_reg);
7893d0407baSopenharmony_ci            ret = gc2093_set_gain(gc2093, hdrae_exp->short_gain_reg);
7903d0407baSopenharmony_ci            if (ret) {
7913d0407baSopenharmony_ci                dev_err(gc2093->dev, "Failed to set gain!)\n");
7923d0407baSopenharmony_ci                return ret;
7933d0407baSopenharmony_ci            }
7943d0407baSopenharmony_ci
7953d0407baSopenharmony_ci            dev_dbg(gc2093->dev, "%s exp_reg middle: 0x%x, short: 0x%x\n", __func__, hdrae_exp->middle_exp_reg,
7963d0407baSopenharmony_ci                    hdrae_exp->short_exp_reg);
7973d0407baSopenharmony_ci            // Optimize blooming effect
7983d0407baSopenharmony_ci            if (hdrae_exp->middle_exp_reg < 0x30 || hdrae_exp->short_exp_reg < PI_REG_VALUE_FO) {
7993d0407baSopenharmony_ci                gc2093_write_reg(gc2093, 0x0032, 0xfd);
8003d0407baSopenharmony_ci            } else {
8013d0407baSopenharmony_ci                gc2093_write_reg(gc2093, 0x0032, 0xf8);
8023d0407baSopenharmony_ci            }
8033d0407baSopenharmony_ci
8043d0407baSopenharmony_ci            /* hdr exp limit
8053d0407baSopenharmony_ci             * 1. max short_exp_reg  < VB
8063d0407baSopenharmony_ci             * 2. short_exp_reg + middle_exp_reg < framelength
8073d0407baSopenharmony_ci             */
8083d0407baSopenharmony_ci            /* 30FPS sample */
8093d0407baSopenharmony_ci
8103d0407baSopenharmony_ci            ret = gc2093_read_reg(gc2093, GC2093_REG_VB_H, &vb_h);
8113d0407baSopenharmony_ci            ret |= gc2093_read_reg(gc2093, GC2093_REG_VB_L, &vb_l);
8123d0407baSopenharmony_ci            if (ret) {
8133d0407baSopenharmony_ci                dev_err(gc2093->dev, "Failed to read vb data)\n");
8143d0407baSopenharmony_ci                return ret;
8153d0407baSopenharmony_ci            }
8163d0407baSopenharmony_ci            vb = (vb_h << PI_REG_VALUE_EI) | vb_l;
8173d0407baSopenharmony_ci
8183d0407baSopenharmony_ci            /* max short exposure limit to 3 ms */
8193d0407baSopenharmony_ci            if (hdrae_exp->short_exp_reg <= (vb - PI_REG_VALUE_EI)) {
8203d0407baSopenharmony_ci                short_exp = hdrae_exp->short_exp_reg;
8213d0407baSopenharmony_ci            } else {
8223d0407baSopenharmony_ci                short_exp = vb - PI_REG_VALUE_EI;
8233d0407baSopenharmony_ci            }
8243d0407baSopenharmony_ci            cur_vts = gc2093->cur_vts;
8253d0407baSopenharmony_ci            dev_info(gc2093->dev, "%s cur_vts: 0x%x\n", __func__, cur_vts);
8263d0407baSopenharmony_ci
8273d0407baSopenharmony_ci            if (short_exp + hdrae_exp->middle_exp_reg > cur_vts) {
8283d0407baSopenharmony_ci                middle_exp = cur_vts - short_exp;
8293d0407baSopenharmony_ci            } else {
8303d0407baSopenharmony_ci                middle_exp = hdrae_exp->middle_exp_reg;
8313d0407baSopenharmony_ci            }
8323d0407baSopenharmony_ci
8333d0407baSopenharmony_ci            dev_dbg(gc2093->dev, "%s cal exp_reg middle: 0x%x, short: 0x%x\n", __func__, middle_exp, short_exp);
8343d0407baSopenharmony_ci            ret |= gc2093_write_reg(gc2093, GC2093_REG_EXP_LONG_H, (middle_exp >> PI_REG_VALUE_EI) & 0x3f);
8353d0407baSopenharmony_ci            ret |= gc2093_write_reg(gc2093, GC2093_REG_EXP_LONG_L, middle_exp & 0xff);
8363d0407baSopenharmony_ci            ret |= gc2093_write_reg(gc2093, GC2093_REG_EXP_SHORT_H, (short_exp >> PI_REG_VALUE_EI) & 0x3f);
8373d0407baSopenharmony_ci            ret |= gc2093_write_reg(gc2093, GC2093_REG_EXP_SHORT_L, short_exp & 0xff);
8383d0407baSopenharmony_ci            break;
8393d0407baSopenharmony_ci        case RKMODULE_GET_HDR_CFG:
8403d0407baSopenharmony_ci            hdr_cfg = (struct rkmodule_hdr_cfg *)arg;
8413d0407baSopenharmony_ci            hdr_cfg->esp.mode = HDR_NORMAL_VC;
8423d0407baSopenharmony_ci            hdr_cfg->hdr_mode = gc2093->cur_mode->hdr_mode;
8433d0407baSopenharmony_ci            break;
8443d0407baSopenharmony_ci        case RKMODULE_SET_HDR_CFG:
8453d0407baSopenharmony_ci            hdr_cfg = (struct rkmodule_hdr_cfg *)arg;
8463d0407baSopenharmony_ci            w = gc2093->cur_mode->width;
8473d0407baSopenharmony_ci            h = gc2093->cur_mode->height;
8483d0407baSopenharmony_ci            for (i = 0; i < gc2093->cfg_num; i++) {
8493d0407baSopenharmony_ci                if (w == supported_modes[i].width && h == supported_modes[i].height &&
8503d0407baSopenharmony_ci                    supported_modes[i].hdr_mode == hdr_cfg->hdr_mode) {
8513d0407baSopenharmony_ci                    gc2093->cur_mode = &supported_modes[i];
8523d0407baSopenharmony_ci                    break;
8533d0407baSopenharmony_ci                }
8543d0407baSopenharmony_ci            }
8553d0407baSopenharmony_ci            if (i == gc2093->cfg_num) {
8563d0407baSopenharmony_ci                dev_err(gc2093->dev, "not find hdr mode:%d %dx%d config\n", hdr_cfg->hdr_mode, w, h);
8573d0407baSopenharmony_ci                ret = -EINVAL;
8583d0407baSopenharmony_ci            } else {
8593d0407baSopenharmony_ci                w = gc2093->cur_mode->hts_def - gc2093->cur_mode->width;
8603d0407baSopenharmony_ci                h = gc2093->cur_mode->vts_def - gc2093->cur_mode->height;
8613d0407baSopenharmony_ci                __v4l2_ctrl_modify_range(gc2093->hblank, w, w, 1, w);
8623d0407baSopenharmony_ci                __v4l2_ctrl_modify_range(gc2093->vblank, h, GC2093_VTS_MAX - gc2093->cur_mode->height, 1, h);
8633d0407baSopenharmony_ci                gc2093->cur_vts = gc2093->cur_mode->vts_def;
8643d0407baSopenharmony_ci                dev_info(gc2093->dev, "sensor mode: %d\n", gc2093->cur_mode->hdr_mode);
8653d0407baSopenharmony_ci            }
8663d0407baSopenharmony_ci            break;
8673d0407baSopenharmony_ci        case RKMODULE_GET_MODULE_INFO:
8683d0407baSopenharmony_ci            gc2093_get_module_inf(gc2093, (struct rkmodule_inf *)arg);
8693d0407baSopenharmony_ci            break;
8703d0407baSopenharmony_ci        case RKMODULE_SET_QUICK_STREAM:
8713d0407baSopenharmony_ci
8723d0407baSopenharmony_ci            stream = *((u32 *)arg);
8733d0407baSopenharmony_ci
8743d0407baSopenharmony_ci            if (stream) {
8753d0407baSopenharmony_ci                ret = gc2093_write_reg(gc2093, GC2093_REG_CTRL_MODE, GC2093_MODE_STREAMING);
8763d0407baSopenharmony_ci            } else {
8773d0407baSopenharmony_ci                ret = gc2093_write_reg(gc2093, GC2093_REG_CTRL_MODE, GC2093_MODE_SW_STANDBY);
8783d0407baSopenharmony_ci            }
8793d0407baSopenharmony_ci            break;
8803d0407baSopenharmony_ci        default:
8813d0407baSopenharmony_ci            ret = -ENOIOCTLCMD;
8823d0407baSopenharmony_ci            break;
8833d0407baSopenharmony_ci    }
8843d0407baSopenharmony_ci    return ret;
8853d0407baSopenharmony_ci}
8863d0407baSopenharmony_ci
8873d0407baSopenharmony_cistatic int __gc2093_start_stream(struct gc2093 *gc2093)
8883d0407baSopenharmony_ci{
8893d0407baSopenharmony_ci    int ret;
8903d0407baSopenharmony_ci
8913d0407baSopenharmony_ci    ret = regmap_multi_reg_write(gc2093->regmap, gc2093->cur_mode->reg_list, gc2093->cur_mode->reg_num);
8923d0407baSopenharmony_ci    if (ret) {
8933d0407baSopenharmony_ci        return ret;
8943d0407baSopenharmony_ci    }
8953d0407baSopenharmony_ci
8963d0407baSopenharmony_ci    /* Apply customized control from user */
8973d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
8983d0407baSopenharmony_ci    v4l2_ctrl_handler_setup(&gc2093->ctrl_handler);
8993d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
9003d0407baSopenharmony_ci
9013d0407baSopenharmony_ci    if (gc2093->has_init_exp && gc2093->cur_mode->hdr_mode != NO_HDR) {
9023d0407baSopenharmony_ci        ret = gc2093_ioctl(&gc2093->subdev, PREISP_CMD_SET_HDRAE_EXP, &gc2093->init_hdrae_exp);
9033d0407baSopenharmony_ci        if (ret) {
9043d0407baSopenharmony_ci            dev_err(gc2093->dev, "init exp fail in hdr mode\n");
9053d0407baSopenharmony_ci            return ret;
9063d0407baSopenharmony_ci        }
9073d0407baSopenharmony_ci    }
9083d0407baSopenharmony_ci
9093d0407baSopenharmony_ci    return gc2093_write_reg(gc2093, GC2093_REG_CTRL_MODE, GC2093_MODE_STREAMING);
9103d0407baSopenharmony_ci}
9113d0407baSopenharmony_ci
9123d0407baSopenharmony_cistatic int __gc2093_stop_stream(struct gc2093 *gc2093)
9133d0407baSopenharmony_ci{
9143d0407baSopenharmony_ci    gc2093->has_init_exp = false;
9153d0407baSopenharmony_ci    return gc2093_write_reg(gc2093, GC2093_REG_CTRL_MODE, GC2093_MODE_SW_STANDBY);
9163d0407baSopenharmony_ci}
9173d0407baSopenharmony_ci
9183d0407baSopenharmony_ci#ifdef CONFIG_COMPAT
9193d0407baSopenharmony_cistatic long gc2093_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg)
9203d0407baSopenharmony_ci{
9213d0407baSopenharmony_ci    void __user *up = compat_ptr(arg);
9223d0407baSopenharmony_ci    struct rkmodule_inf *inf;
9233d0407baSopenharmony_ci    struct rkmodule_hdr_cfg *hdr;
9243d0407baSopenharmony_ci    struct preisp_hdrae_exp_s *hdrae;
9253d0407baSopenharmony_ci    long ret = 0;
9263d0407baSopenharmony_ci    u32 stream = 0;
9273d0407baSopenharmony_ci
9283d0407baSopenharmony_ci    switch (cmd) {
9293d0407baSopenharmony_ci        case RKMODULE_GET_MODULE_INFO:
9303d0407baSopenharmony_ci            inf = kzalloc(sizeof(*inf), GFP_KERNEL);
9313d0407baSopenharmony_ci            if (!inf) {
9323d0407baSopenharmony_ci                ret = -ENOMEM;
9333d0407baSopenharmony_ci                return ret;
9343d0407baSopenharmony_ci            }
9353d0407baSopenharmony_ci
9363d0407baSopenharmony_ci            ret = gc2093_ioctl(sd, cmd, inf);
9373d0407baSopenharmony_ci            if (!ret) {
9383d0407baSopenharmony_ci                ret = copy_to_user(up, inf, sizeof(*inf));
9393d0407baSopenharmony_ci                if (ret) {
9403d0407baSopenharmony_ci                    ret = -EFAULT;
9413d0407baSopenharmony_ci                }
9423d0407baSopenharmony_ci            }
9433d0407baSopenharmony_ci            kfree(inf);
9443d0407baSopenharmony_ci            break;
9453d0407baSopenharmony_ci        case RKMODULE_GET_HDR_CFG:
9463d0407baSopenharmony_ci            hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
9473d0407baSopenharmony_ci            if (!hdr) {
9483d0407baSopenharmony_ci                ret = -ENOMEM;
9493d0407baSopenharmony_ci                return ret;
9503d0407baSopenharmony_ci            }
9513d0407baSopenharmony_ci
9523d0407baSopenharmony_ci            ret = gc2093_ioctl(sd, cmd, hdr);
9533d0407baSopenharmony_ci            if (!ret) {
9543d0407baSopenharmony_ci                ret = copy_to_user(up, hdr, sizeof(*hdr));
9553d0407baSopenharmony_ci                if (ret) {
9563d0407baSopenharmony_ci                    ret = -EFAULT;
9573d0407baSopenharmony_ci                }
9583d0407baSopenharmony_ci            }
9593d0407baSopenharmony_ci            kfree(hdr);
9603d0407baSopenharmony_ci            break;
9613d0407baSopenharmony_ci        case RKMODULE_SET_HDR_CFG:
9623d0407baSopenharmony_ci            hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
9633d0407baSopenharmony_ci            if (!hdr) {
9643d0407baSopenharmony_ci                ret = -ENOMEM;
9653d0407baSopenharmony_ci                return ret;
9663d0407baSopenharmony_ci            }
9673d0407baSopenharmony_ci
9683d0407baSopenharmony_ci            ret = copy_from_user(hdr, up, sizeof(*hdr));
9693d0407baSopenharmony_ci            if (!ret) {
9703d0407baSopenharmony_ci                ret = gc2093_ioctl(sd, cmd, hdr);
9713d0407baSopenharmony_ci            } else {
9723d0407baSopenharmony_ci                ret = -EFAULT;
9733d0407baSopenharmony_ci            }
9743d0407baSopenharmony_ci            kfree(hdr);
9753d0407baSopenharmony_ci            break;
9763d0407baSopenharmony_ci        case PREISP_CMD_SET_HDRAE_EXP:
9773d0407baSopenharmony_ci            hdrae = kzalloc(sizeof(*hdrae), GFP_KERNEL);
9783d0407baSopenharmony_ci            if (!hdrae) {
9793d0407baSopenharmony_ci                ret = -ENOMEM;
9803d0407baSopenharmony_ci                return ret;
9813d0407baSopenharmony_ci            }
9823d0407baSopenharmony_ci
9833d0407baSopenharmony_ci            ret = copy_from_user(hdrae, up, sizeof(*hdrae));
9843d0407baSopenharmony_ci            if (!ret) {
9853d0407baSopenharmony_ci                ret = gc2093_ioctl(sd, cmd, hdrae);
9863d0407baSopenharmony_ci            } else {
9873d0407baSopenharmony_ci                ret = -EFAULT;
9883d0407baSopenharmony_ci            }
9893d0407baSopenharmony_ci            kfree(hdrae);
9903d0407baSopenharmony_ci            break;
9913d0407baSopenharmony_ci        case RKMODULE_SET_QUICK_STREAM:
9923d0407baSopenharmony_ci            ret = copy_from_user(&stream, up, sizeof(u32));
9933d0407baSopenharmony_ci            if (!ret) {
9943d0407baSopenharmony_ci                ret = gc2093_ioctl(sd, cmd, &stream);
9953d0407baSopenharmony_ci            } else {
9963d0407baSopenharmony_ci                ret = -EFAULT;
9973d0407baSopenharmony_ci            }
9983d0407baSopenharmony_ci            break;
9993d0407baSopenharmony_ci        default:
10003d0407baSopenharmony_ci            ret = -ENOIOCTLCMD;
10013d0407baSopenharmony_ci            break;
10023d0407baSopenharmony_ci    }
10033d0407baSopenharmony_ci    return ret;
10043d0407baSopenharmony_ci}
10053d0407baSopenharmony_ci#endif
10063d0407baSopenharmony_ci
10073d0407baSopenharmony_cistatic int gc2093_s_stream(struct v4l2_subdev *sd, int on)
10083d0407baSopenharmony_ci{
10093d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
10103d0407baSopenharmony_ci    int ret = 0;
10113d0407baSopenharmony_ci    unsigned int fps;
10123d0407baSopenharmony_ci    unsigned int delay_us;
10133d0407baSopenharmony_ci
10143d0407baSopenharmony_ci    fps = DIV_ROUND_CLOSEST(gc2093->cur_mode->max_fps.denominator, gc2093->cur_mode->max_fps.numerator);
10153d0407baSopenharmony_ci
10163d0407baSopenharmony_ci    dev_info(gc2093->dev, "%s: on: %d, %dx%d@%d\n", __func__, on, gc2093->cur_mode->width, gc2093->cur_mode->height,
10173d0407baSopenharmony_ci             fps);
10183d0407baSopenharmony_ci
10193d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
10203d0407baSopenharmony_ci    on = !!on;
10213d0407baSopenharmony_ci    if (on == gc2093->streaming) {
10223d0407baSopenharmony_ci        goto unlock_and_return;
10233d0407baSopenharmony_ci    }
10243d0407baSopenharmony_ci
10253d0407baSopenharmony_ci    if (on) {
10263d0407baSopenharmony_ci        ret = pm_runtime_get_sync(gc2093->dev);
10273d0407baSopenharmony_ci        if (ret < 0) {
10283d0407baSopenharmony_ci            pm_runtime_put_noidle(gc2093->dev);
10293d0407baSopenharmony_ci            goto unlock_and_return;
10303d0407baSopenharmony_ci        }
10313d0407baSopenharmony_ci
10323d0407baSopenharmony_ci        ret = __gc2093_start_stream(gc2093);
10333d0407baSopenharmony_ci        if (ret) {
10343d0407baSopenharmony_ci            dev_err(gc2093->dev, "Failed to start gc2093 stream\n");
10353d0407baSopenharmony_ci            pm_runtime_put(gc2093->dev);
10363d0407baSopenharmony_ci            goto unlock_and_return;
10373d0407baSopenharmony_ci        }
10383d0407baSopenharmony_ci    } else {
10393d0407baSopenharmony_ci        __gc2093_stop_stream(gc2093);
10403d0407baSopenharmony_ci        /* delay to enable oneframe complete */
10413d0407baSopenharmony_ci        delay_us = SLEEP_LOW_VALUE * SLEEP_LOW_VALUE / fps;
10423d0407baSopenharmony_ci        usleep_range(delay_us, delay_us + PI_RATE_VALUE);
10433d0407baSopenharmony_ci        dev_info(gc2093->dev, "%s: on: %d, sleep(%dus)\n", __func__, on, delay_us);
10443d0407baSopenharmony_ci
10453d0407baSopenharmony_ci        pm_runtime_put(gc2093->dev);
10463d0407baSopenharmony_ci    }
10473d0407baSopenharmony_ci
10483d0407baSopenharmony_ci    gc2093->streaming = on;
10493d0407baSopenharmony_ci
10503d0407baSopenharmony_ciunlock_and_return:
10513d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
10523d0407baSopenharmony_ci    return 0;
10533d0407baSopenharmony_ci}
10543d0407baSopenharmony_ci
10553d0407baSopenharmony_cistatic int gc2093_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi)
10563d0407baSopenharmony_ci{
10573d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
10583d0407baSopenharmony_ci    const struct gc2093_mode *mode = gc2093->cur_mode;
10593d0407baSopenharmony_ci
10603d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
10613d0407baSopenharmony_ci    fi->interval = mode->max_fps;
10623d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
10633d0407baSopenharmony_ci
10643d0407baSopenharmony_ci    return 0;
10653d0407baSopenharmony_ci}
10663d0407baSopenharmony_ci
10673d0407baSopenharmony_ciint gc2093_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_config *config)
10683d0407baSopenharmony_ci{
10693d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
10703d0407baSopenharmony_ci    u32 val = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
10713d0407baSopenharmony_ci    config->flags = val;
10723d0407baSopenharmony_ci
10733d0407baSopenharmony_ci    config->type = V4L2_MBUS_CSI2_DPHY; // V4L2_MBUS_CSI2;
10743d0407baSopenharmony_ci
10753d0407baSopenharmony_ci    return 0;
10763d0407baSopenharmony_ci}
10773d0407baSopenharmony_ci
10783d0407baSopenharmony_cistatic int gc2093_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
10793d0407baSopenharmony_ci                                 struct v4l2_subdev_mbus_code_enum *code)
10803d0407baSopenharmony_ci{
10813d0407baSopenharmony_ci    if (code->index != 0) {
10823d0407baSopenharmony_ci        return -EINVAL;
10833d0407baSopenharmony_ci    }
10843d0407baSopenharmony_ci    code->code = GC2093_MEDIA_BUS_FMT;
10853d0407baSopenharmony_ci    return 0;
10863d0407baSopenharmony_ci}
10873d0407baSopenharmony_ci
10883d0407baSopenharmony_cistatic int gc2093_enum_frame_sizes(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
10893d0407baSopenharmony_ci                                   struct v4l2_subdev_frame_size_enum *fse)
10903d0407baSopenharmony_ci{
10913d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
10923d0407baSopenharmony_ci
10933d0407baSopenharmony_ci    if (fse->index >= gc2093->cfg_num) {
10943d0407baSopenharmony_ci        return -EINVAL;
10953d0407baSopenharmony_ci    }
10963d0407baSopenharmony_ci
10973d0407baSopenharmony_ci    if (fse->code != GC2093_MEDIA_BUS_FMT) {
10983d0407baSopenharmony_ci        return -EINVAL;
10993d0407baSopenharmony_ci    }
11003d0407baSopenharmony_ci
11013d0407baSopenharmony_ci    fse->min_width = supported_modes[fse->index].width;
11023d0407baSopenharmony_ci    fse->max_width = supported_modes[fse->index].width;
11033d0407baSopenharmony_ci    fse->max_height = supported_modes[fse->index].height;
11043d0407baSopenharmony_ci    fse->min_height = supported_modes[fse->index].height;
11053d0407baSopenharmony_ci    return 0;
11063d0407baSopenharmony_ci}
11073d0407baSopenharmony_ci
11083d0407baSopenharmony_cistatic int gc2093_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
11093d0407baSopenharmony_ci                                      struct v4l2_subdev_frame_interval_enum *fie)
11103d0407baSopenharmony_ci{
11113d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
11123d0407baSopenharmony_ci
11133d0407baSopenharmony_ci    if (fie->index >= gc2093->cfg_num) {
11143d0407baSopenharmony_ci        return -EINVAL;
11153d0407baSopenharmony_ci    }
11163d0407baSopenharmony_ci
11173d0407baSopenharmony_ci    fie->code = GC2093_MEDIA_BUS_FMT;
11183d0407baSopenharmony_ci    fie->width = supported_modes[fie->index].width;
11193d0407baSopenharmony_ci    fie->height = supported_modes[fie->index].height;
11203d0407baSopenharmony_ci    fie->interval = supported_modes[fie->index].max_fps;
11213d0407baSopenharmony_ci    fie->reserved[0] = supported_modes[fie->index].hdr_mode;
11223d0407baSopenharmony_ci    return 0;
11233d0407baSopenharmony_ci}
11243d0407baSopenharmony_ci
11253d0407baSopenharmony_cistatic int gc2093_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt)
11263d0407baSopenharmony_ci{
11273d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
11283d0407baSopenharmony_ci    const struct gc2093_mode *mode;
11293d0407baSopenharmony_ci    s64 h_blank, vblank_def;
11303d0407baSopenharmony_ci
11313d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
11323d0407baSopenharmony_ci
11333d0407baSopenharmony_ci    mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes), width, height, fmt->format.width,
11343d0407baSopenharmony_ci                                  fmt->format.height);
11353d0407baSopenharmony_ci
11363d0407baSopenharmony_ci    fmt->format.code = GC2093_MEDIA_BUS_FMT;
11373d0407baSopenharmony_ci    fmt->format.width = mode->width;
11383d0407baSopenharmony_ci    fmt->format.height = mode->height;
11393d0407baSopenharmony_ci    fmt->format.field = V4L2_FIELD_NONE;
11403d0407baSopenharmony_ci    if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
11413d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
11423d0407baSopenharmony_ci        *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
11433d0407baSopenharmony_ci#else
11443d0407baSopenharmony_ci        mutex_unlock(&gc2093->lock);
11453d0407baSopenharmony_ci        return -ENOTTY;
11463d0407baSopenharmony_ci#endif
11473d0407baSopenharmony_ci    } else {
11483d0407baSopenharmony_ci        gc2093->cur_mode = mode;
11493d0407baSopenharmony_ci        __v4l2_ctrl_s_ctrl(gc2093->link_freq, mode->link_freq_index);
11503d0407baSopenharmony_ci        __v4l2_ctrl_s_ctrl_int64(gc2093->pixel_rate, to_pixel_rate(mode->link_freq_index));
11513d0407baSopenharmony_ci        h_blank = mode->hts_def - mode->width;
11523d0407baSopenharmony_ci        __v4l2_ctrl_modify_range(gc2093->hblank, h_blank, h_blank, 1, h_blank);
11533d0407baSopenharmony_ci        vblank_def = mode->vts_def - mode->height;
11543d0407baSopenharmony_ci        __v4l2_ctrl_modify_range(gc2093->vblank, vblank_def, GC2093_VTS_MAX - mode->height, 1, vblank_def);
11553d0407baSopenharmony_ci    }
11563d0407baSopenharmony_ci
11573d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
11583d0407baSopenharmony_ci    return 0;
11593d0407baSopenharmony_ci}
11603d0407baSopenharmony_ci
11613d0407baSopenharmony_cistatic int gc2093_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt)
11623d0407baSopenharmony_ci{
11633d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
11643d0407baSopenharmony_ci    const struct gc2093_mode *mode = gc2093->cur_mode;
11653d0407baSopenharmony_ci
11663d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
11673d0407baSopenharmony_ci    if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
11683d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
11693d0407baSopenharmony_ci        fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
11703d0407baSopenharmony_ci#else
11713d0407baSopenharmony_ci        mutex_unlock(&gc2093->lock);
11723d0407baSopenharmony_ci        return -ENOTTY;
11733d0407baSopenharmony_ci#endif
11743d0407baSopenharmony_ci    } else {
11753d0407baSopenharmony_ci        fmt->format.width = mode->width;
11763d0407baSopenharmony_ci        fmt->format.height = mode->height;
11773d0407baSopenharmony_ci        fmt->format.code = GC2093_MEDIA_BUS_FMT;
11783d0407baSopenharmony_ci        fmt->format.field = V4L2_FIELD_NONE;
11793d0407baSopenharmony_ci    }
11803d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
11813d0407baSopenharmony_ci    return 0;
11823d0407baSopenharmony_ci}
11833d0407baSopenharmony_ci
11843d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
11853d0407baSopenharmony_cistatic int gc2093_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
11863d0407baSopenharmony_ci{
11873d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
11883d0407baSopenharmony_ci    struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
11893d0407baSopenharmony_ci    const struct gc2093_mode *def_mode = &supported_modes[0];
11903d0407baSopenharmony_ci
11913d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
11923d0407baSopenharmony_ci    /* Initialize try_fmt */
11933d0407baSopenharmony_ci    try_fmt->width = def_mode->width;
11943d0407baSopenharmony_ci    try_fmt->height = def_mode->height;
11953d0407baSopenharmony_ci    try_fmt->code = GC2093_MEDIA_BUS_FMT;
11963d0407baSopenharmony_ci    try_fmt->field = V4L2_FIELD_NONE;
11973d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
11983d0407baSopenharmony_ci
11993d0407baSopenharmony_ci    return 0;
12003d0407baSopenharmony_ci}
12013d0407baSopenharmony_ci#endif
12023d0407baSopenharmony_ci
12033d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
12043d0407baSopenharmony_cistatic const struct v4l2_subdev_internal_ops gc2093_internal_ops = {
12053d0407baSopenharmony_ci    .open = gc2093_open,
12063d0407baSopenharmony_ci};
12073d0407baSopenharmony_ci#endif
12083d0407baSopenharmony_ci
12093d0407baSopenharmony_cistatic int gc2093_s_power(struct v4l2_subdev *sd, int on)
12103d0407baSopenharmony_ci{
12113d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
12123d0407baSopenharmony_ci    int ret = 0;
12133d0407baSopenharmony_ci
12143d0407baSopenharmony_ci    mutex_lock(&gc2093->lock);
12153d0407baSopenharmony_ci
12163d0407baSopenharmony_ci    if (gc2093->power_on == !!on) {
12173d0407baSopenharmony_ci        goto unlock_and_return;
12183d0407baSopenharmony_ci    }
12193d0407baSopenharmony_ci
12203d0407baSopenharmony_ci    if (on) {
12213d0407baSopenharmony_ci        ret = pm_runtime_get_sync(gc2093->dev);
12223d0407baSopenharmony_ci        if (ret < 0) {
12233d0407baSopenharmony_ci            pm_runtime_put_noidle(gc2093->dev);
12243d0407baSopenharmony_ci            goto unlock_and_return;
12253d0407baSopenharmony_ci        }
12263d0407baSopenharmony_ci        gc2093->power_on = true;
12273d0407baSopenharmony_ci    } else {
12283d0407baSopenharmony_ci        pm_runtime_put(gc2093->dev);
12293d0407baSopenharmony_ci        gc2093->power_on = false;
12303d0407baSopenharmony_ci    }
12313d0407baSopenharmony_ci
12323d0407baSopenharmony_ciunlock_and_return:
12333d0407baSopenharmony_ci    mutex_unlock(&gc2093->lock);
12343d0407baSopenharmony_ci
12353d0407baSopenharmony_ci    return ret;
12363d0407baSopenharmony_ci}
12373d0407baSopenharmony_ci
12383d0407baSopenharmony_cistatic const struct v4l2_subdev_core_ops gc2093_core_ops = {
12393d0407baSopenharmony_ci    .s_power = gc2093_s_power,
12403d0407baSopenharmony_ci    .ioctl = gc2093_ioctl,
12413d0407baSopenharmony_ci#ifdef CONFIG_COMPAT
12423d0407baSopenharmony_ci    .compat_ioctl32 = gc2093_compat_ioctl32,
12433d0407baSopenharmony_ci#endif
12443d0407baSopenharmony_ci};
12453d0407baSopenharmony_ci
12463d0407baSopenharmony_cistatic const struct v4l2_subdev_video_ops gc2093_video_ops = {
12473d0407baSopenharmony_ci    .s_stream = gc2093_s_stream,
12483d0407baSopenharmony_ci    .g_frame_interval = gc2093_g_frame_interval,
12493d0407baSopenharmony_ci};
12503d0407baSopenharmony_ci
12513d0407baSopenharmony_cistatic const struct v4l2_subdev_pad_ops gc2093_pad_ops = {
12523d0407baSopenharmony_ci    .enum_mbus_code = gc2093_enum_mbus_code,
12533d0407baSopenharmony_ci    .enum_frame_size = gc2093_enum_frame_sizes,
12543d0407baSopenharmony_ci    .enum_frame_interval = gc2093_enum_frame_interval,
12553d0407baSopenharmony_ci    .get_fmt = gc2093_get_fmt,
12563d0407baSopenharmony_ci    .set_fmt = gc2093_set_fmt,
12573d0407baSopenharmony_ci    .get_mbus_config = gc2093_g_mbus_config,
12583d0407baSopenharmony_ci};
12593d0407baSopenharmony_ci
12603d0407baSopenharmony_cistatic const struct v4l2_subdev_ops gc2093_subdev_ops = {
12613d0407baSopenharmony_ci    .core = &gc2093_core_ops,
12623d0407baSopenharmony_ci    .video = &gc2093_video_ops,
12633d0407baSopenharmony_ci    .pad = &gc2093_pad_ops,
12643d0407baSopenharmony_ci};
12653d0407baSopenharmony_ci
12663d0407baSopenharmony_cistatic int gc2093_runtime_resume(struct device *dev)
12673d0407baSopenharmony_ci{
12683d0407baSopenharmony_ci    struct i2c_client *client = to_i2c_client(dev);
12693d0407baSopenharmony_ci    struct v4l2_subdev *sd = i2c_get_clientdata(client);
12703d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
12713d0407baSopenharmony_ci
12723d0407baSopenharmony_ci    __gc2093_power_on(gc2093);
12733d0407baSopenharmony_ci    return 0;
12743d0407baSopenharmony_ci}
12753d0407baSopenharmony_ci
12763d0407baSopenharmony_cistatic int gc2093_runtime_suspend(struct device *dev)
12773d0407baSopenharmony_ci{
12783d0407baSopenharmony_ci    struct i2c_client *client = to_i2c_client(dev);
12793d0407baSopenharmony_ci    struct v4l2_subdev *sd = i2c_get_clientdata(client);
12803d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
12813d0407baSopenharmony_ci
12823d0407baSopenharmony_ci    __gc2093_power_off(gc2093);
12833d0407baSopenharmony_ci    return 0;
12843d0407baSopenharmony_ci}
12853d0407baSopenharmony_ci
12863d0407baSopenharmony_cistatic const struct dev_pm_ops gc2093_pm_ops = {
12873d0407baSopenharmony_ci    SET_RUNTIME_PM_OPS(gc2093_runtime_suspend, gc2093_runtime_resume, NULL)};
12883d0407baSopenharmony_ci
12893d0407baSopenharmony_cistatic int gc2093_probe(struct i2c_client *client, const struct i2c_device_id *id)
12903d0407baSopenharmony_ci{
12913d0407baSopenharmony_ci    struct device *dev = &client->dev;
12923d0407baSopenharmony_ci    struct device_node *node = dev->of_node;
12933d0407baSopenharmony_ci    struct gc2093 *gc2093;
12943d0407baSopenharmony_ci    struct v4l2_subdev *sd;
12953d0407baSopenharmony_ci    char facing[2];
12963d0407baSopenharmony_ci    int ret;
12973d0407baSopenharmony_ci
12983d0407baSopenharmony_ci    dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> PI_OFFSET_VALUE,
12993d0407baSopenharmony_ci             (DRIVER_VERSION & 0xff00) >> PI_REG_VALUE_EI, DRIVER_VERSION & 0x00ff);
13003d0407baSopenharmony_ci
13013d0407baSopenharmony_ci    gc2093 = devm_kzalloc(dev, sizeof(*gc2093), GFP_KERNEL);
13023d0407baSopenharmony_ci    if (!gc2093) {
13033d0407baSopenharmony_ci        return -ENOMEM;
13043d0407baSopenharmony_ci    }
13053d0407baSopenharmony_ci
13063d0407baSopenharmony_ci    gc2093->dev = dev;
13073d0407baSopenharmony_ci    gc2093->regmap = devm_regmap_init_i2c(client, &gc2093_regmap_config);
13083d0407baSopenharmony_ci    if (IS_ERR(gc2093->regmap)) {
13093d0407baSopenharmony_ci        dev_err(dev, "Failed to initialize I2C\n");
13103d0407baSopenharmony_ci        return -ENODEV;
13113d0407baSopenharmony_ci    }
13123d0407baSopenharmony_ci
13133d0407baSopenharmony_ci    ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, &gc2093->module_index);
13143d0407baSopenharmony_ci    ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, &gc2093->module_facing);
13153d0407baSopenharmony_ci    ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, &gc2093->module_name);
13163d0407baSopenharmony_ci    ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, &gc2093->len_name);
13173d0407baSopenharmony_ci    if (ret) {
13183d0407baSopenharmony_ci        dev_err(dev, "Failed to get module information\n");
13193d0407baSopenharmony_ci        return -EINVAL;
13203d0407baSopenharmony_ci    }
13213d0407baSopenharmony_ci
13223d0407baSopenharmony_ci    gc2093->xvclk = devm_clk_get(gc2093->dev, "xvclk");
13233d0407baSopenharmony_ci    if (IS_ERR(gc2093->xvclk)) {
13243d0407baSopenharmony_ci        dev_err(gc2093->dev, "Failed to get xvclk\n");
13253d0407baSopenharmony_ci        return -EINVAL;
13263d0407baSopenharmony_ci    }
13273d0407baSopenharmony_ci
13283d0407baSopenharmony_ci    gc2093->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
13293d0407baSopenharmony_ci    if (IS_ERR(gc2093->reset_gpio)) {
13303d0407baSopenharmony_ci        dev_warn(dev, "Failed to get reset-gpios\n");
13313d0407baSopenharmony_ci    }
13323d0407baSopenharmony_ci
13333d0407baSopenharmony_ci    gc2093->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_HIGH);
13343d0407baSopenharmony_ci    if (IS_ERR(gc2093->pwdn_gpio)) {
13353d0407baSopenharmony_ci        dev_warn(dev, "Failed to get pwdn-gpios\n");
13363d0407baSopenharmony_ci    }
13373d0407baSopenharmony_ci
13383d0407baSopenharmony_ci    ret = gc2093_get_regulators(gc2093);
13393d0407baSopenharmony_ci    if (ret) {
13403d0407baSopenharmony_ci        dev_err(dev, "Failed to get regulators\n");
13413d0407baSopenharmony_ci        return ret;
13423d0407baSopenharmony_ci    }
13433d0407baSopenharmony_ci
13443d0407baSopenharmony_ci    mutex_init(&gc2093->lock);
13453d0407baSopenharmony_ci
13463d0407baSopenharmony_ci    /* set default mode */
13473d0407baSopenharmony_ci    gc2093->cur_mode = &supported_modes[0];
13483d0407baSopenharmony_ci    gc2093->cfg_num = ARRAY_SIZE(supported_modes);
13493d0407baSopenharmony_ci    gc2093->cur_vts = gc2093->cur_mode->vts_def;
13503d0407baSopenharmony_ci
13513d0407baSopenharmony_ci    sd = &gc2093->subdev;
13523d0407baSopenharmony_ci    v4l2_i2c_subdev_init(sd, client, &gc2093_subdev_ops);
13533d0407baSopenharmony_ci    ret = gc2093_initialize_controls(gc2093);
13543d0407baSopenharmony_ci    if (ret) {
13553d0407baSopenharmony_ci        goto err_destroy_mutex;
13563d0407baSopenharmony_ci    }
13573d0407baSopenharmony_ci
13583d0407baSopenharmony_ci    ret = __gc2093_power_on(gc2093);
13593d0407baSopenharmony_ci    if (ret) {
13603d0407baSopenharmony_ci        goto err_free_handler;
13613d0407baSopenharmony_ci    }
13623d0407baSopenharmony_ci
13633d0407baSopenharmony_ci    ret = gc2093_check_sensor_id(gc2093);
13643d0407baSopenharmony_ci    if (ret) {
13653d0407baSopenharmony_ci        goto err_power_off;
13663d0407baSopenharmony_ci    }
13673d0407baSopenharmony_ci
13683d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
13693d0407baSopenharmony_ci    sd->internal_ops = &gc2093_internal_ops;
13703d0407baSopenharmony_ci    sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
13713d0407baSopenharmony_ci#endif
13723d0407baSopenharmony_ci
13733d0407baSopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
13743d0407baSopenharmony_ci    gc2093->pad.flags = MEDIA_PAD_FL_SOURCE;
13753d0407baSopenharmony_ci    sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
13763d0407baSopenharmony_ci    ret = media_entity_pads_init(&sd->entity, 1, &gc2093->pad);
13773d0407baSopenharmony_ci    if (ret < 0) {
13783d0407baSopenharmony_ci        goto err_power_off;
13793d0407baSopenharmony_ci    }
13803d0407baSopenharmony_ci#endif
13813d0407baSopenharmony_ci
13823d0407baSopenharmony_ci    memset(facing, 0, sizeof(facing));
13833d0407baSopenharmony_ci    if (strcmp(gc2093->module_facing, "back") == 0) {
13843d0407baSopenharmony_ci        facing[0] = 'b';
13853d0407baSopenharmony_ci    } else {
13863d0407baSopenharmony_ci        facing[0] = 'f';
13873d0407baSopenharmony_ci    }
13883d0407baSopenharmony_ci
13893d0407baSopenharmony_ci    snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", gc2093->module_index, facing, GC2093_NAME,
13903d0407baSopenharmony_ci             dev_name(sd->dev));
13913d0407baSopenharmony_ci
13923d0407baSopenharmony_ci    ret = v4l2_async_register_subdev_sensor_common(sd);
13933d0407baSopenharmony_ci    if (ret) {
13943d0407baSopenharmony_ci        dev_err(dev, "Failed to register v4l2 async subdev\n");
13953d0407baSopenharmony_ci        goto err_clean_entity;
13963d0407baSopenharmony_ci    }
13973d0407baSopenharmony_ci
13983d0407baSopenharmony_ci    pm_runtime_set_active(dev);
13993d0407baSopenharmony_ci    pm_runtime_enable(dev);
14003d0407baSopenharmony_ci    pm_runtime_idle(dev);
14013d0407baSopenharmony_ci
14023d0407baSopenharmony_ci    return 0;
14033d0407baSopenharmony_ci
14043d0407baSopenharmony_cierr_clean_entity:
14053d0407baSopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
14063d0407baSopenharmony_ci    media_entity_cleanup(&sd->entity);
14073d0407baSopenharmony_ci#endif
14083d0407baSopenharmony_cierr_power_off:
14093d0407baSopenharmony_ci    __gc2093_power_off(gc2093);
14103d0407baSopenharmony_cierr_free_handler:
14113d0407baSopenharmony_ci    v4l2_ctrl_handler_free(&gc2093->ctrl_handler);
14123d0407baSopenharmony_cierr_destroy_mutex:
14133d0407baSopenharmony_ci    mutex_destroy(&gc2093->lock);
14143d0407baSopenharmony_ci
14153d0407baSopenharmony_ci    return ret;
14163d0407baSopenharmony_ci}
14173d0407baSopenharmony_ci
14183d0407baSopenharmony_cistatic int gc2093_remove(struct i2c_client *client)
14193d0407baSopenharmony_ci{
14203d0407baSopenharmony_ci    struct v4l2_subdev *sd = i2c_get_clientdata(client);
14213d0407baSopenharmony_ci    struct gc2093 *gc2093 = to_gc2093(sd);
14223d0407baSopenharmony_ci
14233d0407baSopenharmony_ci    v4l2_async_unregister_subdev(sd);
14243d0407baSopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
14253d0407baSopenharmony_ci    media_entity_cleanup(&sd->entity);
14263d0407baSopenharmony_ci#endif
14273d0407baSopenharmony_ci    v4l2_ctrl_handler_free(&gc2093->ctrl_handler);
14283d0407baSopenharmony_ci    mutex_destroy(&gc2093->lock);
14293d0407baSopenharmony_ci
14303d0407baSopenharmony_ci    pm_runtime_disable(&client->dev);
14313d0407baSopenharmony_ci    if (!pm_runtime_status_suspended(&client->dev)) {
14323d0407baSopenharmony_ci        __gc2093_power_off(gc2093);
14333d0407baSopenharmony_ci    }
14343d0407baSopenharmony_ci    pm_runtime_set_suspended(&client->dev);
14353d0407baSopenharmony_ci    return 0;
14363d0407baSopenharmony_ci}
14373d0407baSopenharmony_ci
14383d0407baSopenharmony_cistatic const struct i2c_device_id gc2093_match_id[] = {
14393d0407baSopenharmony_ci    {"gc2093", 0},
14403d0407baSopenharmony_ci    {},
14413d0407baSopenharmony_ci};
14423d0407baSopenharmony_ci
14433d0407baSopenharmony_cistatic const struct of_device_id gc2093_of_match[] = {
14443d0407baSopenharmony_ci    {.compatible = "galaxycore,gc2093"},
14453d0407baSopenharmony_ci    {},
14463d0407baSopenharmony_ci};
14473d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, gc2093_of_match);
14483d0407baSopenharmony_ci
14493d0407baSopenharmony_cistatic struct i2c_driver gc2093_i2c_driver = {
14503d0407baSopenharmony_ci    .driver =
14513d0407baSopenharmony_ci        {
14523d0407baSopenharmony_ci            .name = GC2093_NAME,
14533d0407baSopenharmony_ci            .pm = &gc2093_pm_ops,
14543d0407baSopenharmony_ci            .of_match_table = of_match_ptr(gc2093_of_match),
14553d0407baSopenharmony_ci        },
14563d0407baSopenharmony_ci    .probe = &gc2093_probe,
14573d0407baSopenharmony_ci    .remove = &gc2093_remove,
14583d0407baSopenharmony_ci    .id_table = gc2093_match_id,
14593d0407baSopenharmony_ci};
14603d0407baSopenharmony_ci
14613d0407baSopenharmony_cistatic int __init sensor_mod_init(void)
14623d0407baSopenharmony_ci{
14633d0407baSopenharmony_ci    return i2c_add_driver(&gc2093_i2c_driver);
14643d0407baSopenharmony_ci}
14653d0407baSopenharmony_cistatic void __exit sensor_mod_exit(void)
14663d0407baSopenharmony_ci{
14673d0407baSopenharmony_ci    i2c_del_driver(&gc2093_i2c_driver);
14683d0407baSopenharmony_ci}
14693d0407baSopenharmony_ci
14703d0407baSopenharmony_cidevice_initcall_sync(sensor_mod_init);
14713d0407baSopenharmony_cimodule_exit(sensor_mod_exit);
14723d0407baSopenharmony_ci
14733d0407baSopenharmony_ciMODULE_DESCRIPTION("Galaxycore GC2093 Image Sensor driver");
14743d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
1475