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