File Index
Files and directories
Sign in
FILE

gc08a3.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/i2c/gc08a3.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for GalaxyCore gc08a3 image sensor
   4 *
   5 * Copyright 2024 MediaTek
   6 *
   7 * Zhi Mao <zhi.mao@mediatek.com>
   8 */
   9#include <linux/array_size.h>
  10#include <linux/bits.h>
  11#include <linux/clk.h>
  12#include <linux/container_of.h>
  13#include <linux/delay.h>
  14#include <linux/device.h>
  15#include <linux/err.h>
  16#include <linux/gpio/consumer.h>
  17#include <linux/math64.h>
  18#include <linux/mod_devicetable.h>
  19#include <linux/pm_runtime.h>
  20#include <linux/property.h>
  21#include <linux/regulator/consumer.h>
  22#include <linux/types.h>
  23#include <linux/units.h>
  24
  25#include <media/v4l2-cci.h>
  26#include <media/v4l2-ctrls.h>
  27#include <media/v4l2-fwnode.h>
  28#include <media/v4l2-subdev.h>
  29
  30#define GC08A3_REG_TEST_PATTERN_EN CCI_REG8(0x008c)
  31#define GC08A3_REG_TEST_PATTERN_IDX CCI_REG8(0x008d)
  32#define GC08A3_TEST_PATTERN_EN 0x01
  33
  34#define GC08A3_STREAMING_REG CCI_REG8(0x0100)
  35
  36#define GC08A3_FLIP_REG CCI_REG8(0x0101)
  37#define GC08A3_FLIP_H_MASK BIT(0)
  38#define GC08A3_FLIP_V_MASK BIT(1)
  39
  40#define GC08A3_EXP_REG CCI_REG16(0x0202)
  41#define GC08A3_EXP_MARGIN 16
  42#define GC08A3_EXP_MIN 4
  43#define GC08A3_EXP_STEP 1
  44
  45#define GC08A3_AGAIN_REG CCI_REG16(0x0204)
  46#define GC08A3_AGAIN_MIN 1024
  47#define GC08A3_AGAIN_MAX (1024 * 16)
  48#define GC08A3_AGAIN_STEP 1
  49
  50#define GC08A3_FRAME_LENGTH_REG CCI_REG16(0x0340)
  51#define GC08A3_VTS_MAX 0xfff0
  52
  53#define GC08A3_REG_CHIP_ID CCI_REG16(0x03f0)
  54#define GC08A3_CHIP_ID 0x08a3
  55
  56#define GC08A3_NATIVE_WIDTH 3264
  57#define GC08A3_NATIVE_HEIGHT 2448
  58
  59#define GC08A3_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ)
  60#define GC08A3_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
  61#define GC08A3_DATA_LANES 4
  62
  63#define GC08A3_RGB_DEPTH 10
  64
  65#define GC08A3_SLEEP_US  (2 * USEC_PER_MSEC)
  66
  67static const char *const gc08a3_test_pattern_menu[] = {
  68	"No Pattern", "Solid Black", "Colour Bar", "Solid White",
  69	"Solid Red", "Solid Green", "Solid Blue", "Solid Yellow",
  70};
  71
  72static const s64 gc08a3_link_freq_menu_items[] = {
  73	(336 * HZ_PER_MHZ),
  74	(207 * HZ_PER_MHZ),
  75};
  76
  77static const char *const gc08a3_supply_name[] = {
  78	"avdd",
  79	"dvdd",
  80	"dovdd",
  81};
  82
  83struct gc08a3 {
  84	struct device *dev;
  85	struct v4l2_subdev sd;
  86	struct media_pad pad;
  87
  88	struct clk *xclk;
  89	struct regulator_bulk_data supplies[ARRAY_SIZE(gc08a3_supply_name)];
  90	struct gpio_desc *reset_gpio;
  91
  92	struct v4l2_ctrl_handler ctrls;
  93	struct v4l2_ctrl *pixel_rate;
  94	struct v4l2_ctrl *link_freq;
  95	struct v4l2_ctrl *exposure;
  96	struct v4l2_ctrl *vblank;
  97	struct v4l2_ctrl *hblank;
  98	struct v4l2_ctrl *hflip;
  99	struct v4l2_ctrl *vflip;
 100
 101	struct regmap *regmap;
 102	unsigned long link_freq_bitmap;
 103	const struct gc08a3_mode *cur_mode;
 104};
 105
 106struct gc08a3_reg_list {
 107	u32 num_of_regs;
 108	const struct cci_reg_sequence *regs;
 109};
 110
 111static const struct cci_reg_sequence mode_3264x2448[] = {
 112	/* system */
 113	{ CCI_REG8(0x0336), 0x70 },
 114	{ CCI_REG8(0x0383), 0xbb },
 115	{ CCI_REG8(0x0344), 0x00 },
 116	{ CCI_REG8(0x0345), 0x06 },
 117	{ CCI_REG8(0x0346), 0x00 },
 118	{ CCI_REG8(0x0347), 0x04 },
 119	{ CCI_REG8(0x0348), 0x0c },
 120	{ CCI_REG8(0x0349), 0xd0 },
 121	{ CCI_REG8(0x034a), 0x09 },
 122	{ CCI_REG8(0x034b), 0x9c },
 123	{ CCI_REG8(0x0202), 0x09 },
 124	{ CCI_REG8(0x0203), 0x04 },
 125	{ CCI_REG8(0x0340), 0x09 },
 126	{ CCI_REG8(0x0341), 0xf4 },
 127	{ CCI_REG8(0x0342), 0x07 },
 128	{ CCI_REG8(0x0343), 0x1c },
 129
 130	{ CCI_REG8(0x0226), 0x00 },
 131	{ CCI_REG8(0x0227), 0x28 },
 132	{ CCI_REG8(0x0e38), 0x49 },
 133	{ CCI_REG8(0x0210), 0x13 },
 134	{ CCI_REG8(0x0218), 0x00 },
 135	{ CCI_REG8(0x0241), 0x88 },
 136	{ CCI_REG8(0x0392), 0x60 },
 137
 138	/* ISP */
 139	{ CCI_REG8(0x00a2), 0x00 },
 140	{ CCI_REG8(0x00a3), 0x00 },
 141	{ CCI_REG8(0x00ab), 0x00 },
 142	{ CCI_REG8(0x00ac), 0x00 },
 143
 144	/* GAIN */
 145	{ CCI_REG8(0x0204), 0x04 },
 146	{ CCI_REG8(0x0205), 0x00 },
 147	{ CCI_REG8(0x0050), 0x5c },
 148	{ CCI_REG8(0x0051), 0x44 },
 149
 150	/* out window */
 151	{ CCI_REG8(0x009a), 0x66 },
 152	{ CCI_REG8(0x0351), 0x00 },
 153	{ CCI_REG8(0x0352), 0x06 },
 154	{ CCI_REG8(0x0353), 0x00 },
 155	{ CCI_REG8(0x0354), 0x08 },
 156	{ CCI_REG8(0x034c), 0x0c },
 157	{ CCI_REG8(0x034d), 0xc0 },
 158	{ CCI_REG8(0x034e), 0x09 },
 159	{ CCI_REG8(0x034f), 0x90 },
 160
 161	/* MIPI */
 162	{ CCI_REG8(0x0114), 0x03 },
 163	{ CCI_REG8(0x0180), 0x65 },
 164	{ CCI_REG8(0x0181), 0xf0 },
 165	{ CCI_REG8(0x0185), 0x01 },
 166	{ CCI_REG8(0x0115), 0x30 },
 167	{ CCI_REG8(0x011b), 0x12 },
 168	{ CCI_REG8(0x011c), 0x12 },
 169	{ CCI_REG8(0x0121), 0x06 },
 170	{ CCI_REG8(0x0122), 0x06 },
 171	{ CCI_REG8(0x0123), 0x15 },
 172	{ CCI_REG8(0x0124), 0x01 },
 173	{ CCI_REG8(0x0125), 0x0b },
 174	{ CCI_REG8(0x0126), 0x08 },
 175	{ CCI_REG8(0x0129), 0x06 },
 176	{ CCI_REG8(0x012a), 0x08 },
 177	{ CCI_REG8(0x012b), 0x08 },
 178
 179	{ CCI_REG8(0x0a73), 0x60 },
 180	{ CCI_REG8(0x0a70), 0x11 },
 181	{ CCI_REG8(0x0313), 0x80 },
 182	{ CCI_REG8(0x0aff), 0x00 },
 183	{ CCI_REG8(0x0a70), 0x00 },
 184	{ CCI_REG8(0x00a4), 0x80 },
 185	{ CCI_REG8(0x0316), 0x01 },
 186	{ CCI_REG8(0x0a67), 0x00 },
 187	{ CCI_REG8(0x0084), 0x10 },
 188	{ CCI_REG8(0x0102), 0x09 },
 189};
 190
 191static const struct cci_reg_sequence mode_1920x1080[] = {
 192	/* system */
 193	{ CCI_REG8(0x0336), 0x45 },
 194	{ CCI_REG8(0x0383), 0x8b },
 195	{ CCI_REG8(0x0344), 0x02 },
 196	{ CCI_REG8(0x0345), 0xa6 },
 197	{ CCI_REG8(0x0346), 0x02 },
 198	{ CCI_REG8(0x0347), 0xb0 },
 199	{ CCI_REG8(0x0348), 0x07 },
 200	{ CCI_REG8(0x0349), 0x90 },
 201	{ CCI_REG8(0x034a), 0x04 },
 202	{ CCI_REG8(0x034b), 0x44 },
 203	{ CCI_REG8(0x0202), 0x03 },
 204	{ CCI_REG8(0x0203), 0x00 },
 205	{ CCI_REG8(0x0340), 0x04 },
 206	{ CCI_REG8(0x0341), 0xfc },
 207	{ CCI_REG8(0x0342), 0x07 },
 208	{ CCI_REG8(0x0343), 0x1c },
 209	{ CCI_REG8(0x0226), 0x00 },
 210	{ CCI_REG8(0x0227), 0x88 },
 211	{ CCI_REG8(0x0e38), 0x49 },
 212	{ CCI_REG8(0x0210), 0x13 },
 213	{ CCI_REG8(0x0218), 0x00 },
 214	{ CCI_REG8(0x0241), 0x88 },
 215	{ CCI_REG8(0x0392), 0x60 },
 216
 217	/* ISP */
 218	{ CCI_REG8(0x00a2), 0xac },
 219	{ CCI_REG8(0x00a3), 0x02 },
 220	{ CCI_REG8(0x00ab), 0xa0 },
 221	{ CCI_REG8(0x00ac), 0x02 },
 222
 223	/* GAIN */
 224	{ CCI_REG8(0x0204), 0x04 },
 225	{ CCI_REG8(0x0205), 0x00 },
 226	{ CCI_REG8(0x0050), 0x38 },
 227	{ CCI_REG8(0x0051), 0x20 },
 228
 229	/* out window */
 230	{ CCI_REG8(0x009a), 0x66 },
 231	{ CCI_REG8(0x0351), 0x00 },
 232	{ CCI_REG8(0x0352), 0x06 },
 233	{ CCI_REG8(0x0353), 0x00 },
 234	{ CCI_REG8(0x0354), 0x08 },
 235	{ CCI_REG8(0x034c), 0x07 },
 236	{ CCI_REG8(0x034d), 0x80 },
 237	{ CCI_REG8(0x034e), 0x04 },
 238	{ CCI_REG8(0x034f), 0x38 },
 239
 240	/* MIPI */
 241	{ CCI_REG8(0x0114), 0x03 },
 242	{ CCI_REG8(0x0180), 0x65 },
 243	{ CCI_REG8(0x0181), 0xf0 },
 244	{ CCI_REG8(0x0185), 0x01 },
 245	{ CCI_REG8(0x0115), 0x30 },
 246	{ CCI_REG8(0x011b), 0x12 },
 247	{ CCI_REG8(0x011c), 0x12 },
 248	{ CCI_REG8(0x0121), 0x02 },
 249	{ CCI_REG8(0x0122), 0x03 },
 250	{ CCI_REG8(0x0123), 0x0c },
 251	{ CCI_REG8(0x0124), 0x00 },
 252	{ CCI_REG8(0x0125), 0x09 },
 253	{ CCI_REG8(0x0126), 0x06 },
 254	{ CCI_REG8(0x0129), 0x04 },
 255	{ CCI_REG8(0x012a), 0x03 },
 256	{ CCI_REG8(0x012b), 0x06 },
 257
 258	{ CCI_REG8(0x0a73), 0x60 },
 259	{ CCI_REG8(0x0a70), 0x11 },
 260	{ CCI_REG8(0x0313), 0x80 },
 261	{ CCI_REG8(0x0aff), 0x00 },
 262	{ CCI_REG8(0x0a70), 0x00 },
 263	{ CCI_REG8(0x00a4), 0x80 },
 264	{ CCI_REG8(0x0316), 0x01 },
 265	{ CCI_REG8(0x0a67), 0x00 },
 266	{ CCI_REG8(0x0084), 0x10 },
 267	{ CCI_REG8(0x0102), 0x09 },
 268};
 269
 270static const struct cci_reg_sequence mode_table_common[] = {
 271	{ GC08A3_STREAMING_REG, 0x00 },
 272	/* system */
 273	{ CCI_REG8(0x031c), 0x60 },
 274	{ CCI_REG8(0x0337), 0x04 },
 275	{ CCI_REG8(0x0335), 0x51 },
 276	{ CCI_REG8(0x0336), 0x70 },
 277	{ CCI_REG8(0x0383), 0xbb },
 278	{ CCI_REG8(0x031a), 0x00 },
 279	{ CCI_REG8(0x0321), 0x10 },
 280	{ CCI_REG8(0x0327), 0x03 },
 281	{ CCI_REG8(0x0325), 0x40 },
 282	{ CCI_REG8(0x0326), 0x23 },
 283	{ CCI_REG8(0x0314), 0x11 },
 284	{ CCI_REG8(0x0315), 0xd6 },
 285	{ CCI_REG8(0x0316), 0x01 },
 286	{ CCI_REG8(0x0334), 0x40 },
 287	{ CCI_REG8(0x0324), 0x42 },
 288	{ CCI_REG8(0x031c), 0x00 },
 289	{ CCI_REG8(0x031c), 0x9f },
 290	{ CCI_REG8(0x039a), 0x13 },
 291	{ CCI_REG8(0x0084), 0x30 },
 292	{ CCI_REG8(0x02b3), 0x08 },
 293	{ CCI_REG8(0x0057), 0x0c },
 294	{ CCI_REG8(0x05c3), 0x50 },
 295	{ CCI_REG8(0x0311), 0x90 },
 296	{ CCI_REG8(0x05a0), 0x02 },
 297	{ CCI_REG8(0x0074), 0x0a },
 298	{ CCI_REG8(0x0059), 0x11 },
 299	{ CCI_REG8(0x0070), 0x05 },
 300	{ CCI_REG8(0x0101), 0x00 },
 301
 302	/* analog */
 303	{ CCI_REG8(0x0344), 0x00 },
 304	{ CCI_REG8(0x0345), 0x06 },
 305	{ CCI_REG8(0x0346), 0x00 },
 306	{ CCI_REG8(0x0347), 0x04 },
 307	{ CCI_REG8(0x0348), 0x0c },
 308	{ CCI_REG8(0x0349), 0xd0 },
 309	{ CCI_REG8(0x034a), 0x09 },
 310	{ CCI_REG8(0x034b), 0x9c },
 311	{ CCI_REG8(0x0202), 0x09 },
 312	{ CCI_REG8(0x0203), 0x04 },
 313
 314	{ CCI_REG8(0x0219), 0x05 },
 315	{ CCI_REG8(0x0226), 0x00 },
 316	{ CCI_REG8(0x0227), 0x28 },
 317	{ CCI_REG8(0x0e0a), 0x00 },
 318	{ CCI_REG8(0x0e0b), 0x00 },
 319	{ CCI_REG8(0x0e24), 0x04 },
 320	{ CCI_REG8(0x0e25), 0x04 },
 321	{ CCI_REG8(0x0e26), 0x00 },
 322	{ CCI_REG8(0x0e27), 0x10 },
 323	{ CCI_REG8(0x0e01), 0x74 },
 324	{ CCI_REG8(0x0e03), 0x47 },
 325	{ CCI_REG8(0x0e04), 0x33 },
 326	{ CCI_REG8(0x0e05), 0x44 },
 327	{ CCI_REG8(0x0e06), 0x44 },
 328	{ CCI_REG8(0x0e0c), 0x1e },
 329	{ CCI_REG8(0x0e17), 0x3a },
 330	{ CCI_REG8(0x0e18), 0x3c },
 331	{ CCI_REG8(0x0e19), 0x40 },
 332	{ CCI_REG8(0x0e1a), 0x42 },
 333	{ CCI_REG8(0x0e28), 0x21 },
 334	{ CCI_REG8(0x0e2b), 0x68 },
 335	{ CCI_REG8(0x0e2c), 0x0d },
 336	{ CCI_REG8(0x0e2d), 0x08 },
 337	{ CCI_REG8(0x0e34), 0xf4 },
 338	{ CCI_REG8(0x0e35), 0x44 },
 339	{ CCI_REG8(0x0e36), 0x07 },
 340	{ CCI_REG8(0x0e38), 0x49 },
 341	{ CCI_REG8(0x0210), 0x13 },
 342	{ CCI_REG8(0x0218), 0x00 },
 343	{ CCI_REG8(0x0241), 0x88 },
 344	{ CCI_REG8(0x0e32), 0x00 },
 345	{ CCI_REG8(0x0e33), 0x18 },
 346	{ CCI_REG8(0x0e42), 0x03 },
 347	{ CCI_REG8(0x0e43), 0x80 },
 348	{ CCI_REG8(0x0e44), 0x04 },
 349	{ CCI_REG8(0x0e45), 0x00 },
 350	{ CCI_REG8(0x0e4f), 0x04 },
 351	{ CCI_REG8(0x057a), 0x20 },
 352	{ CCI_REG8(0x0381), 0x7c },
 353	{ CCI_REG8(0x0382), 0x9b },
 354	{ CCI_REG8(0x0384), 0xfb },
 355	{ CCI_REG8(0x0389), 0x38 },
 356	{ CCI_REG8(0x038a), 0x03 },
 357	{ CCI_REG8(0x0390), 0x6a },
 358	{ CCI_REG8(0x0391), 0x0b },
 359	{ CCI_REG8(0x0392), 0x60 },
 360	{ CCI_REG8(0x0393), 0xc1 },
 361	{ CCI_REG8(0x0396), 0xff },
 362	{ CCI_REG8(0x0398), 0x62 },
 363
 364	/* cisctl reset */
 365	{ CCI_REG8(0x031c), 0x80 },
 366	{ CCI_REG8(0x03fe), 0x10 },
 367	{ CCI_REG8(0x03fe), 0x00 },
 368	{ CCI_REG8(0x031c), 0x9f },
 369	{ CCI_REG8(0x03fe), 0x00 },
 370	{ CCI_REG8(0x03fe), 0x00 },
 371	{ CCI_REG8(0x03fe), 0x00 },
 372	{ CCI_REG8(0x03fe), 0x00 },
 373	{ CCI_REG8(0x031c), 0x80 },
 374	{ CCI_REG8(0x03fe), 0x10 },
 375	{ CCI_REG8(0x03fe), 0x00 },
 376	{ CCI_REG8(0x031c), 0x9f },
 377	{ CCI_REG8(0x0360), 0x01 },
 378	{ CCI_REG8(0x0360), 0x00 },
 379	{ CCI_REG8(0x0316), 0x09 },
 380	{ CCI_REG8(0x0a67), 0x80 },
 381	{ CCI_REG8(0x0313), 0x00 },
 382	{ CCI_REG8(0x0a53), 0x0e },
 383	{ CCI_REG8(0x0a65), 0x17 },
 384	{ CCI_REG8(0x0a68), 0xa1 },
 385	{ CCI_REG8(0x0a58), 0x00 },
 386	{ CCI_REG8(0x0ace), 0x0c },
 387	{ CCI_REG8(0x00a4), 0x00 },
 388	{ CCI_REG8(0x00a5), 0x01 },
 389	{ CCI_REG8(0x00a7), 0x09 },
 390	{ CCI_REG8(0x00a8), 0x9c },
 391	{ CCI_REG8(0x00a9), 0x0c },
 392	{ CCI_REG8(0x00aa), 0xd0 },
 393	{ CCI_REG8(0x0a8a), 0x00 },
 394	{ CCI_REG8(0x0a8b), 0xe0 },
 395	{ CCI_REG8(0x0a8c), 0x13 },
 396	{ CCI_REG8(0x0a8d), 0xe8 },
 397	{ CCI_REG8(0x0a90), 0x0a },
 398	{ CCI_REG8(0x0a91), 0x10 },
 399	{ CCI_REG8(0x0a92), 0xf8 },
 400	{ CCI_REG8(0x0a71), 0xf2 },
 401	{ CCI_REG8(0x0a72), 0x12 },
 402	{ CCI_REG8(0x0a73), 0x64 },
 403	{ CCI_REG8(0x0a75), 0x41 },
 404	{ CCI_REG8(0x0a70), 0x07 },
 405	{ CCI_REG8(0x0313), 0x80 },
 406
 407	/* ISP */
 408	{ CCI_REG8(0x00a0), 0x01 },
 409	{ CCI_REG8(0x0080), 0xd2 },
 410	{ CCI_REG8(0x0081), 0x3f },
 411	{ CCI_REG8(0x0087), 0x51 },
 412	{ CCI_REG8(0x0089), 0x03 },
 413	{ CCI_REG8(0x009b), 0x40 },
 414	{ CCI_REG8(0x05a0), 0x82 },
 415	{ CCI_REG8(0x05ac), 0x00 },
 416	{ CCI_REG8(0x05ad), 0x01 },
 417	{ CCI_REG8(0x05ae), 0x00 },
 418	{ CCI_REG8(0x0800), 0x0a },
 419	{ CCI_REG8(0x0801), 0x14 },
 420	{ CCI_REG8(0x0802), 0x28 },
 421	{ CCI_REG8(0x0803), 0x34 },
 422	{ CCI_REG8(0x0804), 0x0e },
 423	{ CCI_REG8(0x0805), 0x33 },
 424	{ CCI_REG8(0x0806), 0x03 },
 425	{ CCI_REG8(0x0807), 0x8a },
 426	{ CCI_REG8(0x0808), 0x50 },
 427	{ CCI_REG8(0x0809), 0x00 },
 428	{ CCI_REG8(0x080a), 0x34 },
 429	{ CCI_REG8(0x080b), 0x03 },
 430	{ CCI_REG8(0x080c), 0x26 },
 431	{ CCI_REG8(0x080d), 0x03 },
 432	{ CCI_REG8(0x080e), 0x18 },
 433	{ CCI_REG8(0x080f), 0x03 },
 434	{ CCI_REG8(0x0810), 0x10 },
 435	{ CCI_REG8(0x0811), 0x03 },
 436	{ CCI_REG8(0x0812), 0x00 },
 437	{ CCI_REG8(0x0813), 0x00 },
 438	{ CCI_REG8(0x0814), 0x01 },
 439	{ CCI_REG8(0x0815), 0x00 },
 440	{ CCI_REG8(0x0816), 0x01 },
 441	{ CCI_REG8(0x0817), 0x00 },
 442	{ CCI_REG8(0x0818), 0x00 },
 443	{ CCI_REG8(0x0819), 0x0a },
 444	{ CCI_REG8(0x081a), 0x01 },
 445	{ CCI_REG8(0x081b), 0x6c },
 446	{ CCI_REG8(0x081c), 0x00 },
 447	{ CCI_REG8(0x081d), 0x0b },
 448	{ CCI_REG8(0x081e), 0x02 },
 449	{ CCI_REG8(0x081f), 0x00 },
 450	{ CCI_REG8(0x0820), 0x00 },
 451	{ CCI_REG8(0x0821), 0x0c },
 452	{ CCI_REG8(0x0822), 0x02 },
 453	{ CCI_REG8(0x0823), 0xd9 },
 454	{ CCI_REG8(0x0824), 0x00 },
 455	{ CCI_REG8(0x0825), 0x0d },
 456	{ CCI_REG8(0x0826), 0x03 },
 457	{ CCI_REG8(0x0827), 0xf0 },
 458	{ CCI_REG8(0x0828), 0x00 },
 459	{ CCI_REG8(0x0829), 0x0e },
 460	{ CCI_REG8(0x082a), 0x05 },
 461	{ CCI_REG8(0x082b), 0x94 },
 462	{ CCI_REG8(0x082c), 0x09 },
 463	{ CCI_REG8(0x082d), 0x6e },
 464	{ CCI_REG8(0x082e), 0x07 },
 465	{ CCI_REG8(0x082f), 0xe6 },
 466	{ CCI_REG8(0x0830), 0x10 },
 467	{ CCI_REG8(0x0831), 0x0e },
 468	{ CCI_REG8(0x0832), 0x0b },
 469	{ CCI_REG8(0x0833), 0x2c },
 470	{ CCI_REG8(0x0834), 0x14 },
 471	{ CCI_REG8(0x0835), 0xae },
 472	{ CCI_REG8(0x0836), 0x0f },
 473	{ CCI_REG8(0x0837), 0xc4 },
 474	{ CCI_REG8(0x0838), 0x18 },
 475	{ CCI_REG8(0x0839), 0x0e },
 476	{ CCI_REG8(0x05ac), 0x01 },
 477	{ CCI_REG8(0x059a), 0x00 },
 478	{ CCI_REG8(0x059b), 0x00 },
 479	{ CCI_REG8(0x059c), 0x01 },
 480	{ CCI_REG8(0x0598), 0x00 },
 481	{ CCI_REG8(0x0597), 0x14 },
 482	{ CCI_REG8(0x05ab), 0x09 },
 483	{ CCI_REG8(0x05a4), 0x02 },
 484	{ CCI_REG8(0x05a3), 0x05 },
 485	{ CCI_REG8(0x05a0), 0xc2 },
 486	{ CCI_REG8(0x0207), 0xc4 },
 487
 488	/* GAIN */
 489	{ CCI_REG8(0x0208), 0x01 },
 490	{ CCI_REG8(0x0209), 0x72 },
 491	{ CCI_REG8(0x0204), 0x04 },
 492	{ CCI_REG8(0x0205), 0x00 },
 493
 494	{ CCI_REG8(0x0040), 0x22 },
 495	{ CCI_REG8(0x0041), 0x20 },
 496	{ CCI_REG8(0x0043), 0x10 },
 497	{ CCI_REG8(0x0044), 0x00 },
 498	{ CCI_REG8(0x0046), 0x08 },
 499	{ CCI_REG8(0x0047), 0xf0 },
 500	{ CCI_REG8(0x0048), 0x0f },
 501	{ CCI_REG8(0x004b), 0x0f },
 502	{ CCI_REG8(0x004c), 0x00 },
 503	{ CCI_REG8(0x0050), 0x5c },
 504	{ CCI_REG8(0x0051), 0x44 },
 505	{ CCI_REG8(0x005b), 0x03 },
 506	{ CCI_REG8(0x00c0), 0x00 },
 507	{ CCI_REG8(0x00c1), 0x80 },
 508	{ CCI_REG8(0x00c2), 0x31 },
 509	{ CCI_REG8(0x00c3), 0x00 },
 510	{ CCI_REG8(0x0460), 0x04 },
 511	{ CCI_REG8(0x0462), 0x08 },
 512	{ CCI_REG8(0x0464), 0x0e },
 513	{ CCI_REG8(0x0466), 0x0a },
 514	{ CCI_REG8(0x0468), 0x12 },
 515	{ CCI_REG8(0x046a), 0x12 },
 516	{ CCI_REG8(0x046c), 0x10 },
 517	{ CCI_REG8(0x046e), 0x0c },
 518	{ CCI_REG8(0x0461), 0x03 },
 519	{ CCI_REG8(0x0463), 0x03 },
 520	{ CCI_REG8(0x0465), 0x03 },
 521	{ CCI_REG8(0x0467), 0x03 },
 522	{ CCI_REG8(0x0469), 0x04 },
 523	{ CCI_REG8(0x046b), 0x04 },
 524	{ CCI_REG8(0x046d), 0x04 },
 525	{ CCI_REG8(0x046f), 0x04 },
 526	{ CCI_REG8(0x0470), 0x04 },
 527	{ CCI_REG8(0x0472), 0x10 },
 528	{ CCI_REG8(0x0474), 0x26 },
 529	{ CCI_REG8(0x0476), 0x38 },
 530	{ CCI_REG8(0x0478), 0x20 },
 531	{ CCI_REG8(0x047a), 0x30 },
 532	{ CCI_REG8(0x047c), 0x38 },
 533	{ CCI_REG8(0x047e), 0x60 },
 534	{ CCI_REG8(0x0471), 0x05 },
 535	{ CCI_REG8(0x0473), 0x05 },
 536	{ CCI_REG8(0x0475), 0x05 },
 537	{ CCI_REG8(0x0477), 0x05 },
 538	{ CCI_REG8(0x0479), 0x04 },
 539	{ CCI_REG8(0x047b), 0x04 },
 540	{ CCI_REG8(0x047d), 0x04 },
 541	{ CCI_REG8(0x047f), 0x04 },
 542};
 543
 544struct gc08a3_mode {
 545	u32 width;
 546	u32 height;
 547	const struct gc08a3_reg_list reg_list;
 548
 549	u32 hts; /* Horizontal timining size */
 550	u32 vts_def; /* Default vertical timining size */
 551	u32 vts_min; /* Min vertical timining size */
 552};
 553
 554/* Declare modes in order, from biggest to smallest height. */
 555static const struct gc08a3_mode gc08a3_modes[] = {
 556	{
 557		/* 3264*2448@30fps */
 558		.width = GC08A3_NATIVE_WIDTH,
 559		.height = GC08A3_NATIVE_HEIGHT,
 560		.reg_list = {
 561			.num_of_regs = ARRAY_SIZE(mode_3264x2448),
 562			.regs = mode_3264x2448,
 563		},
 564		.hts = 3640,
 565		.vts_def = 2548,
 566		.vts_min = 2548,
 567	},
 568	{
 569		/* 1920*1080@60fps */
 570		.width = 1920,
 571		.height = 1080,
 572		.reg_list = {
 573			.num_of_regs = ARRAY_SIZE(mode_1920x1080),
 574			.regs = mode_1920x1080,
 575		},
 576		.hts = 3640,
 577		.vts_def = 1276,
 578		.vts_min = 1276,
 579	},
 580};
 581
 582static inline struct gc08a3 *to_gc08a3(struct v4l2_subdev *sd)
 583{
 584	return container_of(sd, struct gc08a3, sd);
 585}
 586
 587static int gc08a3_power_on(struct device *dev)
 588{
 589	struct v4l2_subdev *sd = dev_get_drvdata(dev);
 590	struct gc08a3 *gc08a3 = to_gc08a3(sd);
 591	int ret;
 592
 593	ret = regulator_bulk_enable(ARRAY_SIZE(gc08a3_supply_name),
 594				    gc08a3->supplies);
 595	if (ret < 0) {
 596		dev_err(gc08a3->dev, "failed to enable regulators: %d\n", ret);
 597		return ret;
 598	}
 599
 600	ret = clk_prepare_enable(gc08a3->xclk);
 601	if (ret < 0) {
 602		regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name),
 603				       gc08a3->supplies);
 604		dev_err(gc08a3->dev, "clk prepare enable failed\n");
 605		return ret;
 606	}
 607
 608	fsleep(GC08A3_SLEEP_US);
 609
 610	gpiod_set_value_cansleep(gc08a3->reset_gpio, 0);
 611	fsleep(GC08A3_SLEEP_US);
 612
 613	return 0;
 614}
 615
 616static int gc08a3_power_off(struct device *dev)
 617{
 618	struct v4l2_subdev *sd = dev_get_drvdata(dev);
 619	struct gc08a3 *gc08a3 = to_gc08a3(sd);
 620
 621	clk_disable_unprepare(gc08a3->xclk);
 622	gpiod_set_value_cansleep(gc08a3->reset_gpio, 1);
 623	regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name),
 624			       gc08a3->supplies);
 625
 626	return 0;
 627}
 628
 629static int gc08a3_enum_mbus_code(struct v4l2_subdev *sd,
 630				 struct v4l2_subdev_state *sd_state,
 631				 struct v4l2_subdev_mbus_code_enum *code)
 632{
 633	if (code->index > 0)
 634		return -EINVAL;
 635
 636	code->code = GC08A3_MBUS_CODE;
 637
 638	return 0;
 639}
 640
 641static int gc08a3_enum_frame_size(struct v4l2_subdev *subdev,
 642				  struct v4l2_subdev_state *sd_state,
 643				  struct v4l2_subdev_frame_size_enum *fse)
 644{
 645	if (fse->code != GC08A3_MBUS_CODE)
 646		return -EINVAL;
 647
 648	if (fse->index >= ARRAY_SIZE(gc08a3_modes))
 649		return -EINVAL;
 650
 651	fse->min_width = gc08a3_modes[fse->index].width;
 652	fse->max_width = gc08a3_modes[fse->index].width;
 653	fse->min_height = gc08a3_modes[fse->index].height;
 654	fse->max_height = gc08a3_modes[fse->index].height;
 655
 656	return 0;
 657}
 658
 659static int gc08a3_update_cur_mode_controls(struct gc08a3 *gc08a3,
 660					   const struct gc08a3_mode *mode)
 661{
 662	s64 exposure_max, h_blank;
 663	int ret;
 664
 665	ret = __v4l2_ctrl_modify_range(gc08a3->vblank,
 666				       mode->vts_min - mode->height,
 667				       GC08A3_VTS_MAX - mode->height, 1,
 668				       mode->vts_def - mode->height);
 669	if (ret) {
 670		dev_err(gc08a3->dev, "VB ctrl range update failed\n");
 671		return ret;
 672	}
 673
 674	h_blank = mode->hts - mode->width;
 675	ret = __v4l2_ctrl_modify_range(gc08a3->hblank, h_blank, h_blank, 1,
 676				       h_blank);
 677	if (ret) {
 678		dev_err(gc08a3->dev, "HB ctrl range update failed\n");
 679		return ret;
 680	}
 681
 682	exposure_max = mode->vts_def - GC08A3_EXP_MARGIN;
 683	ret = __v4l2_ctrl_modify_range(gc08a3->exposure, GC08A3_EXP_MIN,
 684				       exposure_max, GC08A3_EXP_STEP,
 685				       exposure_max);
 686	if (ret) {
 687		dev_err(gc08a3->dev, "exposure ctrl range update failed\n");
 688		return ret;
 689	}
 690
 691	return 0;
 692}
 693
 694static void gc08a3_update_pad_format(struct gc08a3 *gc08a3,
 695				     const struct gc08a3_mode *mode,
 696				     struct v4l2_mbus_framefmt *fmt)
 697{
 698	fmt->width = mode->width;
 699	fmt->height = mode->height;
 700	fmt->code = GC08A3_MBUS_CODE;
 701	fmt->field = V4L2_FIELD_NONE;
 702	fmt->colorspace = V4L2_COLORSPACE_RAW;
 703	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
 704	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
 705	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
 706}
 707
 708static int gc08a3_set_format(struct v4l2_subdev *sd,
 709			     struct v4l2_subdev_state *state,
 710			     struct v4l2_subdev_format *fmt)
 711{
 712	struct gc08a3 *gc08a3 = to_gc08a3(sd);
 713	struct v4l2_mbus_framefmt *mbus_fmt;
 714	struct v4l2_rect *crop;
 715	const struct gc08a3_mode *mode;
 716
 717	mode = v4l2_find_nearest_size(gc08a3_modes, ARRAY_SIZE(gc08a3_modes),
 718				      width, height, fmt->format.width,
 719				      fmt->format.height);
 720
 721	/* update crop info to subdev state */
 722	crop = v4l2_subdev_state_get_crop(state, 0);
 723	crop->width = mode->width;
 724	crop->height = mode->height;
 725
 726	/* update fmt info to subdev state */
 727	gc08a3_update_pad_format(gc08a3, mode, &fmt->format);
 728	mbus_fmt = v4l2_subdev_state_get_format(state, 0);
 729	*mbus_fmt = fmt->format;
 730
 731	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
 732		return 0;
 733
 734	gc08a3->cur_mode = mode;
 735	gc08a3_update_cur_mode_controls(gc08a3, mode);
 736
 737	return 0;
 738}
 739
 740static int gc08a3_get_selection(struct v4l2_subdev *sd,
 741				struct v4l2_subdev_state *state,
 742				struct v4l2_subdev_selection *sel)
 743{
 744	switch (sel->target) {
 745	case V4L2_SEL_TGT_CROP_DEFAULT:
 746	case V4L2_SEL_TGT_CROP:
 747		sel->r = *v4l2_subdev_state_get_crop(state, 0);
 748		break;
 749	case V4L2_SEL_TGT_CROP_BOUNDS:
 750		sel->r.top = 0;
 751		sel->r.left = 0;
 752		sel->r.width = GC08A3_NATIVE_WIDTH;
 753		sel->r.height = GC08A3_NATIVE_HEIGHT;
 754		break;
 755	default:
 756		return -EINVAL;
 757	}
 758
 759	return 0;
 760}
 761
 762static int gc08a3_init_state(struct v4l2_subdev *sd,
 763			     struct v4l2_subdev_state *state)
 764{
 765	struct v4l2_subdev_format fmt = {
 766		.which = V4L2_SUBDEV_FORMAT_TRY,
 767		.pad = 0,
 768		.format = {
 769			.code = GC08A3_MBUS_CODE,
 770			.width = gc08a3_modes[0].width,
 771			.height = gc08a3_modes[0].height,
 772		},
 773	};
 774
 775	gc08a3_set_format(sd, state, &fmt);
 776
 777	return 0;
 778}
 779
 780static int gc08a3_set_ctrl_hflip(struct gc08a3 *gc08a3, u32 ctrl_val)
 781{
 782	int ret;
 783	u64 val;
 784
 785	ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
 786	if (ret) {
 787		dev_err(gc08a3->dev, "read hflip register failed: %d\n", ret);
 788		return ret;
 789	}
 790
 791	return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
 792			       GC08A3_FLIP_H_MASK,
 793			       ctrl_val ? GC08A3_FLIP_H_MASK : 0, NULL);
 794}
 795
 796static int gc08a3_set_ctrl_vflip(struct gc08a3 *gc08a3, u32 ctrl_val)
 797{
 798	int ret;
 799	u64 val;
 800
 801	ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
 802	if (ret) {
 803		dev_err(gc08a3->dev, "read vflip register failed: %d\n", ret);
 804		return ret;
 805	}
 806
 807	return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
 808			       GC08A3_FLIP_V_MASK,
 809			       ctrl_val ? GC08A3_FLIP_V_MASK : 0, NULL);
 810}
 811
 812static int gc08a3_test_pattern(struct gc08a3 *gc08a3, u32 pattern_menu)
 813{
 814	u32 pattern;
 815	int ret;
 816
 817	if (pattern_menu) {
 818		switch (pattern_menu) {
 819		case 1:
 820			pattern = 0x00;
 821			break;
 822		case 2:
 823			pattern = 0x10;
 824			break;
 825		case 3:
 826		case 4:
 827		case 5:
 828		case 6:
 829		case 7:
 830			pattern = pattern_menu + 1;
 831			break;
 832		default:
 833			pattern = 0x00;
 834			break;
 835		}
 836
 837		ret = cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_IDX,
 838				pattern, NULL);
 839		if (ret)
 840			return ret;
 841
 842		return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
 843				 GC08A3_TEST_PATTERN_EN, NULL);
 844	} else {
 845		return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
 846				 0x00, NULL);
 847	}
 848}
 849
 850static int gc08a3_set_ctrl(struct v4l2_ctrl *ctrl)
 851{
 852	struct gc08a3 *gc08a3 =
 853		container_of(ctrl->handler, struct gc08a3, ctrls);
 854	int ret = 0;
 855	s64 exposure_max;
 856	struct v4l2_subdev_state *state;
 857	const struct v4l2_mbus_framefmt *format;
 858
 859	state = v4l2_subdev_get_locked_active_state(&gc08a3->sd);
 860	format = v4l2_subdev_state_get_format(state, 0);
 861
 862	if (ctrl->id == V4L2_CID_VBLANK) {
 863		/* Update max exposure while meeting expected vblanking */
 864		exposure_max = format->height + ctrl->val - GC08A3_EXP_MARGIN;
 865		__v4l2_ctrl_modify_range(gc08a3->exposure,
 866					 gc08a3->exposure->minimum,
 867					 exposure_max, gc08a3->exposure->step,
 868					 exposure_max);
 869	}
 870
 871	/*
 872	 * Applying V4L2 control value only happens
 873	 * when power is on for streaming.
 874	 */
 875	if (!pm_runtime_get_if_active(gc08a3->dev))
 876		return 0;
 877
 878	switch (ctrl->id) {
 879	case V4L2_CID_EXPOSURE:
 880		ret = cci_write(gc08a3->regmap, GC08A3_EXP_REG,
 881				ctrl->val, NULL);
 882		break;
 883
 884	case V4L2_CID_ANALOGUE_GAIN:
 885		ret = cci_write(gc08a3->regmap, GC08A3_AGAIN_REG,
 886				ctrl->val, NULL);
 887		break;
 888
 889	case V4L2_CID_VBLANK:
 890		ret = cci_write(gc08a3->regmap, GC08A3_FRAME_LENGTH_REG,
 891				gc08a3->cur_mode->height + ctrl->val, NULL);
 892		break;
 893
 894	case V4L2_CID_HFLIP:
 895		ret = gc08a3_set_ctrl_hflip(gc08a3, ctrl->val);
 896		break;
 897
 898	case V4L2_CID_VFLIP:
 899		ret = gc08a3_set_ctrl_vflip(gc08a3, ctrl->val);
 900		break;
 901
 902	case V4L2_CID_TEST_PATTERN:
 903		ret = gc08a3_test_pattern(gc08a3, ctrl->val);
 904		break;
 905
 906	default:
 907		break;
 908	}
 909
 910	pm_runtime_put(gc08a3->dev);
 911
 912	return ret;
 913}
 914
 915static const struct v4l2_ctrl_ops gc08a3_ctrl_ops = {
 916	.s_ctrl = gc08a3_set_ctrl,
 917};
 918
 919static int gc08a3_start_streaming(struct gc08a3 *gc08a3)
 920{
 921	const struct gc08a3_mode *mode;
 922	const struct gc08a3_reg_list *reg_list;
 923	int ret;
 924
 925	ret = pm_runtime_resume_and_get(gc08a3->dev);
 926	if (ret < 0)
 927		return ret;
 928
 929	ret = cci_multi_reg_write(gc08a3->regmap,
 930				  mode_table_common,
 931				  ARRAY_SIZE(mode_table_common), NULL);
 932	if (ret)
 933		goto err_rpm_put;
 934
 935	mode = gc08a3->cur_mode;
 936	reg_list = &mode->reg_list;
 937	ret = cci_multi_reg_write(gc08a3->regmap,
 938				  reg_list->regs, reg_list->num_of_regs, NULL);
 939	if (ret < 0)
 940		goto err_rpm_put;
 941
 942	ret = __v4l2_ctrl_handler_setup(&gc08a3->ctrls);
 943	if (ret < 0) {
 944		dev_err(gc08a3->dev, "could not sync v4l2 controls\n");
 945		goto err_rpm_put;
 946	}
 947
 948	ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 1, NULL);
 949	if (ret < 0) {
 950		dev_err(gc08a3->dev, "write STREAMING_REG failed: %d\n", ret);
 951		goto err_rpm_put;
 952	}
 953
 954	return 0;
 955
 956err_rpm_put:
 957	pm_runtime_put(gc08a3->dev);
 958	return ret;
 959}
 960
 961static int gc08a3_stop_streaming(struct gc08a3 *gc08a3)
 962{
 963	int ret;
 964
 965	ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 0, NULL);
 966	if (ret < 0)
 967		dev_err(gc08a3->dev, "could not sent stop streaming %d\n", ret);
 968
 969	pm_runtime_put(gc08a3->dev);
 970	return ret;
 971}
 972
 973static int gc08a3_s_stream(struct v4l2_subdev *subdev, int enable)
 974{
 975	struct gc08a3 *gc08a3 = to_gc08a3(subdev);
 976	struct v4l2_subdev_state *state;
 977	int ret;
 978
 979	state = v4l2_subdev_lock_and_get_active_state(subdev);
 980
 981	if (enable)
 982		ret = gc08a3_start_streaming(gc08a3);
 983	else
 984		ret = gc08a3_stop_streaming(gc08a3);
 985
 986	v4l2_subdev_unlock_state(state);
 987
 988	return ret;
 989}
 990
 991static const struct v4l2_subdev_video_ops gc08a3_video_ops = {
 992	.s_stream = gc08a3_s_stream,
 993};
 994
 995static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = {
 996	.enum_mbus_code = gc08a3_enum_mbus_code,
 997	.enum_frame_size = gc08a3_enum_frame_size,
 998	.get_fmt = v4l2_subdev_get_fmt,
 999	.set_fmt = gc08a3_set_format,
1000	.get_selection = gc08a3_get_selection,
1001};
1002
1003static const struct v4l2_subdev_ops gc08a3_subdev_ops = {
1004	.video = &gc08a3_video_ops,
1005	.pad = &gc08a3_subdev_pad_ops,
1006};
1007
1008static const struct v4l2_subdev_internal_ops gc08a3_internal_ops = {
1009	.init_state = gc08a3_init_state,
1010};
1011
1012static int gc08a3_get_regulators(struct device *dev, struct gc08a3 *gc08a3)
1013{
1014	unsigned int i;
1015
1016	for (i = 0; i < ARRAY_SIZE(gc08a3_supply_name); i++)
1017		gc08a3->supplies[i].supply = gc08a3_supply_name[i];
1018
1019	return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc08a3_supply_name),
1020				       gc08a3->supplies);
1021}
1022
1023static int gc08a3_parse_fwnode(struct gc08a3 *gc08a3)
1024{
1025	struct fwnode_handle *endpoint;
1026	struct v4l2_fwnode_endpoint bus_cfg = {
1027		.bus_type = V4L2_MBUS_CSI2_DPHY,
1028	};
1029	int ret;
1030	struct device *dev = gc08a3->dev;
1031
1032	endpoint =
1033		fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
1034						FWNODE_GRAPH_ENDPOINT_NEXT);
1035	if (!endpoint) {
1036		dev_err(dev, "endpoint node not found\n");
1037		return -EINVAL;
1038	}
1039
1040	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
1041	if (ret) {
1042		dev_err(dev, "parsing endpoint node failed\n");
1043		goto done;
1044	}
1045
1046	ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
1047				       bus_cfg.nr_of_link_frequencies,
1048				       gc08a3_link_freq_menu_items,
1049				       ARRAY_SIZE(gc08a3_link_freq_menu_items),
1050				       &gc08a3->link_freq_bitmap);
1051	if (ret)
1052		goto done;
1053
1054done:
1055	v4l2_fwnode_endpoint_free(&bus_cfg);
1056	fwnode_handle_put(endpoint);
1057	return ret;
1058}
1059
1060static u64 gc08a3_to_pixel_rate(u32 f_index)
1061{
1062	u64 pixel_rate =
1063		gc08a3_link_freq_menu_items[f_index] * 2 * GC08A3_DATA_LANES;
1064
1065	return div_u64(pixel_rate, GC08A3_RGB_DEPTH);
1066}
1067
1068static int gc08a3_init_controls(struct gc08a3 *gc08a3)
1069{
1070	struct i2c_client *client = v4l2_get_subdevdata(&gc08a3->sd);
1071	const struct gc08a3_mode *mode = &gc08a3_modes[0];
1072	const struct v4l2_ctrl_ops *ops = &gc08a3_ctrl_ops;
1073	struct v4l2_fwnode_device_properties props;
1074	struct v4l2_ctrl_handler *ctrl_hdlr;
1075	s64 exposure_max, h_blank;
1076	int ret;
1077
1078	ctrl_hdlr = &gc08a3->ctrls;
1079	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
1080	if (ret)
1081		return ret;
1082
1083	gc08a3->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
1084					  V4L2_CID_HFLIP, 0, 1, 1, 0);
1085	gc08a3->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
1086					  V4L2_CID_VFLIP, 0, 1, 1, 0);
1087	v4l2_ctrl_cluster(2, &gc08a3->hflip);
1088
1089	gc08a3->link_freq =
1090	v4l2_ctrl_new_int_menu(ctrl_hdlr,
1091			       &gc08a3_ctrl_ops,
1092			       V4L2_CID_LINK_FREQ,
1093			       ARRAY_SIZE(gc08a3_link_freq_menu_items) - 1,
1094			       0,
1095			       gc08a3_link_freq_menu_items);
1096	if (gc08a3->link_freq)
1097		gc08a3->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1098
1099	gc08a3->pixel_rate =
1100		v4l2_ctrl_new_std(ctrl_hdlr,
1101				  &gc08a3_ctrl_ops,
1102				  V4L2_CID_PIXEL_RATE, 0,
1103				  gc08a3_to_pixel_rate(0),
1104				  1,
1105				  gc08a3_to_pixel_rate(0));
1106
1107	gc08a3->vblank =
1108		v4l2_ctrl_new_std(ctrl_hdlr,
1109				  &gc08a3_ctrl_ops, V4L2_CID_VBLANK,
1110				  mode->vts_min - mode->height,
1111				  GC08A3_VTS_MAX - mode->height, 1,
1112				  mode->vts_def - mode->height);
1113
1114	h_blank = mode->hts - mode->width;
1115	gc08a3->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
1116					   V4L2_CID_HBLANK, h_blank, h_blank, 1,
1117					   h_blank);
1118	if (gc08a3->hblank)
1119		gc08a3->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1120
1121	v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
1122			  V4L2_CID_ANALOGUE_GAIN, GC08A3_AGAIN_MIN,
1123			  GC08A3_AGAIN_MAX, GC08A3_AGAIN_STEP,
1124			  GC08A3_AGAIN_MIN);
1125
1126	exposure_max = mode->vts_def - GC08A3_EXP_MARGIN;
1127	gc08a3->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
1128					     V4L2_CID_EXPOSURE, GC08A3_EXP_MIN,
1129					     exposure_max, GC08A3_EXP_STEP,
1130					     exposure_max);
1131
1132	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc08a3_ctrl_ops,
1133				     V4L2_CID_TEST_PATTERN,
1134				     ARRAY_SIZE(gc08a3_test_pattern_menu) - 1,
1135				     0, 0, gc08a3_test_pattern_menu);
1136
1137	/* register properties to fwnode (e.g. rotation, orientation) */
1138	ret = v4l2_fwnode_device_parse(&client->dev, &props);
1139	if (ret)
1140		goto error_ctrls;
1141
1142	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props);
1143	if (ret)
1144		goto error_ctrls;
1145
1146	if (ctrl_hdlr->error) {
1147		ret = ctrl_hdlr->error;
1148		goto error_ctrls;
1149	}
1150
1151	gc08a3->sd.ctrl_handler = ctrl_hdlr;
1152
1153	return 0;
1154
1155error_ctrls:
1156	v4l2_ctrl_handler_free(ctrl_hdlr);
1157
1158	return ret;
1159}
1160
1161static int gc08a3_identify_module(struct gc08a3 *gc08a3)
1162{
1163	u64 val;
1164	int ret;
1165
1166	ret = cci_read(gc08a3->regmap, GC08A3_REG_CHIP_ID, &val, NULL);
1167	if (ret) {
1168		dev_err(gc08a3->dev, "failed to read chip id");
1169		return ret;
1170	}
1171
1172	if (val != GC08A3_CHIP_ID) {
1173		dev_err(gc08a3->dev, "chip id mismatch: 0x%x!=0x%llx",
1174			GC08A3_CHIP_ID, val);
1175		return -ENXIO;
1176	}
1177
1178	return 0;
1179}
1180
1181static int gc08a3_probe(struct i2c_client *client)
1182{
1183	struct device *dev = &client->dev;
1184	struct gc08a3 *gc08a3;
1185	int ret;
1186
1187	gc08a3 = devm_kzalloc(dev, sizeof(*gc08a3), GFP_KERNEL);
1188	if (!gc08a3)
1189		return -ENOMEM;
1190
1191	gc08a3->dev = dev;
1192
1193	ret = gc08a3_parse_fwnode(gc08a3);
1194	if (ret)
1195		return ret;
1196
1197	gc08a3->regmap = devm_cci_regmap_init_i2c(client, 16);
1198	if (IS_ERR(gc08a3->regmap))
1199		return dev_err_probe(dev, PTR_ERR(gc08a3->regmap),
1200				     "failed to init CCI\n");
1201
1202	gc08a3->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true,
1203						       GC08A3_DEFAULT_CLK_FREQ);
1204	if (IS_ERR(gc08a3->xclk))
1205		return dev_err_probe(dev, PTR_ERR(gc08a3->xclk),
1206				     "failed to get xclk\n");
1207
1208	ret = gc08a3_get_regulators(dev, gc08a3);
1209	if (ret < 0)
1210		return dev_err_probe(dev, ret,
1211				     "failed to get regulators\n");
1212
1213	gc08a3->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
1214	if (IS_ERR(gc08a3->reset_gpio))
1215		return dev_err_probe(dev, PTR_ERR(gc08a3->reset_gpio),
1216				     "failed to get gpio\n");
1217
1218	v4l2_i2c_subdev_init(&gc08a3->sd, client, &gc08a3_subdev_ops);
1219	gc08a3->sd.internal_ops = &gc08a3_internal_ops;
1220	gc08a3->cur_mode = &gc08a3_modes[0];
1221
1222	ret = gc08a3_power_on(gc08a3->dev);
1223	if (ret)
1224		return dev_err_probe(dev, ret,
1225				     "failed to sensor power on\n");
1226
1227	ret = gc08a3_identify_module(gc08a3);
1228	if (ret) {
1229		dev_err(&client->dev, "failed to find sensor: %d\n", ret);
1230		goto err_power_off;
1231	}
1232
1233	ret = gc08a3_init_controls(gc08a3);
1234	if (ret) {
1235		dev_err(&client->dev, "failed to init controls: %d", ret);
1236		goto err_power_off;
1237	}
1238
1239	gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1240	gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE;
1241	gc08a3->sd.dev = &client->dev;
1242	gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1243
1244	ret = media_entity_pads_init(&gc08a3->sd.entity, 1, &gc08a3->pad);
1245	if (ret < 0) {
1246		dev_err(dev, "could not register media entity\n");
1247		goto err_v4l2_ctrl_handler_free;
1248	}
1249
1250	gc08a3->sd.state_lock = gc08a3->ctrls.lock;
1251	ret = v4l2_subdev_init_finalize(&gc08a3->sd);
1252	if (ret < 0) {
1253		dev_err(dev, "v4l2 subdev init error: %d\n", ret);
1254		goto err_media_entity_cleanup;
1255	}
1256
1257	pm_runtime_set_active(gc08a3->dev);
1258	pm_runtime_enable(gc08a3->dev);
1259	pm_runtime_set_autosuspend_delay(gc08a3->dev, 1000);
1260	pm_runtime_use_autosuspend(gc08a3->dev);
1261	pm_runtime_idle(gc08a3->dev);
1262
1263	ret = v4l2_async_register_subdev_sensor(&gc08a3->sd);
1264	if (ret < 0) {
1265		dev_err(dev, "could not register v4l2 device\n");
1266		goto err_rpm;
1267	}
1268
1269	return 0;
1270
1271err_rpm:
1272	pm_runtime_disable(gc08a3->dev);
1273	v4l2_subdev_cleanup(&gc08a3->sd);
1274
1275err_media_entity_cleanup:
1276	media_entity_cleanup(&gc08a3->sd.entity);
1277
1278err_v4l2_ctrl_handler_free:
1279	v4l2_ctrl_handler_free(gc08a3->sd.ctrl_handler);
1280
1281err_power_off:
1282	gc08a3_power_off(gc08a3->dev);
1283
1284	return ret;
1285}
1286
1287static void gc08a3_remove(struct i2c_client *client)
1288{
1289	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1290	struct gc08a3 *gc08a3 = to_gc08a3(sd);
1291
1292	v4l2_async_unregister_subdev(&gc08a3->sd);
1293	v4l2_subdev_cleanup(sd);
1294	media_entity_cleanup(&gc08a3->sd.entity);
1295	v4l2_ctrl_handler_free(&gc08a3->ctrls);
1296
1297	pm_runtime_disable(&client->dev);
1298	if (!pm_runtime_status_suspended(&client->dev))
1299		gc08a3_power_off(gc08a3->dev);
1300	pm_runtime_set_suspended(&client->dev);
1301}
1302
1303static const struct of_device_id gc08a3_of_match[] = {
1304	{ .compatible = "galaxycore,gc08a3" },
1305	{}
1306};
1307MODULE_DEVICE_TABLE(of, gc08a3_of_match);
1308
1309static DEFINE_RUNTIME_DEV_PM_OPS(gc08a3_pm_ops,
1310				 gc08a3_power_off,
1311				 gc08a3_power_on,
1312				 NULL);
1313
1314static struct i2c_driver gc08a3_i2c_driver = {
1315	.driver = {
1316		.of_match_table = gc08a3_of_match,
1317		.pm = pm_ptr(&gc08a3_pm_ops),
1318		.name  = "gc08a3",
1319	},
1320	.probe  = gc08a3_probe,
1321	.remove = gc08a3_remove,
1322};
1323module_i2c_driver(gc08a3_i2c_driver);
1324
1325MODULE_DESCRIPTION("GalaxyCore gc08a3 Camera driver");
1326MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>");
1327MODULE_LICENSE("GPL");
~/ Read-only file preview.