1// SPDX-License-Identifier: GPL-2.0
2/*
3 * A V4L2 driver for Galaxycore GC2145 camera.
4 * Copyright (C) 2023, STMicroelectronics SA
5 *
6 * Inspired by the imx219.c driver
7 *
8 * Datasheet v1.0 available at http://files.pine64.org/doc/datasheet/PinebookPro/GC2145%20CSP%20DataSheet%20release%20V1.0_20131201.pdf
9 */
10
11#include <linux/clk.h>
12#include <linux/delay.h>
13#include <linux/gpio/consumer.h>
14#include <linux/i2c.h>
15#include <linux/module.h>
16#include <linux/pm_runtime.h>
17#include <linux/regulator/consumer.h>
18#include <linux/units.h>
19
20#include <media/mipi-csi2.h>
21#include <media/v4l2-cci.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-device.h>
24#include <media/v4l2-event.h>
25#include <media/v4l2-fwnode.h>
26#include <media/v4l2-mediabus.h>
27
28/* Chip ID */
29#define GC2145_CHIP_ID		0x2145
30
31/* Page 0 */
32#define GC2145_REG_EXPOSURE	CCI_REG16(0x03)
33#define GC2145_REG_HBLANK	CCI_REG16(0x05)
34#define GC2145_REG_VBLANK	CCI_REG16(0x07)
35#define GC2145_REG_ROW_START	CCI_REG16(0x09)
36#define GC2145_REG_COL_START	CCI_REG16(0x0b)
37#define GC2145_REG_WIN_HEIGHT	CCI_REG16(0x0d)
38#define GC2145_REG_WIN_WIDTH	CCI_REG16(0x0f)
39#define GC2145_REG_ANALOG_MODE1	CCI_REG8(0x17)
40#define GC2145_REG_OUTPUT_FMT	CCI_REG8(0x84)
41#define GC2145_REG_SYNC_MODE	CCI_REG8(0x86)
42#define GC2145_SYNC_MODE_COL_SWITCH	BIT(4)
43#define GC2145_SYNC_MODE_ROW_SWITCH	BIT(5)
44#define GC2145_REG_BYPASS_MODE	CCI_REG8(0x89)
45#define GC2145_BYPASS_MODE_SWITCH	BIT(5)
46#define GC2145_REG_DEBUG_MODE2	CCI_REG8(0x8c)
47#define GC2145_REG_DEBUG_MODE3	CCI_REG8(0x8d)
48#define GC2145_REG_CROP_ENABLE	CCI_REG8(0x90)
49#define GC2145_REG_CROP_Y	CCI_REG16(0x91)
50#define GC2145_REG_CROP_X	CCI_REG16(0x93)
51#define GC2145_REG_CROP_HEIGHT	CCI_REG16(0x95)
52#define GC2145_REG_CROP_WIDTH	CCI_REG16(0x97)
53#define GC2145_REG_GLOBAL_GAIN	CCI_REG8(0xb0)
54#define GC2145_REG_CHIP_ID	CCI_REG16(0xf0)
55#define GC2145_REG_PAD_IO	CCI_REG8(0xf2)
56#define GC2145_REG_PAGE_SELECT	CCI_REG8(0xfe)
57/* Page 3 */
58#define GC2145_REG_DPHY_ANALOG_MODE1	CCI_REG8(0x01)
59#define GC2145_DPHY_MODE_PHY_CLK_EN	BIT(0)
60#define GC2145_DPHY_MODE_PHY_LANE0_EN	BIT(1)
61#define GC2145_DPHY_MODE_PHY_LANE1_EN	BIT(2)
62#define GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL	BIT(7)
63#define GC2145_REG_DPHY_ANALOG_MODE2	CCI_REG8(0x02)
64#define GC2145_DPHY_CLK_DIFF(a)		((a) & 0x07)
65#define GC2145_DPHY_LANE0_DIFF(a)	(((a) & 0x07) << 4)
66#define GC2145_REG_DPHY_ANALOG_MODE3	CCI_REG8(0x03)
67#define GC2145_DPHY_LANE1_DIFF(a)	((a) & 0x07)
68#define GC2145_DPHY_CLK_DELAY		BIT(4)
69#define GC2145_DPHY_LANE0_DELAY		BIT(5)
70#define GC2145_DPHY_LANE1_DELAY		BIT(6)
71#define GC2145_REG_FIFO_FULL_LVL_LOW	CCI_REG8(0x04)
72#define GC2145_REG_FIFO_FULL_LVL_HIGH	CCI_REG8(0x05)
73#define GC2145_REG_FIFO_MODE		CCI_REG8(0x06)
74#define GC2145_FIFO_MODE_READ_GATE	BIT(3)
75#define GC2145_FIFO_MODE_MIPI_CLK_MODULE	BIT(7)
76#define GC2145_REG_BUF_CSI2_MODE	CCI_REG8(0x10)
77#define GC2145_CSI2_MODE_DOUBLE		BIT(0)
78#define GC2145_CSI2_MODE_RAW8		BIT(2)
79#define GC2145_CSI2_MODE_MIPI_EN	BIT(4)
80#define GC2145_CSI2_MODE_EN		BIT(7)
81#define GC2145_REG_MIPI_DT	CCI_REG8(0x11)
82#define GC2145_REG_LWC_LOW	CCI_REG8(0x12)
83#define GC2145_REG_LWC_HIGH	CCI_REG8(0x13)
84#define GC2145_REG_DPHY_MODE	CCI_REG8(0x15)
85#define GC2145_DPHY_MODE_TRIGGER_PROG	BIT(4)
86#define GC2145_REG_FIFO_GATE_MODE	CCI_REG8(0x17)
87#define GC2145_REG_T_LPX	CCI_REG8(0x21)
88#define GC2145_REG_T_CLK_HS_PREPARE	CCI_REG8(0x22)
89#define GC2145_REG_T_CLK_ZERO	CCI_REG8(0x23)
90#define GC2145_REG_T_CLK_PRE	CCI_REG8(0x24)
91#define GC2145_REG_T_CLK_POST	CCI_REG8(0x25)
92#define GC2145_REG_T_CLK_TRAIL	CCI_REG8(0x26)
93#define GC2145_REG_T_HS_EXIT	CCI_REG8(0x27)
94#define GC2145_REG_T_WAKEUP	CCI_REG8(0x28)
95#define GC2145_REG_T_HS_PREPARE	CCI_REG8(0x29)
96#define GC2145_REG_T_HS_ZERO	CCI_REG8(0x2a)
97#define GC2145_REG_T_HS_TRAIL	CCI_REG8(0x2b)
98
99/* External clock frequency is 24.0MHz */
100#define GC2145_XCLK_FREQ	(24 * HZ_PER_MHZ)
101
102#define GC2145_NATIVE_WIDTH	1616U
103#define GC2145_NATIVE_HEIGHT	1232U
104
105/**
106 * struct gc2145_mode - GC2145 mode description
107 * @width: frame width (in pixels)
108 * @height: frame height (in pixels)
109 * @reg_seq: registers config sequence to enter into the mode
110 * @reg_seq_size: size of the sequence
111 * @pixel_rate: pixel rate associated with the mode
112 * @crop: window area captured
113 * @hblank: default horizontal blanking
114 * @vblank: default vertical blanking
115 * @link_freq_index: index within the link frequency menu
116 */
117struct gc2145_mode {
118	unsigned int width;
119	unsigned int height;
120	const struct cci_reg_sequence *reg_seq;
121	size_t reg_seq_size;
122	unsigned long pixel_rate;
123	struct v4l2_rect crop;
124	unsigned int hblank;
125	unsigned int vblank;
126	unsigned int link_freq_index;
127};
128
129#define GC2145_DEFAULT_EXPOSURE	0x04e2
130#define GC2145_DEFAULT_GLOBAL_GAIN	0x55
131static const struct cci_reg_sequence gc2145_common_regs[] = {
132	{GC2145_REG_PAGE_SELECT, 0x00},
133	/* SH Delay */
134	{CCI_REG8(0x12), 0x2e},
135	/* Flip */
136	{GC2145_REG_ANALOG_MODE1, 0x14},
137	/* Analog Conf */
138	{CCI_REG8(0x18), 0x22}, {CCI_REG8(0x19), 0x0e}, {CCI_REG8(0x1a), 0x01},
139	{CCI_REG8(0x1b), 0x4b}, {CCI_REG8(0x1c), 0x07}, {CCI_REG8(0x1d), 0x10},
140	{CCI_REG8(0x1e), 0x88}, {CCI_REG8(0x1f), 0x78}, {CCI_REG8(0x20), 0x03},
141	{CCI_REG8(0x21), 0x40}, {CCI_REG8(0x22), 0xa0}, {CCI_REG8(0x24), 0x16},
142	{CCI_REG8(0x25), 0x01}, {CCI_REG8(0x26), 0x10}, {CCI_REG8(0x2d), 0x60},
143	{CCI_REG8(0x30), 0x01}, {CCI_REG8(0x31), 0x90}, {CCI_REG8(0x33), 0x06},
144	{CCI_REG8(0x34), 0x01},
145	/* ISP related */
146	{CCI_REG8(0x80), 0x7f}, {CCI_REG8(0x81), 0x26}, {CCI_REG8(0x82), 0xfa},
147	{CCI_REG8(0x83), 0x00}, {CCI_REG8(0x84), 0x02}, {CCI_REG8(0x86), 0x02},
148	{CCI_REG8(0x88), 0x03},
149	{GC2145_REG_BYPASS_MODE, 0x03},
150	{CCI_REG8(0x85), 0x08}, {CCI_REG8(0x8a), 0x00}, {CCI_REG8(0x8b), 0x00},
151	{GC2145_REG_GLOBAL_GAIN, GC2145_DEFAULT_GLOBAL_GAIN},
152	{CCI_REG8(0xc3), 0x00}, {CCI_REG8(0xc4), 0x80}, {CCI_REG8(0xc5), 0x90},
153	{CCI_REG8(0xc6), 0x3b}, {CCI_REG8(0xc7), 0x46},
154	/* BLK */
155	{GC2145_REG_PAGE_SELECT, 0x00},
156	{CCI_REG8(0x40), 0x42}, {CCI_REG8(0x41), 0x00}, {CCI_REG8(0x43), 0x5b},
157	{CCI_REG8(0x5e), 0x00}, {CCI_REG8(0x5f), 0x00}, {CCI_REG8(0x60), 0x00},
158	{CCI_REG8(0x61), 0x00}, {CCI_REG8(0x62), 0x00}, {CCI_REG8(0x63), 0x00},
159	{CCI_REG8(0x64), 0x00}, {CCI_REG8(0x65), 0x00}, {CCI_REG8(0x66), 0x20},
160	{CCI_REG8(0x67), 0x20}, {CCI_REG8(0x68), 0x20}, {CCI_REG8(0x69), 0x20},
161	{CCI_REG8(0x76), 0x00}, {CCI_REG8(0x6a), 0x08}, {CCI_REG8(0x6b), 0x08},
162	{CCI_REG8(0x6c), 0x08}, {CCI_REG8(0x6d), 0x08}, {CCI_REG8(0x6e), 0x08},
163	{CCI_REG8(0x6f), 0x08}, {CCI_REG8(0x70), 0x08}, {CCI_REG8(0x71), 0x08},
164	{CCI_REG8(0x76), 0x00}, {CCI_REG8(0x72), 0xf0}, {CCI_REG8(0x7e), 0x3c},
165	{CCI_REG8(0x7f), 0x00},
166	{GC2145_REG_PAGE_SELECT, 0x02},
167	{CCI_REG8(0x48), 0x15}, {CCI_REG8(0x49), 0x00}, {CCI_REG8(0x4b), 0x0b},
168	/* AEC */
169	{GC2145_REG_PAGE_SELECT, 0x00},
170	{GC2145_REG_EXPOSURE, GC2145_DEFAULT_EXPOSURE},
171	{GC2145_REG_PAGE_SELECT, 0x01},
172	{CCI_REG8(0x01), 0x04}, {CCI_REG8(0x02), 0xc0}, {CCI_REG8(0x03), 0x04},
173	{CCI_REG8(0x04), 0x90}, {CCI_REG8(0x05), 0x30}, {CCI_REG8(0x06), 0x90},
174	{CCI_REG8(0x07), 0x30}, {CCI_REG8(0x08), 0x80}, {CCI_REG8(0x09), 0x00},
175	{CCI_REG8(0x0a), 0x82}, {CCI_REG8(0x0b), 0x11}, {CCI_REG8(0x0c), 0x10},
176	{CCI_REG8(0x11), 0x10}, {CCI_REG8(0x13), 0x7b}, {CCI_REG8(0x17), 0x00},
177	{CCI_REG8(0x1c), 0x11}, {CCI_REG8(0x1e), 0x61}, {CCI_REG8(0x1f), 0x35},
178	{CCI_REG8(0x20), 0x40}, {CCI_REG8(0x22), 0x40}, {CCI_REG8(0x23), 0x20},
179	{GC2145_REG_PAGE_SELECT, 0x02},
180	{CCI_REG8(0x0f), 0x04},
181	{GC2145_REG_PAGE_SELECT, 0x01},
182	{CCI_REG8(0x12), 0x35}, {CCI_REG8(0x15), 0xb0}, {CCI_REG8(0x10), 0x31},
183	{CCI_REG8(0x3e), 0x28}, {CCI_REG8(0x3f), 0xb0}, {CCI_REG8(0x40), 0x90},
184	{CCI_REG8(0x41), 0x0f},
185	/* INTPEE */
186	{GC2145_REG_PAGE_SELECT, 0x02},
187	{CCI_REG8(0x90), 0x6c}, {CCI_REG8(0x91), 0x03}, {CCI_REG8(0x92), 0xcb},
188	{CCI_REG8(0x94), 0x33}, {CCI_REG8(0x95), 0x84}, {CCI_REG8(0x97), 0x65},
189	{CCI_REG8(0xa2), 0x11},
190	/* DNDD */
191	{GC2145_REG_PAGE_SELECT, 0x02},
192	{CCI_REG8(0x80), 0xc1}, {CCI_REG8(0x81), 0x08}, {CCI_REG8(0x82), 0x05},
193	{CCI_REG8(0x83), 0x08}, {CCI_REG8(0x84), 0x0a}, {CCI_REG8(0x86), 0xf0},
194	{CCI_REG8(0x87), 0x50}, {CCI_REG8(0x88), 0x15}, {CCI_REG8(0x89), 0xb0},
195	{CCI_REG8(0x8a), 0x30}, {CCI_REG8(0x8b), 0x10},
196	/* ASDE */
197	{GC2145_REG_PAGE_SELECT, 0x01},
198	{CCI_REG8(0x21), 0x04},
199	{GC2145_REG_PAGE_SELECT, 0x02},
200	{CCI_REG8(0xa3), 0x50}, {CCI_REG8(0xa4), 0x20}, {CCI_REG8(0xa5), 0x40},
201	{CCI_REG8(0xa6), 0x80}, {CCI_REG8(0xab), 0x40}, {CCI_REG8(0xae), 0x0c},
202	{CCI_REG8(0xb3), 0x46}, {CCI_REG8(0xb4), 0x64}, {CCI_REG8(0xb6), 0x38},
203	{CCI_REG8(0xb7), 0x01}, {CCI_REG8(0xb9), 0x2b}, {CCI_REG8(0x3c), 0x04},
204	{CCI_REG8(0x3d), 0x15}, {CCI_REG8(0x4b), 0x06}, {CCI_REG8(0x4c), 0x20},
205	/* Gamma */
206	{GC2145_REG_PAGE_SELECT, 0x02},
207	{CCI_REG8(0x10), 0x09}, {CCI_REG8(0x11), 0x0d}, {CCI_REG8(0x12), 0x13},
208	{CCI_REG8(0x13), 0x19}, {CCI_REG8(0x14), 0x27}, {CCI_REG8(0x15), 0x37},
209	{CCI_REG8(0x16), 0x45}, {CCI_REG8(0x17), 0x53}, {CCI_REG8(0x18), 0x69},
210	{CCI_REG8(0x19), 0x7d}, {CCI_REG8(0x1a), 0x8f}, {CCI_REG8(0x1b), 0x9d},
211	{CCI_REG8(0x1c), 0xa9}, {CCI_REG8(0x1d), 0xbd}, {CCI_REG8(0x1e), 0xcd},
212	{CCI_REG8(0x1f), 0xd9}, {CCI_REG8(0x20), 0xe3}, {CCI_REG8(0x21), 0xea},
213	{CCI_REG8(0x22), 0xef}, {CCI_REG8(0x23), 0xf5}, {CCI_REG8(0x24), 0xf9},
214	{CCI_REG8(0x25), 0xff},
215	{GC2145_REG_PAGE_SELECT, 0x00},
216	{CCI_REG8(0xc6), 0x20}, {CCI_REG8(0xc7), 0x2b},
217	/* Gamma 2 */
218	{GC2145_REG_PAGE_SELECT, 0x02},
219	{CCI_REG8(0x26), 0x0f}, {CCI_REG8(0x27), 0x14}, {CCI_REG8(0x28), 0x19},
220	{CCI_REG8(0x29), 0x1e}, {CCI_REG8(0x2a), 0x27}, {CCI_REG8(0x2b), 0x33},
221	{CCI_REG8(0x2c), 0x3b}, {CCI_REG8(0x2d), 0x45}, {CCI_REG8(0x2e), 0x59},
222	{CCI_REG8(0x2f), 0x69}, {CCI_REG8(0x30), 0x7c}, {CCI_REG8(0x31), 0x89},
223	{CCI_REG8(0x32), 0x98}, {CCI_REG8(0x33), 0xae}, {CCI_REG8(0x34), 0xc0},
224	{CCI_REG8(0x35), 0xcf}, {CCI_REG8(0x36), 0xda}, {CCI_REG8(0x37), 0xe2},
225	{CCI_REG8(0x38), 0xe9}, {CCI_REG8(0x39), 0xf3}, {CCI_REG8(0x3a), 0xf9},
226	{CCI_REG8(0x3b), 0xff},
227	/* YCP */
228	{GC2145_REG_PAGE_SELECT, 0x02},
229	{CCI_REG8(0xd1), 0x32}, {CCI_REG8(0xd2), 0x32}, {CCI_REG8(0xd3), 0x40},
230	{CCI_REG8(0xd6), 0xf0}, {CCI_REG8(0xd7), 0x10}, {CCI_REG8(0xd8), 0xda},
231	{CCI_REG8(0xdd), 0x14}, {CCI_REG8(0xde), 0x86}, {CCI_REG8(0xed), 0x80},
232	{CCI_REG8(0xee), 0x00}, {CCI_REG8(0xef), 0x3f}, {CCI_REG8(0xd8), 0xd8},
233	/* ABS */
234	{GC2145_REG_PAGE_SELECT, 0x01},
235	{CCI_REG8(0x9f), 0x40},
236	/* LSC */
237	{GC2145_REG_PAGE_SELECT, 0x01},
238	{CCI_REG8(0xc2), 0x14}, {CCI_REG8(0xc3), 0x0d}, {CCI_REG8(0xc4), 0x0c},
239	{CCI_REG8(0xc8), 0x15}, {CCI_REG8(0xc9), 0x0d}, {CCI_REG8(0xca), 0x0a},
240	{CCI_REG8(0xbc), 0x24}, {CCI_REG8(0xbd), 0x10}, {CCI_REG8(0xbe), 0x0b},
241	{CCI_REG8(0xb6), 0x25}, {CCI_REG8(0xb7), 0x16}, {CCI_REG8(0xb8), 0x15},
242	{CCI_REG8(0xc5), 0x00}, {CCI_REG8(0xc6), 0x00}, {CCI_REG8(0xc7), 0x00},
243	{CCI_REG8(0xcb), 0x00}, {CCI_REG8(0xcc), 0x00}, {CCI_REG8(0xcd), 0x00},
244	{CCI_REG8(0xbf), 0x07}, {CCI_REG8(0xc0), 0x00}, {CCI_REG8(0xc1), 0x00},
245	{CCI_REG8(0xb9), 0x00}, {CCI_REG8(0xba), 0x00}, {CCI_REG8(0xbb), 0x00},
246	{CCI_REG8(0xaa), 0x01}, {CCI_REG8(0xab), 0x01}, {CCI_REG8(0xac), 0x00},
247	{CCI_REG8(0xad), 0x05}, {CCI_REG8(0xae), 0x06}, {CCI_REG8(0xaf), 0x0e},
248	{CCI_REG8(0xb0), 0x0b}, {CCI_REG8(0xb1), 0x07}, {CCI_REG8(0xb2), 0x06},
249	{CCI_REG8(0xb3), 0x17}, {CCI_REG8(0xb4), 0x0e}, {CCI_REG8(0xb5), 0x0e},
250	{CCI_REG8(0xd0), 0x09}, {CCI_REG8(0xd1), 0x00}, {CCI_REG8(0xd2), 0x00},
251	{CCI_REG8(0xd6), 0x08}, {CCI_REG8(0xd7), 0x00}, {CCI_REG8(0xd8), 0x00},
252	{CCI_REG8(0xd9), 0x00}, {CCI_REG8(0xda), 0x00}, {CCI_REG8(0xdb), 0x00},
253	{CCI_REG8(0xd3), 0x0a}, {CCI_REG8(0xd4), 0x00}, {CCI_REG8(0xd5), 0x00},
254	{CCI_REG8(0xa4), 0x00}, {CCI_REG8(0xa5), 0x00}, {CCI_REG8(0xa6), 0x77},
255	{CCI_REG8(0xa7), 0x77}, {CCI_REG8(0xa8), 0x77}, {CCI_REG8(0xa9), 0x77},
256	{CCI_REG8(0xa1), 0x80}, {CCI_REG8(0xa2), 0x80},
257	{GC2145_REG_PAGE_SELECT, 0x01},
258	{CCI_REG8(0xdf), 0x0d}, {CCI_REG8(0xdc), 0x25}, {CCI_REG8(0xdd), 0x30},
259	{CCI_REG8(0xe0), 0x77}, {CCI_REG8(0xe1), 0x80}, {CCI_REG8(0xe2), 0x77},
260	{CCI_REG8(0xe3), 0x90}, {CCI_REG8(0xe6), 0x90}, {CCI_REG8(0xe7), 0xa0},
261	{CCI_REG8(0xe8), 0x90}, {CCI_REG8(0xe9), 0xa0},
262	/* AWB */
263	/* measure window */
264	{GC2145_REG_PAGE_SELECT, 0x00},
265	{CCI_REG8(0xec), 0x06}, {CCI_REG8(0xed), 0x04}, {CCI_REG8(0xee), 0x60},
266	{CCI_REG8(0xef), 0x90}, {CCI_REG8(0xb6), 0x01},
267	{GC2145_REG_PAGE_SELECT, 0x01},
268	{CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4b), 0x01},
269	{CCI_REG8(0x4f), 0x00},
270	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x71}, {CCI_REG8(0x4e), 0x01},
271	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x91}, {CCI_REG8(0x4e), 0x01},
272	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x70}, {CCI_REG8(0x4e), 0x01},
273	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x90}, {CCI_REG8(0x4e), 0x02},
274	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xb0}, {CCI_REG8(0x4e), 0x02},
275	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8f}, {CCI_REG8(0x4e), 0x02},
276	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6f}, {CCI_REG8(0x4e), 0x02},
277	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaf}, {CCI_REG8(0x4e), 0x02},
278	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xd0}, {CCI_REG8(0x4e), 0x02},
279	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xf0}, {CCI_REG8(0x4e), 0x02},
280	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcf}, {CCI_REG8(0x4e), 0x02},
281	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xef}, {CCI_REG8(0x4e), 0x02},
282	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6e}, {CCI_REG8(0x4e), 0x03},
283	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8e}, {CCI_REG8(0x4e), 0x03},
284	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xae}, {CCI_REG8(0x4e), 0x03},
285	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xce}, {CCI_REG8(0x4e), 0x03},
286	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4d}, {CCI_REG8(0x4e), 0x03},
287	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6d}, {CCI_REG8(0x4e), 0x03},
288	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8d}, {CCI_REG8(0x4e), 0x03},
289	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xad}, {CCI_REG8(0x4e), 0x03},
290	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcd}, {CCI_REG8(0x4e), 0x03},
291	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4c}, {CCI_REG8(0x4e), 0x03},
292	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6c}, {CCI_REG8(0x4e), 0x03},
293	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8c}, {CCI_REG8(0x4e), 0x03},
294	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xac}, {CCI_REG8(0x4e), 0x03},
295	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcc}, {CCI_REG8(0x4e), 0x03},
296	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcb}, {CCI_REG8(0x4e), 0x03},
297	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4b}, {CCI_REG8(0x4e), 0x03},
298	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6b}, {CCI_REG8(0x4e), 0x03},
299	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8b}, {CCI_REG8(0x4e), 0x03},
300	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xab}, {CCI_REG8(0x4e), 0x03},
301	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04},
302	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaa}, {CCI_REG8(0x4e), 0x04},
303	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04},
304	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04},
305	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x04},
306	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04},
307	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x04},
308	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x04},
309	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0b}, {CCI_REG8(0x4e), 0x05},
310	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0a}, {CCI_REG8(0x4e), 0x05},
311	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xeb}, {CCI_REG8(0x4e), 0x05},
312	{CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xea}, {CCI_REG8(0x4e), 0x05},
313	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x05},
314	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x29}, {CCI_REG8(0x4e), 0x05},
315	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x2a}, {CCI_REG8(0x4e), 0x05},
316	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x4a}, {CCI_REG8(0x4e), 0x05},
317	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x06},
318	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x49}, {CCI_REG8(0x4e), 0x06},
319	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06},
320	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x06},
321	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x06},
322	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x48}, {CCI_REG8(0x4e), 0x06},
323	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x68}, {CCI_REG8(0x4e), 0x06},
324	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06},
325	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x07},
326	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x07},
327	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe9}, {CCI_REG8(0x4e), 0x07},
328	{CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x07},
329	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc8}, {CCI_REG8(0x4e), 0x07},
330	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe8}, {CCI_REG8(0x4e), 0x07},
331	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa7}, {CCI_REG8(0x4e), 0x07},
332	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc7}, {CCI_REG8(0x4e), 0x07},
333	{CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe7}, {CCI_REG8(0x4e), 0x07},
334	{CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x07}, {CCI_REG8(0x4e), 0x07},
335	{CCI_REG8(0x4f), 0x01},
336	{CCI_REG8(0x50), 0x80}, {CCI_REG8(0x51), 0xa8}, {CCI_REG8(0x52), 0x47},
337	{CCI_REG8(0x53), 0x38}, {CCI_REG8(0x54), 0xc7}, {CCI_REG8(0x56), 0x0e},
338	{CCI_REG8(0x58), 0x08}, {CCI_REG8(0x5b), 0x00}, {CCI_REG8(0x5c), 0x74},
339	{CCI_REG8(0x5d), 0x8b}, {CCI_REG8(0x61), 0xdb}, {CCI_REG8(0x62), 0xb8},
340	{CCI_REG8(0x63), 0x86}, {CCI_REG8(0x64), 0xc0}, {CCI_REG8(0x65), 0x04},
341	{CCI_REG8(0x67), 0xa8}, {CCI_REG8(0x68), 0xb0}, {CCI_REG8(0x69), 0x00},
342	{CCI_REG8(0x6a), 0xa8}, {CCI_REG8(0x6b), 0xb0}, {CCI_REG8(0x6c), 0xaf},
343	{CCI_REG8(0x6d), 0x8b}, {CCI_REG8(0x6e), 0x50}, {CCI_REG8(0x6f), 0x18},
344	{CCI_REG8(0x73), 0xf0}, {CCI_REG8(0x70), 0x0d}, {CCI_REG8(0x71), 0x60},
345	{CCI_REG8(0x72), 0x80}, {CCI_REG8(0x74), 0x01}, {CCI_REG8(0x75), 0x01},
346	{CCI_REG8(0x7f), 0x0c}, {CCI_REG8(0x76), 0x70}, {CCI_REG8(0x77), 0x58},
347	{CCI_REG8(0x78), 0xa0}, {CCI_REG8(0x79), 0x5e}, {CCI_REG8(0x7a), 0x54},
348	{CCI_REG8(0x7b), 0x58},
349	/* CC */
350	{GC2145_REG_PAGE_SELECT, 0x02},
351	{CCI_REG8(0xc0), 0x01}, {CCI_REG8(0xc1), 0x44}, {CCI_REG8(0xc2), 0xfd},
352	{CCI_REG8(0xc3), 0x04}, {CCI_REG8(0xc4), 0xf0}, {CCI_REG8(0xc5), 0x48},
353	{CCI_REG8(0xc6), 0xfd}, {CCI_REG8(0xc7), 0x46}, {CCI_REG8(0xc8), 0xfd},
354	{CCI_REG8(0xc9), 0x02}, {CCI_REG8(0xca), 0xe0}, {CCI_REG8(0xcb), 0x45},
355	{CCI_REG8(0xcc), 0xec}, {CCI_REG8(0xcd), 0x48}, {CCI_REG8(0xce), 0xf0},
356	{CCI_REG8(0xcf), 0xf0}, {CCI_REG8(0xe3), 0x0c}, {CCI_REG8(0xe4), 0x4b},
357	{CCI_REG8(0xe5), 0xe0},
358	/* ABS */
359	{GC2145_REG_PAGE_SELECT, 0x01},
360	{CCI_REG8(0x9f), 0x40},
361	/* Dark sun */
362	{GC2145_REG_PAGE_SELECT, 0x02},
363	{CCI_REG8(0x40), 0xbf}, {CCI_REG8(0x46), 0xcf},
364};
365
366#define GC2145_640_480_PIXELRATE	30000000
367#define GC2145_640_480_LINKFREQ		120000000
368#define GC2145_640_480_HBLANK		0x0130
369#define GC2145_640_480_VBLANK		0x000c
370static const struct cci_reg_sequence gc2145_mode_640_480_regs[] = {
371	{GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
372	{GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
373	{CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x86},
374	{CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
375	/* Disable PAD IO */
376	{GC2145_REG_PAD_IO, 0x00},
377	{GC2145_REG_PAGE_SELECT, 0x00},
378	/* Row/Col start - 0/0 */
379	{GC2145_REG_ROW_START, 0x0000},
380	{GC2145_REG_COL_START, 0x0000},
381	/* Window size 1216/1618 */
382	{GC2145_REG_WIN_HEIGHT, 0x04c0},
383	{GC2145_REG_WIN_WIDTH, 0x0652},
384	/* Scalar more */
385	{CCI_REG8(0xfd), 0x01}, {CCI_REG8(0xfa), 0x00},
386	/* Crop 640-480@0-0 */
387	{GC2145_REG_CROP_ENABLE, 0x01},
388	{GC2145_REG_CROP_Y, 0x0000},
389	{GC2145_REG_CROP_X, 0x0000},
390	{GC2145_REG_CROP_HEIGHT, 0x01e0},
391	{GC2145_REG_CROP_WIDTH, 0x0280},
392	/* Subsampling configuration */
393	{CCI_REG8(0x99), 0x55}, {CCI_REG8(0x9a), 0x06}, {CCI_REG8(0x9b), 0x01},
394	{CCI_REG8(0x9c), 0x23}, {CCI_REG8(0x9d), 0x00}, {CCI_REG8(0x9e), 0x00},
395	{CCI_REG8(0x9f), 0x01}, {CCI_REG8(0xa0), 0x23}, {CCI_REG8(0xa1), 0x00},
396	{CCI_REG8(0xa2), 0x00},
397	{GC2145_REG_PAGE_SELECT, 0x01},
398	/* AEC anti-flicker */
399	{CCI_REG16(0x25), 0x0175},
400	/* AEC exposure level 1-5 */
401	{CCI_REG16(0x27), 0x045f}, {CCI_REG16(0x29), 0x045f},
402	{CCI_REG16(0x2b), 0x045f}, {CCI_REG16(0x2d), 0x045f},
403};
404
405#define GC2145_1280_720_PIXELRATE	48000000
406#define GC2145_1280_720_LINKFREQ	192000000
407#define GC2145_1280_720_HBLANK		0x0156
408#define GC2145_1280_720_VBLANK		0x0011
409static const struct cci_reg_sequence gc2145_mode_1280_720_regs[] = {
410	{GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
411	{GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
412	{CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x83},
413	{CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
414	/* Disable PAD IO */
415	{GC2145_REG_PAD_IO, 0x00},
416	{GC2145_REG_PAGE_SELECT, 0x00},
417	/* Row/Col start - 240/160 */
418	{GC2145_REG_ROW_START, 0x00f0},
419	{GC2145_REG_COL_START, 0x00a0},
420	/* Window size 736/1296 */
421	{GC2145_REG_WIN_HEIGHT, 0x02e0},
422	{GC2145_REG_WIN_WIDTH, 0x0510},
423	/* Crop 1280-720@0-0 */
424	{GC2145_REG_CROP_ENABLE, 0x01},
425	{GC2145_REG_CROP_Y, 0x0000},
426	{GC2145_REG_CROP_X, 0x0000},
427	{GC2145_REG_CROP_HEIGHT, 0x02d0},
428	{GC2145_REG_CROP_WIDTH, 0x0500},
429	{GC2145_REG_PAGE_SELECT, 0x01},
430	/* AEC anti-flicker */
431	{CCI_REG16(0x25), 0x00e6},
432	/* AEC exposure level 1-5 */
433	{CCI_REG16(0x27), 0x02b2}, {CCI_REG16(0x29), 0x02b2},
434	{CCI_REG16(0x2b), 0x02b2}, {CCI_REG16(0x2d), 0x02b2},
435};
436
437#define GC2145_1600_1200_PIXELRATE	60000000
438#define GC2145_1600_1200_LINKFREQ	240000000
439#define GC2145_1600_1200_HBLANK		0x0156
440#define GC2145_1600_1200_VBLANK		0x0010
441static const struct cci_reg_sequence gc2145_mode_1600_1200_regs[] = {
442	{GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
443	{GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
444	{CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x84},
445	{CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
446	/* Disable PAD IO */
447	{GC2145_REG_PAD_IO, 0x00},
448	{GC2145_REG_PAGE_SELECT, 0x00},
449	/* Row/Col start - 0/0 */
450	{GC2145_REG_ROW_START, 0x0000},
451	{GC2145_REG_COL_START, 0x0000},
452	/* Window size: 1216/1618 */
453	{GC2145_REG_WIN_HEIGHT, 0x04c0},
454	{GC2145_REG_WIN_WIDTH, 0x0652},
455	/* Crop 1600-1200@0-0 */
456	{GC2145_REG_CROP_ENABLE, 0x01},
457	{GC2145_REG_CROP_Y, 0x0000},
458	{GC2145_REG_CROP_X, 0x0000},
459	{GC2145_REG_CROP_HEIGHT, 0x04b0},
460	{GC2145_REG_CROP_WIDTH, 0x0640},
461	{GC2145_REG_PAGE_SELECT, 0x01},
462	/* AEC anti-flicker */
463	{CCI_REG16(0x25), 0x00fa},
464	/* AEC exposure level 1-5 */
465	{CCI_REG16(0x27), 0x04e2}, {CCI_REG16(0x29), 0x04e2},
466	{CCI_REG16(0x2b), 0x04e2}, {CCI_REG16(0x2d), 0x04e2},
467};
468
469static const s64 gc2145_link_freq_menu[] = {
470	GC2145_640_480_LINKFREQ,
471	GC2145_1280_720_LINKFREQ,
472	GC2145_1600_1200_LINKFREQ,
473};
474
475/* Regulators supplies */
476static const char * const gc2145_supply_name[] = {
477	"iovdd", /* Digital I/O (1.7-3V) suppply */
478	"avdd",  /* Analog (2.7-3V) supply */
479	"dvdd",  /* Digital Core (1.7-1.9V) supply */
480};
481
482#define GC2145_NUM_SUPPLIES ARRAY_SIZE(gc2145_supply_name)
483
484/* Mode configs */
485#define GC2145_MODE_640X480	0
486#define GC2145_MODE_1280X720	1
487#define GC2145_MODE_1600X1200	2
488static const struct gc2145_mode supported_modes[] = {
489	{
490		/* 640x480 30fps mode */
491		.width = 640,
492		.height = 480,
493		.reg_seq = gc2145_mode_640_480_regs,
494		.reg_seq_size = ARRAY_SIZE(gc2145_mode_640_480_regs),
495		.pixel_rate = GC2145_640_480_PIXELRATE,
496		.crop = {
497			.top = 0,
498			.left = 0,
499			.width = 640,
500			.height = 480,
501		},
502		.hblank = GC2145_640_480_HBLANK,
503		.vblank = GC2145_640_480_VBLANK,
504		.link_freq_index = GC2145_MODE_640X480,
505	},
506	{
507		/* 1280x720 30fps mode */
508		.width = 1280,
509		.height = 720,
510		.reg_seq = gc2145_mode_1280_720_regs,
511		.reg_seq_size = ARRAY_SIZE(gc2145_mode_1280_720_regs),
512		.pixel_rate = GC2145_1280_720_PIXELRATE,
513		.crop = {
514			.top = 160,
515			.left = 240,
516			.width = 1280,
517			.height = 720,
518		},
519		.hblank = GC2145_1280_720_HBLANK,
520		.vblank = GC2145_1280_720_VBLANK,
521		.link_freq_index = GC2145_MODE_1280X720,
522	},
523	{
524		/* 1600x1200 20fps mode */
525		.width = 1600,
526		.height = 1200,
527		.reg_seq = gc2145_mode_1600_1200_regs,
528		.reg_seq_size = ARRAY_SIZE(gc2145_mode_1600_1200_regs),
529		.pixel_rate = GC2145_1600_1200_PIXELRATE,
530		.crop = {
531			.top = 0,
532			.left = 0,
533			.width = 1600,
534			.height = 1200,
535		},
536		.hblank = GC2145_1600_1200_HBLANK,
537		.vblank = GC2145_1600_1200_VBLANK,
538		.link_freq_index = GC2145_MODE_1600X1200,
539	},
540};
541
542/**
543 * struct gc2145_format - GC2145 pixel format description
544 * @code: media bus (MBUS) associated code
545 * @datatype: MIPI CSI2 data type
546 * @output_fmt: GC2145 output format
547 * @switch_bit: GC2145 first/second switch
548 */
549struct gc2145_format {
550	unsigned int code;
551	unsigned char datatype;
552	unsigned char output_fmt;
553	bool switch_bit;
554};
555
556/* All supported formats */
557static const struct gc2145_format supported_formats[] = {
558	{
559		.code		= MEDIA_BUS_FMT_UYVY8_1X16,
560		.datatype	= MIPI_CSI2_DT_YUV422_8B,
561		.output_fmt	= 0x00,
562	},
563	{
564		.code		= MEDIA_BUS_FMT_VYUY8_1X16,
565		.datatype	= MIPI_CSI2_DT_YUV422_8B,
566		.output_fmt	= 0x01,
567	},
568	{
569		.code		= MEDIA_BUS_FMT_YUYV8_1X16,
570		.datatype	= MIPI_CSI2_DT_YUV422_8B,
571		.output_fmt	= 0x02,
572	},
573	{
574		.code		= MEDIA_BUS_FMT_YVYU8_1X16,
575		.datatype	= MIPI_CSI2_DT_YUV422_8B,
576		.output_fmt	= 0x03,
577	},
578	{
579		.code		= MEDIA_BUS_FMT_RGB565_1X16,
580		.datatype	= MIPI_CSI2_DT_RGB565,
581		.output_fmt	= 0x06,
582		.switch_bit	= true,
583	},
584};
585
586struct gc2145_ctrls {
587	struct v4l2_ctrl_handler handler;
588	struct v4l2_ctrl *pixel_rate;
589	struct v4l2_ctrl *link_freq;
590	struct v4l2_ctrl *test_pattern;
591	struct v4l2_ctrl *hflip;
592	struct v4l2_ctrl *vflip;
593	struct v4l2_ctrl *hblank;
594	struct v4l2_ctrl *vblank;
595};
596
597struct gc2145 {
598	struct v4l2_subdev sd;
599	struct media_pad pad;
600
601	struct regmap *regmap;
602	struct clk *xclk;
603
604	struct gpio_desc *reset_gpio;
605	struct gpio_desc *powerdown_gpio;
606	struct regulator_bulk_data supplies[GC2145_NUM_SUPPLIES];
607
608	/* V4L2 controls */
609	struct gc2145_ctrls ctrls;
610
611	/* Current mode */
612	const struct gc2145_mode *mode;
613};
614
615static inline struct gc2145 *to_gc2145(struct v4l2_subdev *_sd)
616{
617	return container_of(_sd, struct gc2145, sd);
618}
619
620static inline struct v4l2_subdev *gc2145_ctrl_to_sd(struct v4l2_ctrl *ctrl)
621{
622	return &container_of(ctrl->handler, struct gc2145,
623			     ctrls.handler)->sd;
624}
625
626static const struct gc2145_format *
627gc2145_get_format_code(struct gc2145 *gc2145, u32 code)
628{
629	unsigned int i;
630
631	for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
632		if (supported_formats[i].code == code)
633			break;
634	}
635
636	if (i >= ARRAY_SIZE(supported_formats))
637		i = 0;
638
639	return &supported_formats[i];
640}
641
642static void gc2145_update_pad_format(struct gc2145 *gc2145,
643				     const struct gc2145_mode *mode,
644				     struct v4l2_mbus_framefmt *fmt, u32 code)
645{
646	fmt->code = code;
647	fmt->width = mode->width;
648	fmt->height = mode->height;
649	fmt->field = V4L2_FIELD_NONE;
650	fmt->colorspace = V4L2_COLORSPACE_SRGB;
651	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
652	fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
653	fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
654}
655
656static int gc2145_init_state(struct v4l2_subdev *sd,
657			     struct v4l2_subdev_state *state)
658{
659	struct gc2145 *gc2145 = to_gc2145(sd);
660	struct v4l2_mbus_framefmt *format;
661	struct v4l2_rect *crop;
662
663	/* Initialize pad format */
664	format = v4l2_subdev_state_get_format(state, 0);
665	gc2145_update_pad_format(gc2145, &supported_modes[0], format,
666				 MEDIA_BUS_FMT_RGB565_1X16);
667
668	/* Initialize crop rectangle. */
669	crop = v4l2_subdev_state_get_crop(state, 0);
670	*crop = supported_modes[0].crop;
671
672	return 0;
673}
674
675static int gc2145_get_selection(struct v4l2_subdev *sd,
676				struct v4l2_subdev_state *sd_state,
677				struct v4l2_subdev_selection *sel)
678{
679	switch (sel->target) {
680	case V4L2_SEL_TGT_CROP:
681		sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
682		return 0;
683
684	case V4L2_SEL_TGT_NATIVE_SIZE:
685		sel->r.top = 0;
686		sel->r.left = 0;
687		sel->r.width = GC2145_NATIVE_WIDTH;
688		sel->r.height = GC2145_NATIVE_HEIGHT;
689
690		return 0;
691
692	case V4L2_SEL_TGT_CROP_DEFAULT:
693	case V4L2_SEL_TGT_CROP_BOUNDS:
694		sel->r.top = 0;
695		sel->r.left = 0;
696		sel->r.width = 1600;
697		sel->r.height = 1200;
698
699		return 0;
700	}
701
702	return -EINVAL;
703}
704
705static int gc2145_enum_mbus_code(struct v4l2_subdev *sd,
706				 struct v4l2_subdev_state *sd_state,
707				 struct v4l2_subdev_mbus_code_enum *code)
708{
709	if (code->index >= ARRAY_SIZE(supported_formats))
710		return -EINVAL;
711
712	code->code = supported_formats[code->index].code;
713	return 0;
714}
715
716static int gc2145_enum_frame_size(struct v4l2_subdev *sd,
717				  struct v4l2_subdev_state *sd_state,
718				  struct v4l2_subdev_frame_size_enum *fse)
719{
720	struct gc2145 *gc2145 = to_gc2145(sd);
721	const struct gc2145_format *gc2145_format;
722	u32 code;
723
724	if (fse->index >= ARRAY_SIZE(supported_modes))
725		return -EINVAL;
726
727	gc2145_format = gc2145_get_format_code(gc2145, fse->code);
728	code = gc2145_format->code;
729	if (fse->code != code)
730		return -EINVAL;
731
732	fse->min_width = supported_modes[fse->index].width;
733	fse->max_width = fse->min_width;
734	fse->min_height = supported_modes[fse->index].height;
735	fse->max_height = fse->min_height;
736
737	return 0;
738}
739
740static int gc2145_set_pad_format(struct v4l2_subdev *sd,
741				 struct v4l2_subdev_state *sd_state,
742				 struct v4l2_subdev_format *fmt)
743{
744	struct gc2145 *gc2145 = to_gc2145(sd);
745	const struct gc2145_mode *mode;
746	const struct gc2145_format *gc2145_fmt;
747	struct v4l2_mbus_framefmt *framefmt;
748	struct gc2145_ctrls *ctrls = &gc2145->ctrls;
749	struct v4l2_rect *crop;
750
751	gc2145_fmt = gc2145_get_format_code(gc2145, fmt->format.code);
752	mode = v4l2_find_nearest_size(supported_modes,
753				      ARRAY_SIZE(supported_modes),
754				      width, height,
755				      fmt->format.width, fmt->format.height);
756
757	gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code);
758	framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
759	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
760		gc2145->mode = mode;
761		/* Update pixel_rate based on the mode */
762		__v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mode->pixel_rate);
763		/* Update link_freq based on the mode */
764		__v4l2_ctrl_s_ctrl(ctrls->link_freq, mode->link_freq_index);
765		/* Update hblank/vblank based on the mode */
766		__v4l2_ctrl_s_ctrl(ctrls->hblank, mode->hblank);
767		__v4l2_ctrl_s_ctrl(ctrls->vblank, mode->vblank);
768	}
769	*framefmt = fmt->format;
770	crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad);
771	*crop = mode->crop;
772
773	return 0;
774}
775
776static const struct cci_reg_sequence gc2145_common_mipi_regs[] = {
777	{GC2145_REG_PAGE_SELECT, 0x03},
778	{GC2145_REG_DPHY_ANALOG_MODE1, GC2145_DPHY_MODE_PHY_CLK_EN |
779				       GC2145_DPHY_MODE_PHY_LANE0_EN |
780				       GC2145_DPHY_MODE_PHY_LANE1_EN |
781				       GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL},
782	{GC2145_REG_DPHY_ANALOG_MODE2, GC2145_DPHY_CLK_DIFF(2) |
783				       GC2145_DPHY_LANE0_DIFF(2)},
784	{GC2145_REG_DPHY_ANALOG_MODE3, GC2145_DPHY_LANE1_DIFF(0) |
785				       GC2145_DPHY_CLK_DELAY},
786	{GC2145_REG_FIFO_MODE, GC2145_FIFO_MODE_READ_GATE |
787			       GC2145_FIFO_MODE_MIPI_CLK_MODULE},
788	{GC2145_REG_DPHY_MODE, GC2145_DPHY_MODE_TRIGGER_PROG},
789	/* Clock & Data lanes timing */
790	{GC2145_REG_T_LPX, 0x10},
791	{GC2145_REG_T_CLK_HS_PREPARE, 0x04}, {GC2145_REG_T_CLK_ZERO, 0x10},
792	{GC2145_REG_T_CLK_PRE, 0x10}, {GC2145_REG_T_CLK_POST, 0x10},
793	{GC2145_REG_T_CLK_TRAIL, 0x05},
794	{GC2145_REG_T_HS_PREPARE, 0x03}, {GC2145_REG_T_HS_ZERO, 0x0a},
795	{GC2145_REG_T_HS_TRAIL, 0x06},
796};
797
798static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
799				   const struct gc2145_format *gc2145_format)
800{
801	u16 lwc, fifo_full_lvl;
802	int ret = 0;
803
804	/* Common MIPI settings */
805	cci_multi_reg_write(gc2145->regmap, gc2145_common_mipi_regs,
806			    ARRAY_SIZE(gc2145_common_mipi_regs), &ret);
807
808	/*
809	 * Adjust the MIPI buffer settings.
810	 * For YUV/RGB, LWC = image width * 2
811	 * For RAW8, LWC = image width
812	 * For RAW10, LWC = image width * 1.25
813	 */
814	lwc = gc2145->mode->width * 2;
815	cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret);
816	cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret);
817
818	/*
819	 * Adjust the MIPI FIFO Full Level
820	 * 640x480 RGB: 0x0190
821	 * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001
822	 * 1600x1200 RAW: 0x0190
823	 */
824	if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
825		fifo_full_lvl = 0x0001;
826	else
827		fifo_full_lvl = 0x0190;
828
829	cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH,
830		  fifo_full_lvl >> 8, &ret);
831	cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW,
832		  fifo_full_lvl & 0xff, &ret);
833
834	/*
835	 * Set the FIFO gate mode / MIPI wdiv set:
836	 * 0xf1 in case of RAW mode and 0xf0 otherwise
837	 */
838	cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret);
839
840	/* Set the MIPI data type */
841	cci_write(gc2145->regmap, GC2145_REG_MIPI_DT,
842		  gc2145_format->datatype, &ret);
843
844	/* Configure mode and enable CSI */
845	cci_write(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE,
846		  GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
847		  GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, &ret);
848
849	return ret;
850}
851
852static int gc2145_start_streaming(struct gc2145 *gc2145,
853				  struct v4l2_subdev_state *state)
854{
855	struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
856	const struct gc2145_format *gc2145_format;
857	struct v4l2_mbus_framefmt *fmt;
858	int ret;
859
860	ret = pm_runtime_resume_and_get(&client->dev);
861	if (ret < 0)
862		return ret;
863
864	/* Apply default values of current mode */
865	cci_multi_reg_write(gc2145->regmap, gc2145->mode->reg_seq,
866			    gc2145->mode->reg_seq_size, &ret);
867	cci_multi_reg_write(gc2145->regmap, gc2145_common_regs,
868			    ARRAY_SIZE(gc2145_common_regs), &ret);
869	if (ret) {
870		dev_err(&client->dev, "%s failed to write regs\n", __func__);
871		goto err_rpm_put;
872	}
873
874	fmt = v4l2_subdev_state_get_format(state, 0);
875	gc2145_format = gc2145_get_format_code(gc2145, fmt->code);
876
877	/* Set the output format */
878	cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
879
880	cci_write(gc2145->regmap, GC2145_REG_OUTPUT_FMT,
881		  gc2145_format->output_fmt, &ret);
882	cci_update_bits(gc2145->regmap, GC2145_REG_BYPASS_MODE,
883			GC2145_BYPASS_MODE_SWITCH,
884			gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH
885						  : 0, &ret);
886	if (ret) {
887		dev_err(&client->dev, "%s failed to write regs\n", __func__);
888		goto err_rpm_put;
889	}
890
891	/* Apply customized values from user */
892	ret =  __v4l2_ctrl_handler_setup(&gc2145->ctrls.handler);
893	if (ret) {
894		dev_err(&client->dev, "%s failed to apply ctrls\n", __func__);
895		goto err_rpm_put;
896	}
897
898	/* Perform MIPI specific configuration */
899	ret = gc2145_config_mipi_mode(gc2145, gc2145_format);
900	if (ret) {
901		dev_err(&client->dev, "%s failed to write mipi conf\n",
902			__func__);
903		goto err_rpm_put;
904	}
905
906	cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
907
908	return 0;
909
910err_rpm_put:
911	pm_runtime_mark_last_busy(&client->dev);
912	pm_runtime_put_autosuspend(&client->dev);
913	return ret;
914}
915
916static void gc2145_stop_streaming(struct gc2145 *gc2145)
917{
918	struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
919	int ret = 0;
920
921	/* Disable lanes & mipi streaming */
922	cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x03, &ret);
923	cci_update_bits(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE,
924			GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, 0,
925			&ret);
926	cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
927	if (ret)
928		dev_err(&client->dev, "%s failed to write regs\n", __func__);
929
930	pm_runtime_mark_last_busy(&client->dev);
931	pm_runtime_put_autosuspend(&client->dev);
932}
933
934static int gc2145_set_stream(struct v4l2_subdev *sd, int enable)
935{
936	struct gc2145 *gc2145 = to_gc2145(sd);
937	struct v4l2_subdev_state *state;
938	int ret = 0;
939
940	state = v4l2_subdev_lock_and_get_active_state(sd);
941
942	if (enable)
943		ret = gc2145_start_streaming(gc2145, state);
944	else
945		gc2145_stop_streaming(gc2145);
946
947	v4l2_subdev_unlock_state(state);
948
949	return ret;
950}
951
952/* Power/clock management functions */
953static int gc2145_power_on(struct device *dev)
954{
955	struct v4l2_subdev *sd = dev_get_drvdata(dev);
956	struct gc2145 *gc2145 = to_gc2145(sd);
957	int ret;
958
959	ret = regulator_bulk_enable(GC2145_NUM_SUPPLIES, gc2145->supplies);
960	if (ret) {
961		dev_err(dev, "failed to enable regulators\n");
962		return ret;
963	}
964
965	ret = clk_prepare_enable(gc2145->xclk);
966	if (ret) {
967		dev_err(dev, "failed to enable clock\n");
968		goto reg_off;
969	}
970
971	gpiod_set_value_cansleep(gc2145->powerdown_gpio, 0);
972	gpiod_set_value_cansleep(gc2145->reset_gpio, 0);
973
974	/*
975	 * Datasheet doesn't mention timing between PWDN/RESETB control and
976	 * i2c access however, experimentation shows that a rather big delay is
977	 * needed.
978	 */
979	msleep(41);
980
981	return 0;
982
983reg_off:
984	regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies);
985
986	return ret;
987}
988
989static int gc2145_power_off(struct device *dev)
990{
991	struct v4l2_subdev *sd = dev_get_drvdata(dev);
992	struct gc2145 *gc2145 = to_gc2145(sd);
993
994	gpiod_set_value_cansleep(gc2145->powerdown_gpio, 1);
995	gpiod_set_value_cansleep(gc2145->reset_gpio, 1);
996	clk_disable_unprepare(gc2145->xclk);
997	regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies);
998
999	return 0;
1000}
1001
1002static int gc2145_get_regulators(struct gc2145 *gc2145)
1003{
1004	struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
1005	unsigned int i;
1006
1007	for (i = 0; i < GC2145_NUM_SUPPLIES; i++)
1008		gc2145->supplies[i].supply = gc2145_supply_name[i];
1009
1010	return devm_regulator_bulk_get(&client->dev, GC2145_NUM_SUPPLIES,
1011				       gc2145->supplies);
1012}
1013
1014/* Verify chip ID */
1015static int gc2145_identify_module(struct gc2145 *gc2145)
1016{
1017	struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
1018	int ret;
1019	u64 chip_id;
1020
1021	ret = cci_read(gc2145->regmap, GC2145_REG_CHIP_ID, &chip_id, NULL);
1022	if (ret) {
1023		dev_err(&client->dev, "failed to read chip id (%d)\n", ret);
1024		return ret;
1025	}
1026
1027	if (chip_id != GC2145_CHIP_ID) {
1028		dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
1029			GC2145_CHIP_ID, chip_id);
1030		return -EIO;
1031	}
1032
1033	return 0;
1034}
1035
1036static const char * const test_pattern_menu[] = {
1037	"Disabled",
1038	"Colored patterns",
1039	"Uniform white",
1040	"Uniform yellow",
1041	"Uniform cyan",
1042	"Uniform green",
1043	"Uniform magenta",
1044	"Uniform red",
1045	"Uniform black",
1046};
1047
1048#define GC2145_TEST_PATTERN_ENABLE	BIT(0)
1049#define GC2145_TEST_PATTERN_UXGA	BIT(3)
1050
1051#define GC2145_TEST_UNIFORM		BIT(3)
1052#define GC2145_TEST_WHITE		(4 << 4)
1053#define GC2145_TEST_YELLOW		(8 << 4)
1054#define GC2145_TEST_CYAN		(9 << 4)
1055#define GC2145_TEST_GREEN		(6 << 4)
1056#define GC2145_TEST_MAGENTA		(10 << 4)
1057#define GC2145_TEST_RED			(5 << 4)
1058#define GC2145_TEST_BLACK		(0)
1059
1060static const u8 test_pattern_val[] = {
1061	0,
1062	GC2145_TEST_PATTERN_ENABLE,
1063	GC2145_TEST_UNIFORM | GC2145_TEST_WHITE,
1064	GC2145_TEST_UNIFORM | GC2145_TEST_YELLOW,
1065	GC2145_TEST_UNIFORM | GC2145_TEST_CYAN,
1066	GC2145_TEST_UNIFORM | GC2145_TEST_GREEN,
1067	GC2145_TEST_UNIFORM | GC2145_TEST_MAGENTA,
1068	GC2145_TEST_UNIFORM | GC2145_TEST_RED,
1069	GC2145_TEST_UNIFORM | GC2145_TEST_BLACK,
1070};
1071
1072static const struct v4l2_subdev_core_ops gc2145_core_ops = {
1073	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1074	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1075};
1076
1077static const struct v4l2_subdev_video_ops gc2145_video_ops = {
1078	.s_stream = gc2145_set_stream,
1079};
1080
1081static const struct v4l2_subdev_pad_ops gc2145_pad_ops = {
1082	.enum_mbus_code = gc2145_enum_mbus_code,
1083	.get_fmt = v4l2_subdev_get_fmt,
1084	.set_fmt = gc2145_set_pad_format,
1085	.get_selection = gc2145_get_selection,
1086	.enum_frame_size = gc2145_enum_frame_size,
1087};
1088
1089static const struct v4l2_subdev_ops gc2145_subdev_ops = {
1090	.core = &gc2145_core_ops,
1091	.video = &gc2145_video_ops,
1092	.pad = &gc2145_pad_ops,
1093};
1094
1095static const struct v4l2_subdev_internal_ops gc2145_subdev_internal_ops = {
1096	.init_state = gc2145_init_state,
1097};
1098
1099static int gc2145_set_ctrl_test_pattern(struct gc2145 *gc2145, int value)
1100{
1101	int ret = 0;
1102
1103	if (!value) {
1104		/* Disable test pattern */
1105		cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2, 0, &ret);
1106		return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0,
1107				 &ret);
1108	}
1109
1110	/* Enable test pattern, colored or uniform */
1111	cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2,
1112		  GC2145_TEST_PATTERN_ENABLE | GC2145_TEST_PATTERN_UXGA, &ret);
1113
1114	if (!(test_pattern_val[value] & GC2145_TEST_UNIFORM))
1115		return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0,
1116				 &ret);
1117
1118	/* Uniform */
1119	return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3,
1120			 test_pattern_val[value], &ret);
1121}
1122
1123static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl)
1124{
1125	struct v4l2_subdev *sd = gc2145_ctrl_to_sd(ctrl);
1126	struct i2c_client *client = v4l2_get_subdevdata(sd);
1127	struct gc2145 *gc2145 = to_gc2145(sd);
1128	int ret;
1129
1130	if (pm_runtime_get_if_in_use(&client->dev) == 0)
1131		return 0;
1132
1133	switch (ctrl->id) {
1134	case V4L2_CID_HBLANK:
1135		ret = cci_write(gc2145->regmap, GC2145_REG_HBLANK, ctrl->val,
1136				NULL);
1137		break;
1138	case V4L2_CID_VBLANK:
1139		ret = cci_write(gc2145->regmap, GC2145_REG_VBLANK, ctrl->val,
1140				NULL);
1141		break;
1142	case V4L2_CID_TEST_PATTERN:
1143		ret = gc2145_set_ctrl_test_pattern(gc2145, ctrl->val);
1144		break;
1145	case V4L2_CID_HFLIP:
1146		ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1,
1147				      BIT(0), (ctrl->val ? BIT(0) : 0), NULL);
1148		break;
1149	case V4L2_CID_VFLIP:
1150		ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1,
1151				      BIT(1), (ctrl->val ? BIT(1) : 0), NULL);
1152		break;
1153	default:
1154		ret = -EINVAL;
1155		break;
1156	}
1157
1158	pm_runtime_mark_last_busy(&client->dev);
1159	pm_runtime_put_autosuspend(&client->dev);
1160
1161	return ret;
1162}
1163
1164static const struct v4l2_ctrl_ops gc2145_ctrl_ops = {
1165	.s_ctrl = gc2145_s_ctrl,
1166};
1167
1168/* Initialize control handlers */
1169static int gc2145_init_controls(struct gc2145 *gc2145)
1170{
1171	struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
1172	const struct v4l2_ctrl_ops *ops = &gc2145_ctrl_ops;
1173	struct gc2145_ctrls *ctrls = &gc2145->ctrls;
1174	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
1175	struct v4l2_fwnode_device_properties props;
1176	int ret;
1177
1178	ret = v4l2_ctrl_handler_init(hdl, 12);
1179	if (ret)
1180		return ret;
1181
1182	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
1183					      GC2145_640_480_PIXELRATE,
1184					      GC2145_1600_1200_PIXELRATE, 1,
1185					      supported_modes[0].pixel_rate);
1186
1187	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
1188						  ARRAY_SIZE(gc2145_link_freq_menu) - 1,
1189						  0, gc2145_link_freq_menu);
1190	if (ctrls->link_freq)
1191		ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1192
1193	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
1194					  0, 0xfff, 1, GC2145_640_480_HBLANK);
1195
1196	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
1197					  0, 0x1fff, 1, GC2145_640_480_VBLANK);
1198
1199	ctrls->test_pattern =
1200		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
1201					     ARRAY_SIZE(test_pattern_menu) - 1,
1202					     0, 0, test_pattern_menu);
1203	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
1204					 0, 1, 1, 0);
1205	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
1206					 0, 1, 1, 0);
1207
1208	if (hdl->error) {
1209		ret = hdl->error;
1210		dev_err(&client->dev, "control init failed (%d)\n", ret);
1211		goto error;
1212	}
1213
1214	ret = v4l2_fwnode_device_parse(&client->dev, &props);
1215	if (ret)
1216		goto error;
1217
1218	ret = v4l2_ctrl_new_fwnode_properties(hdl, &gc2145_ctrl_ops,
1219					      &props);
1220	if (ret)
1221		goto error;
1222
1223	gc2145->sd.ctrl_handler = hdl;
1224
1225	return 0;
1226
1227error:
1228	v4l2_ctrl_handler_free(hdl);
1229
1230	return ret;
1231}
1232
1233static int gc2145_check_hwcfg(struct device *dev)
1234{
1235	struct fwnode_handle *endpoint;
1236	struct v4l2_fwnode_endpoint ep_cfg = {
1237		.bus_type = V4L2_MBUS_CSI2_DPHY
1238	};
1239	int ret;
1240
1241	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
1242	if (!endpoint) {
1243		dev_err(dev, "endpoint node not found\n");
1244		return -EINVAL;
1245	}
1246
1247	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg);
1248	fwnode_handle_put(endpoint);
1249	if (ret)
1250		return ret;
1251
1252	/* Check the number of MIPI CSI2 data lanes */
1253	if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
1254		dev_err(dev, "only 2 data lanes are currently supported\n");
1255		ret = -EINVAL;
1256		goto out;
1257	}
1258
1259	/* Check the link frequency set in device tree */
1260	if (!ep_cfg.nr_of_link_frequencies) {
1261		dev_err(dev, "link-frequency property not found in DT\n");
1262		ret = -EINVAL;
1263		goto out;
1264	}
1265
1266	if (ep_cfg.nr_of_link_frequencies != 3 ||
1267	    ep_cfg.link_frequencies[0] != GC2145_640_480_LINKFREQ ||
1268	    ep_cfg.link_frequencies[1] != GC2145_1280_720_LINKFREQ ||
1269	    ep_cfg.link_frequencies[2] != GC2145_1600_1200_LINKFREQ) {
1270		dev_err(dev, "Invalid link-frequencies provided\n");
1271		ret = -EINVAL;
1272	}
1273
1274out:
1275	v4l2_fwnode_endpoint_free(&ep_cfg);
1276
1277	return ret;
1278}
1279
1280static int gc2145_probe(struct i2c_client *client)
1281{
1282	struct device *dev = &client->dev;
1283	unsigned int xclk_freq;
1284	struct gc2145 *gc2145;
1285	int ret;
1286
1287	gc2145 = devm_kzalloc(&client->dev, sizeof(*gc2145), GFP_KERNEL);
1288	if (!gc2145)
1289		return -ENOMEM;
1290
1291	v4l2_i2c_subdev_init(&gc2145->sd, client, &gc2145_subdev_ops);
1292	gc2145->sd.internal_ops = &gc2145_subdev_internal_ops;
1293
1294	/* Check the hardware configuration in device tree */
1295	if (gc2145_check_hwcfg(dev))
1296		return -EINVAL;
1297
1298	/* Get system clock (xclk) */
1299	gc2145->xclk = devm_clk_get(dev, NULL);
1300	if (IS_ERR(gc2145->xclk))
1301		return dev_err_probe(dev, PTR_ERR(gc2145->xclk),
1302				     "failed to get xclk\n");
1303
1304	xclk_freq = clk_get_rate(gc2145->xclk);
1305	if (xclk_freq != GC2145_XCLK_FREQ) {
1306		dev_err(dev, "xclk frequency not supported: %d Hz\n",
1307			xclk_freq);
1308		return -EINVAL;
1309	}
1310
1311	ret = gc2145_get_regulators(gc2145);
1312	if (ret)
1313		return dev_err_probe(dev, ret,
1314				     "failed to get regulators\n");
1315
1316	/* Request optional reset pin */
1317	gc2145->reset_gpio = devm_gpiod_get_optional(dev, "reset",
1318						     GPIOD_OUT_HIGH);
1319	if (IS_ERR(gc2145->reset_gpio))
1320		return dev_err_probe(dev, PTR_ERR(gc2145->reset_gpio),
1321				     "failed to get reset_gpio\n");
1322
1323	/* Request optional powerdown pin */
1324	gc2145->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
1325							 GPIOD_OUT_HIGH);
1326	if (IS_ERR(gc2145->powerdown_gpio))
1327		return dev_err_probe(dev, PTR_ERR(gc2145->powerdown_gpio),
1328				     "failed to get powerdown_gpio\n");
1329
1330	/* Initialise the regmap for further cci access */
1331	gc2145->regmap = devm_cci_regmap_init_i2c(client, 8);
1332	if (IS_ERR(gc2145->regmap))
1333		return dev_err_probe(dev, PTR_ERR(gc2145->regmap),
1334				     "failed to get cci regmap\n");
1335
1336	/*
1337	 * The sensor must be powered for gc2145_identify_module()
1338	 * to be able to read the CHIP_ID register
1339	 */
1340	ret = gc2145_power_on(dev);
1341	if (ret)
1342		return ret;
1343
1344	ret = gc2145_identify_module(gc2145);
1345	if (ret)
1346		goto error_power_off;
1347
1348	/* Set default mode */
1349	gc2145->mode = &supported_modes[0];
1350
1351	ret = gc2145_init_controls(gc2145);
1352	if (ret)
1353		goto error_power_off;
1354
1355	/* Initialize subdev */
1356	gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
1357			    V4L2_SUBDEV_FL_HAS_EVENTS;
1358	gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1359
1360	/* Initialize source pad */
1361	gc2145->pad.flags = MEDIA_PAD_FL_SOURCE;
1362
1363	ret = media_entity_pads_init(&gc2145->sd.entity, 1, &gc2145->pad);
1364	if (ret) {
1365		dev_err(dev, "failed to init entity pads: %d\n", ret);
1366		goto error_handler_free;
1367	}
1368
1369	gc2145->sd.state_lock = gc2145->ctrls.handler.lock;
1370	ret = v4l2_subdev_init_finalize(&gc2145->sd);
1371	if (ret < 0) {
1372		dev_err(dev, "subdev init error: %d\n", ret);
1373		goto error_media_entity;
1374	}
1375
1376	/* Enable runtime PM and turn off the device */
1377	pm_runtime_set_active(dev);
1378	pm_runtime_get_noresume(&client->dev);
1379	pm_runtime_enable(dev);
1380
1381	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
1382	pm_runtime_use_autosuspend(&client->dev);
1383	pm_runtime_put_autosuspend(&client->dev);
1384
1385	ret = v4l2_async_register_subdev_sensor(&gc2145->sd);
1386	if (ret < 0) {
1387		dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
1388		goto error_subdev_cleanup;
1389	}
1390
1391	return 0;
1392
1393error_subdev_cleanup:
1394	v4l2_subdev_cleanup(&gc2145->sd);
1395	pm_runtime_disable(&client->dev);
1396	pm_runtime_set_suspended(&client->dev);
1397
1398error_media_entity:
1399	media_entity_cleanup(&gc2145->sd.entity);
1400
1401error_handler_free:
1402	v4l2_ctrl_handler_free(&gc2145->ctrls.handler);
1403
1404error_power_off:
1405	gc2145_power_off(dev);
1406
1407	return ret;
1408}
1409
1410static void gc2145_remove(struct i2c_client *client)
1411{
1412	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1413	struct gc2145 *gc2145 = to_gc2145(sd);
1414
1415	v4l2_subdev_cleanup(sd);
1416	v4l2_async_unregister_subdev(sd);
1417	media_entity_cleanup(&sd->entity);
1418	v4l2_ctrl_handler_free(&gc2145->ctrls.handler);
1419
1420	pm_runtime_disable(&client->dev);
1421	if (!pm_runtime_status_suspended(&client->dev))
1422		gc2145_power_off(&client->dev);
1423	pm_runtime_set_suspended(&client->dev);
1424}
1425
1426static const struct of_device_id gc2145_dt_ids[] = {
1427	{ .compatible = "galaxycore,gc2145" },
1428	{ /* sentinel */ }
1429};
1430MODULE_DEVICE_TABLE(of, gc2145_dt_ids);
1431
1432static const struct dev_pm_ops gc2145_pm_ops = {
1433	RUNTIME_PM_OPS(gc2145_power_off, gc2145_power_on, NULL)
1434};
1435
1436static struct i2c_driver gc2145_i2c_driver = {
1437	.driver = {
1438		.name = "gc2145",
1439		.of_match_table	= gc2145_dt_ids,
1440		.pm = pm_ptr(&gc2145_pm_ops),
1441	},
1442	.probe = gc2145_probe,
1443	.remove = gc2145_remove,
1444};
1445
1446module_i2c_driver(gc2145_i2c_driver);
1447
1448MODULE_AUTHOR("Alain Volmat <alain.volmat@foss.st.com>");
1449MODULE_DESCRIPTION("GalaxyCore GC2145 sensor driver");
1450MODULE_LICENSE("GPL");
1451