xref: /linux/drivers/media/i2c/t4ka3.c (revision 00c6649bafef628955569dd39a59e3170e48f7b5)
1*fd553196SKate Hsuan // SPDX-License-Identifier: GPL-2.0
2*fd553196SKate Hsuan /*
3*fd553196SKate Hsuan  * Support for T4KA3 8M camera sensor.
4*fd553196SKate Hsuan  *
5*fd553196SKate Hsuan  * Copyright (C) 2015 Intel Corporation. All Rights Reserved.
6*fd553196SKate Hsuan  * Copyright (C) 2016 XiaoMi, Inc.
7*fd553196SKate Hsuan  * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
8*fd553196SKate Hsuan  * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com>
9*fd553196SKate Hsuan  */
10*fd553196SKate Hsuan 
11*fd553196SKate Hsuan #include <linux/acpi.h>
12*fd553196SKate Hsuan #include <linux/bits.h>
13*fd553196SKate Hsuan #include <linux/delay.h>
14*fd553196SKate Hsuan #include <linux/dev_printk.h>
15*fd553196SKate Hsuan #include <linux/device.h>
16*fd553196SKate Hsuan #include <linux/err.h>
17*fd553196SKate Hsuan #include <linux/errno.h>
18*fd553196SKate Hsuan #include <linux/gpio/consumer.h>
19*fd553196SKate Hsuan #include <linux/i2c.h>
20*fd553196SKate Hsuan #include <linux/mod_devicetable.h>
21*fd553196SKate Hsuan #include <linux/mutex.h>
22*fd553196SKate Hsuan #include <linux/pm_runtime.h>
23*fd553196SKate Hsuan #include <linux/regmap.h>
24*fd553196SKate Hsuan #include <linux/types.h>
25*fd553196SKate Hsuan 
26*fd553196SKate Hsuan #include <media/media-entity.h>
27*fd553196SKate Hsuan #include <media/v4l2-async.h>
28*fd553196SKate Hsuan #include <media/v4l2-cci.h>
29*fd553196SKate Hsuan #include <media/v4l2-common.h>
30*fd553196SKate Hsuan #include <media/v4l2-ctrls.h>
31*fd553196SKate Hsuan #include <media/v4l2-fwnode.h>
32*fd553196SKate Hsuan #include <media/v4l2-subdev.h>
33*fd553196SKate Hsuan 
34*fd553196SKate Hsuan #define T4KA3_NATIVE_WIDTH			3280
35*fd553196SKate Hsuan #define T4KA3_NATIVE_HEIGHT			2464
36*fd553196SKate Hsuan #define T4KA3_NATIVE_START_LEFT			0
37*fd553196SKate Hsuan #define T4KA3_NATIVE_START_TOP			0
38*fd553196SKate Hsuan #define T4KA3_ACTIVE_WIDTH			3280
39*fd553196SKate Hsuan #define T4KA3_ACTIVE_HEIGHT			2460
40*fd553196SKate Hsuan #define T4KA3_ACTIVE_START_LEFT			0
41*fd553196SKate Hsuan #define T4KA3_ACTIVE_START_TOP			2
42*fd553196SKate Hsuan #define T4KA3_MIN_CROP_WIDTH			2
43*fd553196SKate Hsuan #define T4KA3_MIN_CROP_HEIGHT			2
44*fd553196SKate Hsuan 
45*fd553196SKate Hsuan #define T4KA3_PIXELS_PER_LINE			3440
46*fd553196SKate Hsuan #define T4KA3_LINES_PER_FRAME_30FPS		2492
47*fd553196SKate Hsuan #define T4KA3_FPS				30
48*fd553196SKate Hsuan #define T4KA3_PIXEL_RATE \
49*fd553196SKate Hsuan 	(T4KA3_PIXELS_PER_LINE * T4KA3_LINES_PER_FRAME_30FPS * T4KA3_FPS)
50*fd553196SKate Hsuan 
51*fd553196SKate Hsuan /*
52*fd553196SKate Hsuan  * TODO this really should be derived from the 19.2 MHz xvclk combined
53*fd553196SKate Hsuan  * with the PLL settings. But without a datasheet this is the closest
54*fd553196SKate Hsuan  * approximation possible.
55*fd553196SKate Hsuan  *
56*fd553196SKate Hsuan  * link-freq = pixel_rate * bpp / (lanes * 2)
57*fd553196SKate Hsuan  * (lanes * 2) because CSI lanes use double-data-rate (DDR) signalling.
58*fd553196SKate Hsuan  * bpp = 10 and lanes = 4
59*fd553196SKate Hsuan  */
60*fd553196SKate Hsuan #define T4KA3_LINK_FREQ				((u64)T4KA3_PIXEL_RATE * 10 / 8)
61*fd553196SKate Hsuan 
62*fd553196SKate Hsuan /* For enum_frame_size() full-size + binned-/quarter-size */
63*fd553196SKate Hsuan #define T4KA3_FRAME_SIZES			2
64*fd553196SKate Hsuan 
65*fd553196SKate Hsuan #define T4KA3_REG_PRODUCT_ID_HIGH		CCI_REG8(0x0000)
66*fd553196SKate Hsuan #define T4KA3_REG_PRODUCT_ID_LOW		CCI_REG8(0x0001)
67*fd553196SKate Hsuan #define T4KA3_PRODUCT_ID			0x1490
68*fd553196SKate Hsuan 
69*fd553196SKate Hsuan #define T4KA3_REG_STREAM			CCI_REG8(0x0100)
70*fd553196SKate Hsuan #define T4KA3_REG_IMG_ORIENTATION		CCI_REG8(0x0101)
71*fd553196SKate Hsuan #define T4KA3_HFLIP_BIT				BIT(0)
72*fd553196SKate Hsuan #define T4KA3_VFLIP_BIT				BIT(1)
73*fd553196SKate Hsuan #define T4KA3_REG_PARAM_HOLD			CCI_REG8(0x0104)
74*fd553196SKate Hsuan #define T4KA3_REG_COARSE_INTEGRATION_TIME	CCI_REG16(0x0202)
75*fd553196SKate Hsuan #define T4KA3_COARSE_INTEGRATION_TIME_MARGIN	6
76*fd553196SKate Hsuan #define T4KA3_REG_DIGGAIN_GREEN_R		CCI_REG16(0x020e)
77*fd553196SKate Hsuan #define T4KA3_REG_DIGGAIN_RED			CCI_REG16(0x0210)
78*fd553196SKate Hsuan #define T4KA3_REG_DIGGAIN_BLUE			CCI_REG16(0x0212)
79*fd553196SKate Hsuan #define T4KA3_REG_DIGGAIN_GREEN_B		CCI_REG16(0x0214)
80*fd553196SKate Hsuan #define T4KA3_REG_GLOBAL_GAIN			CCI_REG16(0x0234)
81*fd553196SKate Hsuan #define T4KA3_MIN_GLOBAL_GAIN_SUPPORTED		0x0080
82*fd553196SKate Hsuan #define T4KA3_MAX_GLOBAL_GAIN_SUPPORTED		0x07ff
83*fd553196SKate Hsuan #define T4KA3_REG_FRAME_LENGTH_LINES		CCI_REG16(0x0340) /* aka VTS */
84*fd553196SKate Hsuan /* FIXME: need a datasheet to verify the min + max vblank values */
85*fd553196SKate Hsuan #define T4KA3_MIN_VBLANK			4
86*fd553196SKate Hsuan #define T4KA3_MAX_VBLANK			0xffff
87*fd553196SKate Hsuan #define T4KA3_REG_PIXELS_PER_LINE		CCI_REG16(0x0342) /* aka HTS */
88*fd553196SKate Hsuan /* These 2 being horz/vert start is a guess (no datasheet), always 0 */
89*fd553196SKate Hsuan #define T4KA3_REG_HORZ_START			CCI_REG16(0x0344)
90*fd553196SKate Hsuan #define T4KA3_REG_VERT_START			CCI_REG16(0x0346)
91*fd553196SKate Hsuan /* Always 3279 (T4KA3_NATIVE_WIDTH - 1, window is used to crop */
92*fd553196SKate Hsuan #define T4KA3_REG_HORZ_END			CCI_REG16(0x0348)
93*fd553196SKate Hsuan /* Always 2463 (T4KA3_NATIVE_HEIGHT - 1, window is used to crop */
94*fd553196SKate Hsuan #define T4KA3_REG_VERT_END			CCI_REG16(0x034a)
95*fd553196SKate Hsuan /* Output size (after cropping/window) */
96*fd553196SKate Hsuan #define T4KA3_REG_HORZ_OUTPUT_SIZE		CCI_REG16(0x034c)
97*fd553196SKate Hsuan #define T4KA3_REG_VERT_OUTPUT_SIZE		CCI_REG16(0x034e)
98*fd553196SKate Hsuan /* Window/crop start + size *after* binning */
99*fd553196SKate Hsuan #define T4KA3_REG_WIN_START_X			CCI_REG16(0x0408)
100*fd553196SKate Hsuan #define T4KA3_REG_WIN_START_Y			CCI_REG16(0x040a)
101*fd553196SKate Hsuan #define T4KA3_REG_WIN_WIDTH			CCI_REG16(0x040c)
102*fd553196SKate Hsuan #define T4KA3_REG_WIN_HEIGHT			CCI_REG16(0x040e)
103*fd553196SKate Hsuan #define T4KA3_REG_TEST_PATTERN_MODE		CCI_REG8(0x0601)
104*fd553196SKate Hsuan /* Unknown register at address 0x0900 */
105*fd553196SKate Hsuan #define T4KA3_REG_0900				CCI_REG8(0x0900)
106*fd553196SKate Hsuan #define T4KA3_REG_BINNING			CCI_REG8(0x0901)
107*fd553196SKate Hsuan #define T4KA3_BINNING_VAL(_bin) \
108*fd553196SKate Hsuan ({ \
109*fd553196SKate Hsuan 	typeof(_bin) (b) = (_bin); \
110*fd553196SKate Hsuan 	((b) << 4) | (b); \
111*fd553196SKate Hsuan })
112*fd553196SKate Hsuan 
113*fd553196SKate Hsuan #define to_t4ka3_sensor(_sd) container_of_const(_sd, \
114*fd553196SKate Hsuan 						struct t4ka3_data, sd)
115*fd553196SKate Hsuan #define ctrl_to_t4ka3(_ctrl) container_of_const((_ctrl)->handler, \
116*fd553196SKate Hsuan 						struct t4ka3_data, \
117*fd553196SKate Hsuan 						ctrls.handler)
118*fd553196SKate Hsuan 
119*fd553196SKate Hsuan struct t4ka3_ctrls {
120*fd553196SKate Hsuan 	struct v4l2_ctrl_handler handler;
121*fd553196SKate Hsuan 	struct v4l2_ctrl *hflip;
122*fd553196SKate Hsuan 	struct v4l2_ctrl *vflip;
123*fd553196SKate Hsuan 	struct v4l2_ctrl *vblank;
124*fd553196SKate Hsuan 	struct v4l2_ctrl *hblank;
125*fd553196SKate Hsuan 	struct v4l2_ctrl *exposure;
126*fd553196SKate Hsuan 	struct v4l2_ctrl *gain;
127*fd553196SKate Hsuan 	struct v4l2_ctrl *test_pattern;
128*fd553196SKate Hsuan 	struct v4l2_ctrl *link_freq;
129*fd553196SKate Hsuan 	struct v4l2_ctrl *pixel_rate;
130*fd553196SKate Hsuan };
131*fd553196SKate Hsuan 
132*fd553196SKate Hsuan struct t4ka3_mode {
133*fd553196SKate Hsuan 	int binning;
134*fd553196SKate Hsuan 	u16 win_x;
135*fd553196SKate Hsuan 	u16 win_y;
136*fd553196SKate Hsuan };
137*fd553196SKate Hsuan 
138*fd553196SKate Hsuan struct t4ka3_data {
139*fd553196SKate Hsuan 	struct v4l2_subdev sd;
140*fd553196SKate Hsuan 	struct media_pad pad;
141*fd553196SKate Hsuan 	struct mutex lock; /* serialize sensor's ioctl */
142*fd553196SKate Hsuan 	struct t4ka3_ctrls ctrls;
143*fd553196SKate Hsuan 	struct t4ka3_mode mode;
144*fd553196SKate Hsuan 	struct device *dev;
145*fd553196SKate Hsuan 	struct regmap *regmap;
146*fd553196SKate Hsuan 	struct gpio_desc *powerdown_gpio;
147*fd553196SKate Hsuan 	struct gpio_desc *reset_gpio;
148*fd553196SKate Hsuan 	int streaming;
149*fd553196SKate Hsuan 
150*fd553196SKate Hsuan 	/* MIPI lane info */
151*fd553196SKate Hsuan 	u32 link_freq_index;
152*fd553196SKate Hsuan 	u8 mipi_lanes;
153*fd553196SKate Hsuan };
154*fd553196SKate Hsuan 
155*fd553196SKate Hsuan /* init settings */
156*fd553196SKate Hsuan static const struct cci_reg_sequence t4ka3_init_config[] = {
157*fd553196SKate Hsuan 	{ CCI_REG8(0x4136), 0x13 },
158*fd553196SKate Hsuan 	{ CCI_REG8(0x4137), 0x33 },
159*fd553196SKate Hsuan 	{ CCI_REG8(0x3094), 0x01 },
160*fd553196SKate Hsuan 	{ CCI_REG8(0x0233), 0x01 },
161*fd553196SKate Hsuan 	{ CCI_REG8(0x4B06), 0x01 },
162*fd553196SKate Hsuan 	{ CCI_REG8(0x4B07), 0x01 },
163*fd553196SKate Hsuan 	{ CCI_REG8(0x3028), 0x01 },
164*fd553196SKate Hsuan 	{ CCI_REG8(0x3032), 0x14 },
165*fd553196SKate Hsuan 	{ CCI_REG8(0x305C), 0x0C },
166*fd553196SKate Hsuan 	{ CCI_REG8(0x306D), 0x0A },
167*fd553196SKate Hsuan 	{ CCI_REG8(0x3071), 0xFA },
168*fd553196SKate Hsuan 	{ CCI_REG8(0x307E), 0x0A },
169*fd553196SKate Hsuan 	{ CCI_REG8(0x307F), 0xFC },
170*fd553196SKate Hsuan 	{ CCI_REG8(0x3091), 0x04 },
171*fd553196SKate Hsuan 	{ CCI_REG8(0x3092), 0x60 },
172*fd553196SKate Hsuan 	{ CCI_REG8(0x3096), 0xC0 },
173*fd553196SKate Hsuan 	{ CCI_REG8(0x3100), 0x07 },
174*fd553196SKate Hsuan 	{ CCI_REG8(0x3101), 0x4C },
175*fd553196SKate Hsuan 	{ CCI_REG8(0x3118), 0xCC },
176*fd553196SKate Hsuan 	{ CCI_REG8(0x3139), 0x06 },
177*fd553196SKate Hsuan 	{ CCI_REG8(0x313A), 0x06 },
178*fd553196SKate Hsuan 	{ CCI_REG8(0x313B), 0x04 },
179*fd553196SKate Hsuan 	{ CCI_REG8(0x3143), 0x02 },
180*fd553196SKate Hsuan 	{ CCI_REG8(0x314F), 0x0E },
181*fd553196SKate Hsuan 	{ CCI_REG8(0x3169), 0x99 },
182*fd553196SKate Hsuan 	{ CCI_REG8(0x316A), 0x99 },
183*fd553196SKate Hsuan 	{ CCI_REG8(0x3171), 0x05 },
184*fd553196SKate Hsuan 	{ CCI_REG8(0x31A1), 0xA7 },
185*fd553196SKate Hsuan 	{ CCI_REG8(0x31A2), 0x9C },
186*fd553196SKate Hsuan 	{ CCI_REG8(0x31A3), 0x8F },
187*fd553196SKate Hsuan 	{ CCI_REG8(0x31A4), 0x75 },
188*fd553196SKate Hsuan 	{ CCI_REG8(0x31A5), 0xEE },
189*fd553196SKate Hsuan 	{ CCI_REG8(0x31A6), 0xEA },
190*fd553196SKate Hsuan 	{ CCI_REG8(0x31A7), 0xE4 },
191*fd553196SKate Hsuan 	{ CCI_REG8(0x31A8), 0xE4 },
192*fd553196SKate Hsuan 	{ CCI_REG8(0x31DF), 0x05 },
193*fd553196SKate Hsuan 	{ CCI_REG8(0x31EC), 0x1B },
194*fd553196SKate Hsuan 	{ CCI_REG8(0x31ED), 0x1B },
195*fd553196SKate Hsuan 	{ CCI_REG8(0x31EE), 0x1B },
196*fd553196SKate Hsuan 	{ CCI_REG8(0x31F0), 0x1B },
197*fd553196SKate Hsuan 	{ CCI_REG8(0x31F1), 0x1B },
198*fd553196SKate Hsuan 	{ CCI_REG8(0x31F2), 0x1B },
199*fd553196SKate Hsuan 	{ CCI_REG8(0x3204), 0x3F },
200*fd553196SKate Hsuan 	{ CCI_REG8(0x3205), 0x03 },
201*fd553196SKate Hsuan 	{ CCI_REG8(0x3210), 0x01 },
202*fd553196SKate Hsuan 	{ CCI_REG8(0x3216), 0x68 },
203*fd553196SKate Hsuan 	{ CCI_REG8(0x3217), 0x58 },
204*fd553196SKate Hsuan 	{ CCI_REG8(0x3218), 0x58 },
205*fd553196SKate Hsuan 	{ CCI_REG8(0x321A), 0x68 },
206*fd553196SKate Hsuan 	{ CCI_REG8(0x321B), 0x60 },
207*fd553196SKate Hsuan 	{ CCI_REG8(0x3238), 0x03 },
208*fd553196SKate Hsuan 	{ CCI_REG8(0x3239), 0x03 },
209*fd553196SKate Hsuan 	{ CCI_REG8(0x323A), 0x05 },
210*fd553196SKate Hsuan 	{ CCI_REG8(0x323B), 0x06 },
211*fd553196SKate Hsuan 	{ CCI_REG8(0x3243), 0x03 },
212*fd553196SKate Hsuan 	{ CCI_REG8(0x3244), 0x08 },
213*fd553196SKate Hsuan 	{ CCI_REG8(0x3245), 0x01 },
214*fd553196SKate Hsuan 	{ CCI_REG8(0x3307), 0x19 },
215*fd553196SKate Hsuan 	{ CCI_REG8(0x3308), 0x19 },
216*fd553196SKate Hsuan 	{ CCI_REG8(0x3320), 0x01 },
217*fd553196SKate Hsuan 	{ CCI_REG8(0x3326), 0x15 },
218*fd553196SKate Hsuan 	{ CCI_REG8(0x3327), 0x0D },
219*fd553196SKate Hsuan 	{ CCI_REG8(0x3328), 0x01 },
220*fd553196SKate Hsuan 	{ CCI_REG8(0x3380), 0x01 },
221*fd553196SKate Hsuan 	{ CCI_REG8(0x339E), 0x07 },
222*fd553196SKate Hsuan 	{ CCI_REG8(0x3424), 0x00 },
223*fd553196SKate Hsuan 	{ CCI_REG8(0x343C), 0x01 },
224*fd553196SKate Hsuan 	{ CCI_REG8(0x3398), 0x04 },
225*fd553196SKate Hsuan 	{ CCI_REG8(0x343A), 0x10 },
226*fd553196SKate Hsuan 	{ CCI_REG8(0x339A), 0x22 },
227*fd553196SKate Hsuan 	{ CCI_REG8(0x33B4), 0x00 },
228*fd553196SKate Hsuan 	{ CCI_REG8(0x3393), 0x01 },
229*fd553196SKate Hsuan 	{ CCI_REG8(0x33B3), 0x6E },
230*fd553196SKate Hsuan 	{ CCI_REG8(0x3433), 0x06 },
231*fd553196SKate Hsuan 	{ CCI_REG8(0x3433), 0x00 },
232*fd553196SKate Hsuan 	{ CCI_REG8(0x33B3), 0x00 },
233*fd553196SKate Hsuan 	{ CCI_REG8(0x3393), 0x03 },
234*fd553196SKate Hsuan 	{ CCI_REG8(0x33B4), 0x03 },
235*fd553196SKate Hsuan 	{ CCI_REG8(0x343A), 0x00 },
236*fd553196SKate Hsuan 	{ CCI_REG8(0x339A), 0x00 },
237*fd553196SKate Hsuan 	{ CCI_REG8(0x3398), 0x00 }
238*fd553196SKate Hsuan };
239*fd553196SKate Hsuan 
240*fd553196SKate Hsuan static const struct cci_reg_sequence t4ka3_pre_mode_set_regs[] = {
241*fd553196SKate Hsuan 	{ CCI_REG8(0x0112), 0x0A },
242*fd553196SKate Hsuan 	{ CCI_REG8(0x0113), 0x0A },
243*fd553196SKate Hsuan 	{ CCI_REG8(0x0114), 0x03 },
244*fd553196SKate Hsuan 	{ CCI_REG8(0x4136), 0x13 },
245*fd553196SKate Hsuan 	{ CCI_REG8(0x4137), 0x33 },
246*fd553196SKate Hsuan 	{ CCI_REG8(0x0820), 0x0A },
247*fd553196SKate Hsuan 	{ CCI_REG8(0x0821), 0x0D },
248*fd553196SKate Hsuan 	{ CCI_REG8(0x0822), 0x00 },
249*fd553196SKate Hsuan 	{ CCI_REG8(0x0823), 0x00 },
250*fd553196SKate Hsuan 	{ CCI_REG8(0x0301), 0x0A },
251*fd553196SKate Hsuan 	{ CCI_REG8(0x0303), 0x01 },
252*fd553196SKate Hsuan 	{ CCI_REG8(0x0305), 0x04 },
253*fd553196SKate Hsuan 	{ CCI_REG8(0x0306), 0x02 },
254*fd553196SKate Hsuan 	{ CCI_REG8(0x0307), 0x18 },
255*fd553196SKate Hsuan 	{ CCI_REG8(0x030B), 0x01 },
256*fd553196SKate Hsuan };
257*fd553196SKate Hsuan 
258*fd553196SKate Hsuan static const struct cci_reg_sequence t4ka3_post_mode_set_regs[] = {
259*fd553196SKate Hsuan 	{ CCI_REG8(0x0902), 0x00 },
260*fd553196SKate Hsuan 	{ CCI_REG8(0x4220), 0x00 },
261*fd553196SKate Hsuan 	{ CCI_REG8(0x4222), 0x01 },
262*fd553196SKate Hsuan 	{ CCI_REG8(0x3380), 0x01 },
263*fd553196SKate Hsuan 	{ CCI_REG8(0x3090), 0x88 },
264*fd553196SKate Hsuan 	{ CCI_REG8(0x3394), 0x20 },
265*fd553196SKate Hsuan 	{ CCI_REG8(0x3090), 0x08 },
266*fd553196SKate Hsuan 	{ CCI_REG8(0x3394), 0x10 }
267*fd553196SKate Hsuan };
268*fd553196SKate Hsuan 
269*fd553196SKate Hsuan static const s64 link_freq_menu_items[] = {
270*fd553196SKate Hsuan 	T4KA3_LINK_FREQ,
271*fd553196SKate Hsuan };
272*fd553196SKate Hsuan 
273*fd553196SKate Hsuan /* T4KA3 default GRBG */
274*fd553196SKate Hsuan static const int t4ka3_hv_flip_bayer_order[] = {
275*fd553196SKate Hsuan 	MEDIA_BUS_FMT_SGRBG10_1X10,
276*fd553196SKate Hsuan 	MEDIA_BUS_FMT_SBGGR10_1X10,
277*fd553196SKate Hsuan 	MEDIA_BUS_FMT_SRGGB10_1X10,
278*fd553196SKate Hsuan 	MEDIA_BUS_FMT_SGBRG10_1X10,
279*fd553196SKate Hsuan };
280*fd553196SKate Hsuan 
281*fd553196SKate Hsuan static const struct v4l2_rect t4ka3_default_crop = {
282*fd553196SKate Hsuan 	.left = T4KA3_ACTIVE_START_LEFT,
283*fd553196SKate Hsuan 	.top = T4KA3_ACTIVE_START_TOP,
284*fd553196SKate Hsuan 	.width = T4KA3_ACTIVE_WIDTH,
285*fd553196SKate Hsuan 	.height = T4KA3_ACTIVE_HEIGHT,
286*fd553196SKate Hsuan };
287*fd553196SKate Hsuan 
288*fd553196SKate Hsuan static void t4ka3_set_bayer_order(struct t4ka3_data *sensor,
289*fd553196SKate Hsuan 				  struct v4l2_mbus_framefmt *fmt)
290*fd553196SKate Hsuan {
291*fd553196SKate Hsuan 	unsigned int hv_flip = 0;
292*fd553196SKate Hsuan 
293*fd553196SKate Hsuan 	if (sensor->ctrls.vflip && sensor->ctrls.vflip->val)
294*fd553196SKate Hsuan 		hv_flip += 1;
295*fd553196SKate Hsuan 
296*fd553196SKate Hsuan 	if (sensor->ctrls.hflip && sensor->ctrls.hflip->val)
297*fd553196SKate Hsuan 		hv_flip += 2;
298*fd553196SKate Hsuan 
299*fd553196SKate Hsuan 	fmt->code = t4ka3_hv_flip_bayer_order[hv_flip];
300*fd553196SKate Hsuan }
301*fd553196SKate Hsuan 
302*fd553196SKate Hsuan static int t4ka3_update_exposure_range(struct t4ka3_data *sensor,
303*fd553196SKate Hsuan 				       struct v4l2_mbus_framefmt *fmt)
304*fd553196SKate Hsuan {
305*fd553196SKate Hsuan 	int exp_max = fmt->height + sensor->ctrls.vblank->val -
306*fd553196SKate Hsuan 		      T4KA3_COARSE_INTEGRATION_TIME_MARGIN;
307*fd553196SKate Hsuan 
308*fd553196SKate Hsuan 	return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max,
309*fd553196SKate Hsuan 					1, exp_max);
310*fd553196SKate Hsuan }
311*fd553196SKate Hsuan 
312*fd553196SKate Hsuan static void t4ka3_fill_format(struct t4ka3_data *sensor,
313*fd553196SKate Hsuan 			      struct v4l2_mbus_framefmt *fmt,
314*fd553196SKate Hsuan 			      unsigned int width, unsigned int height)
315*fd553196SKate Hsuan {
316*fd553196SKate Hsuan 	memset(fmt, 0, sizeof(*fmt));
317*fd553196SKate Hsuan 	fmt->width = width;
318*fd553196SKate Hsuan 	fmt->height = height;
319*fd553196SKate Hsuan 	fmt->field = V4L2_FIELD_NONE;
320*fd553196SKate Hsuan 	fmt->colorspace = V4L2_COLORSPACE_RAW;
321*fd553196SKate Hsuan 	t4ka3_set_bayer_order(sensor, fmt);
322*fd553196SKate Hsuan }
323*fd553196SKate Hsuan 
324*fd553196SKate Hsuan static void t4ka3_calc_mode(struct t4ka3_data *sensor,
325*fd553196SKate Hsuan 			    struct v4l2_mbus_framefmt *fmt,
326*fd553196SKate Hsuan 			    struct v4l2_rect *crop)
327*fd553196SKate Hsuan {
328*fd553196SKate Hsuan 	int width;
329*fd553196SKate Hsuan 	int height;
330*fd553196SKate Hsuan 	int binning;
331*fd553196SKate Hsuan 
332*fd553196SKate Hsuan 	width = fmt->width;
333*fd553196SKate Hsuan 	height = fmt->height;
334*fd553196SKate Hsuan 
335*fd553196SKate Hsuan 	if (width <= (crop->width / 2) && height <= (crop->height / 2))
336*fd553196SKate Hsuan 		binning = 2;
337*fd553196SKate Hsuan 	else
338*fd553196SKate Hsuan 		binning = 1;
339*fd553196SKate Hsuan 
340*fd553196SKate Hsuan 	width *= binning;
341*fd553196SKate Hsuan 	height *= binning;
342*fd553196SKate Hsuan 
343*fd553196SKate Hsuan 	sensor->mode.binning = binning;
344*fd553196SKate Hsuan 	sensor->mode.win_x = (crop->left + (crop->width - width) / 2) & ~1;
345*fd553196SKate Hsuan 	sensor->mode.win_y = (crop->top + (crop->height - height) / 2) & ~1;
346*fd553196SKate Hsuan 	/*
347*fd553196SKate Hsuan 	 * t4ka3's window is done after binning, but must still be a
348*fd553196SKate Hsuan 	 * multiple of 2 ?
349*fd553196SKate Hsuan 	 * Round up to avoid top 2 black lines in 1640x1230 (quarter res) case.
350*fd553196SKate Hsuan 	 */
351*fd553196SKate Hsuan 	sensor->mode.win_x = DIV_ROUND_UP(sensor->mode.win_x, binning);
352*fd553196SKate Hsuan 	sensor->mode.win_y = DIV_ROUND_UP(sensor->mode.win_y, binning);
353*fd553196SKate Hsuan }
354*fd553196SKate Hsuan 
355*fd553196SKate Hsuan static void t4ka3_get_vblank_limits(struct t4ka3_data *sensor,
356*fd553196SKate Hsuan 				    struct v4l2_subdev_state *state,
357*fd553196SKate Hsuan 				    int *min, int *max, int *def)
358*fd553196SKate Hsuan {
359*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *fmt = v4l2_subdev_state_get_format(state, 0);
360*fd553196SKate Hsuan 
361*fd553196SKate Hsuan 	*min = T4KA3_MIN_VBLANK + (sensor->mode.binning - 1) * fmt->height;
362*fd553196SKate Hsuan 	*max = T4KA3_MAX_VBLANK - fmt->height;
363*fd553196SKate Hsuan 	*def = T4KA3_LINES_PER_FRAME_30FPS - fmt->height;
364*fd553196SKate Hsuan }
365*fd553196SKate Hsuan 
366*fd553196SKate Hsuan static int t4ka3_set_pad_format(struct v4l2_subdev *sd,
367*fd553196SKate Hsuan 				struct v4l2_subdev_state *sd_state,
368*fd553196SKate Hsuan 				struct v4l2_subdev_format *format)
369*fd553196SKate Hsuan {
370*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
371*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *fmt = &format->format;
372*fd553196SKate Hsuan 	struct v4l2_rect *crop =
373*fd553196SKate Hsuan 		v4l2_subdev_state_get_crop(sd_state, format->pad);
374*fd553196SKate Hsuan 	unsigned int width, height;
375*fd553196SKate Hsuan 	int min, max, def, ret = 0;
376*fd553196SKate Hsuan 
377*fd553196SKate Hsuan 	/* Limit set_fmt max size to crop width / height */
378*fd553196SKate Hsuan 	width = clamp_val(ALIGN(format->format.width, 2),
379*fd553196SKate Hsuan 			  T4KA3_MIN_CROP_WIDTH, crop->width);
380*fd553196SKate Hsuan 	height = clamp_val(ALIGN(format->format.height, 2),
381*fd553196SKate Hsuan 			   T4KA3_MIN_CROP_HEIGHT, crop->height);
382*fd553196SKate Hsuan 	t4ka3_fill_format(sensor, &format->format, width, height);
383*fd553196SKate Hsuan 
384*fd553196SKate Hsuan 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && sensor->streaming)
385*fd553196SKate Hsuan 		return -EBUSY;
386*fd553196SKate Hsuan 
387*fd553196SKate Hsuan 	*v4l2_subdev_state_get_format(sd_state, 0) = format->format;
388*fd553196SKate Hsuan 
389*fd553196SKate Hsuan 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
390*fd553196SKate Hsuan 		return 0;
391*fd553196SKate Hsuan 
392*fd553196SKate Hsuan 	t4ka3_calc_mode(sensor, fmt, crop);
393*fd553196SKate Hsuan 
394*fd553196SKate Hsuan 	/* vblank range is height dependent adjust and reset to default */
395*fd553196SKate Hsuan 	t4ka3_get_vblank_limits(sensor, sd_state, &min, &max, &def);
396*fd553196SKate Hsuan 	ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank, min, max, 1, def);
397*fd553196SKate Hsuan 	if (ret)
398*fd553196SKate Hsuan 		return ret;
399*fd553196SKate Hsuan 
400*fd553196SKate Hsuan 	ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, def);
401*fd553196SKate Hsuan 	if (ret)
402*fd553196SKate Hsuan 		return ret;
403*fd553196SKate Hsuan 
404*fd553196SKate Hsuan 	def = T4KA3_PIXELS_PER_LINE - fmt->width;
405*fd553196SKate Hsuan 	ret = __v4l2_ctrl_modify_range(sensor->ctrls.hblank, def, def, 1, def);
406*fd553196SKate Hsuan 	if (ret)
407*fd553196SKate Hsuan 		return ret;
408*fd553196SKate Hsuan 
409*fd553196SKate Hsuan 	return  __v4l2_ctrl_s_ctrl(sensor->ctrls.hblank, def);
410*fd553196SKate Hsuan }
411*fd553196SKate Hsuan 
412*fd553196SKate Hsuan /* Horizontal or vertically flip the image */
413*fd553196SKate Hsuan static int t4ka3_update_flip(struct v4l2_subdev *sd,
414*fd553196SKate Hsuan 			     struct v4l2_mbus_framefmt *fmt,
415*fd553196SKate Hsuan 			     int value, u8 flip_bit)
416*fd553196SKate Hsuan {
417*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
418*fd553196SKate Hsuan 	int ret;
419*fd553196SKate Hsuan 	u64 val;
420*fd553196SKate Hsuan 
421*fd553196SKate Hsuan 	if (sensor->streaming)
422*fd553196SKate Hsuan 		return -EBUSY;
423*fd553196SKate Hsuan 
424*fd553196SKate Hsuan 	val = value ? flip_bit : 0;
425*fd553196SKate Hsuan 
426*fd553196SKate Hsuan 	ret = cci_update_bits(sensor->regmap, T4KA3_REG_IMG_ORIENTATION,
427*fd553196SKate Hsuan 			      flip_bit, val, NULL);
428*fd553196SKate Hsuan 	if (ret)
429*fd553196SKate Hsuan 		return ret;
430*fd553196SKate Hsuan 
431*fd553196SKate Hsuan 	t4ka3_set_bayer_order(sensor, fmt);
432*fd553196SKate Hsuan 
433*fd553196SKate Hsuan 	return 0;
434*fd553196SKate Hsuan }
435*fd553196SKate Hsuan 
436*fd553196SKate Hsuan static int t4ka3_test_pattern(struct t4ka3_data *sensor, s32 value)
437*fd553196SKate Hsuan {
438*fd553196SKate Hsuan 	return cci_write(sensor->regmap, T4KA3_REG_TEST_PATTERN_MODE,
439*fd553196SKate Hsuan 			 value, NULL);
440*fd553196SKate Hsuan }
441*fd553196SKate Hsuan 
442*fd553196SKate Hsuan static int t4ka3_detect(struct t4ka3_data *sensor, u16 *id)
443*fd553196SKate Hsuan {
444*fd553196SKate Hsuan 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
445*fd553196SKate Hsuan 	struct i2c_adapter *adapter = client->adapter;
446*fd553196SKate Hsuan 	u64 high, low;
447*fd553196SKate Hsuan 	int ret = 0;
448*fd553196SKate Hsuan 
449*fd553196SKate Hsuan 	/* i2c check */
450*fd553196SKate Hsuan 	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
451*fd553196SKate Hsuan 		return -ENODEV;
452*fd553196SKate Hsuan 
453*fd553196SKate Hsuan 	/* check sensor chip ID	 */
454*fd553196SKate Hsuan 	cci_read(sensor->regmap, T4KA3_REG_PRODUCT_ID_HIGH, &high, &ret);
455*fd553196SKate Hsuan 	cci_read(sensor->regmap, T4KA3_REG_PRODUCT_ID_LOW, &low, &ret);
456*fd553196SKate Hsuan 	if (ret)
457*fd553196SKate Hsuan 		return ret;
458*fd553196SKate Hsuan 
459*fd553196SKate Hsuan 	*id = (((u8)high) << 8) | (u8)low;
460*fd553196SKate Hsuan 	if (*id != T4KA3_PRODUCT_ID) {
461*fd553196SKate Hsuan 		dev_err(sensor->dev, "main sensor t4ka3 ID error\n");
462*fd553196SKate Hsuan 		return -ENODEV;
463*fd553196SKate Hsuan 	}
464*fd553196SKate Hsuan 
465*fd553196SKate Hsuan 	return 0;
466*fd553196SKate Hsuan }
467*fd553196SKate Hsuan 
468*fd553196SKate Hsuan static int t4ka3_s_ctrl(struct v4l2_ctrl *ctrl)
469*fd553196SKate Hsuan {
470*fd553196SKate Hsuan 	struct t4ka3_data *sensor = ctrl_to_t4ka3(ctrl);
471*fd553196SKate Hsuan 	struct v4l2_subdev_state *state =
472*fd553196SKate Hsuan 			v4l2_subdev_get_locked_active_state(&sensor->sd);
473*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *fmt =
474*fd553196SKate Hsuan 			v4l2_subdev_state_get_format(state, 0);
475*fd553196SKate Hsuan 	int ret;
476*fd553196SKate Hsuan 
477*fd553196SKate Hsuan 	/* Update exposure range on vblank changes */
478*fd553196SKate Hsuan 	if (ctrl->id == V4L2_CID_VBLANK) {
479*fd553196SKate Hsuan 		ret = t4ka3_update_exposure_range(sensor, fmt);
480*fd553196SKate Hsuan 		if (ret)
481*fd553196SKate Hsuan 			return ret;
482*fd553196SKate Hsuan 	}
483*fd553196SKate Hsuan 
484*fd553196SKate Hsuan 	/* Only apply changes to the controls if the device is powered up */
485*fd553196SKate Hsuan 	if (!pm_runtime_get_if_in_use(sensor->sd.dev))
486*fd553196SKate Hsuan 		return 0;
487*fd553196SKate Hsuan 
488*fd553196SKate Hsuan 	switch (ctrl->id) {
489*fd553196SKate Hsuan 	case V4L2_CID_TEST_PATTERN:
490*fd553196SKate Hsuan 		ret = t4ka3_test_pattern(sensor, ctrl->val);
491*fd553196SKate Hsuan 		break;
492*fd553196SKate Hsuan 	case V4L2_CID_VFLIP:
493*fd553196SKate Hsuan 		ret = t4ka3_update_flip(&sensor->sd, fmt,
494*fd553196SKate Hsuan 					ctrl->val, T4KA3_VFLIP_BIT);
495*fd553196SKate Hsuan 		break;
496*fd553196SKate Hsuan 	case V4L2_CID_HFLIP:
497*fd553196SKate Hsuan 		ret = t4ka3_update_flip(&sensor->sd, fmt,
498*fd553196SKate Hsuan 					ctrl->val, T4KA3_HFLIP_BIT);
499*fd553196SKate Hsuan 		break;
500*fd553196SKate Hsuan 	case V4L2_CID_VBLANK:
501*fd553196SKate Hsuan 		ret = cci_write(sensor->regmap, T4KA3_REG_FRAME_LENGTH_LINES,
502*fd553196SKate Hsuan 				fmt->height + ctrl->val, NULL);
503*fd553196SKate Hsuan 		break;
504*fd553196SKate Hsuan 	case V4L2_CID_EXPOSURE:
505*fd553196SKate Hsuan 		ret = cci_write(sensor->regmap,
506*fd553196SKate Hsuan 				T4KA3_REG_COARSE_INTEGRATION_TIME,
507*fd553196SKate Hsuan 				ctrl->val, NULL);
508*fd553196SKate Hsuan 		break;
509*fd553196SKate Hsuan 	case V4L2_CID_ANALOGUE_GAIN:
510*fd553196SKate Hsuan 		ret = cci_write(sensor->regmap, T4KA3_REG_GLOBAL_GAIN,
511*fd553196SKate Hsuan 				ctrl->val, NULL);
512*fd553196SKate Hsuan 		break;
513*fd553196SKate Hsuan 	default:
514*fd553196SKate Hsuan 		ret = -EINVAL;
515*fd553196SKate Hsuan 		break;
516*fd553196SKate Hsuan 	}
517*fd553196SKate Hsuan 
518*fd553196SKate Hsuan 	pm_runtime_put(sensor->sd.dev);
519*fd553196SKate Hsuan 
520*fd553196SKate Hsuan 	return ret;
521*fd553196SKate Hsuan }
522*fd553196SKate Hsuan 
523*fd553196SKate Hsuan static int t4ka3_set_mode(struct t4ka3_data *sensor,
524*fd553196SKate Hsuan 			  struct v4l2_subdev_state *state)
525*fd553196SKate Hsuan {
526*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *fmt = v4l2_subdev_state_get_format(state, 0);
527*fd553196SKate Hsuan 	int ret = 0;
528*fd553196SKate Hsuan 
529*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_HORZ_OUTPUT_SIZE, fmt->width, &ret);
530*fd553196SKate Hsuan 	/* Write mode-height - 2 otherwise things don't work, hw-bug ? */
531*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_VERT_OUTPUT_SIZE,
532*fd553196SKate Hsuan 		  fmt->height - 2, &ret);
533*fd553196SKate Hsuan 
534*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_PIXELS_PER_LINE,
535*fd553196SKate Hsuan 		  T4KA3_PIXELS_PER_LINE, &ret);
536*fd553196SKate Hsuan 	/* Always use the full sensor, using window to crop */
537*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_HORZ_START, 0, &ret);
538*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_VERT_START, 0, &ret);
539*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_HORZ_END,
540*fd553196SKate Hsuan 		  T4KA3_NATIVE_WIDTH - 1, &ret);
541*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_VERT_END,
542*fd553196SKate Hsuan 		  T4KA3_NATIVE_HEIGHT - 1, &ret);
543*fd553196SKate Hsuan 	/* Set window */
544*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_WIN_START_X,
545*fd553196SKate Hsuan 		  sensor->mode.win_x, &ret);
546*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_WIN_START_Y,
547*fd553196SKate Hsuan 		  sensor->mode.win_y, &ret);
548*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_WIN_WIDTH, fmt->width, &ret);
549*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_WIN_HEIGHT, fmt->height, &ret);
550*fd553196SKate Hsuan 	/* Write 1 to unknown register 0x0900 */
551*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_0900, 1, &ret);
552*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_BINNING,
553*fd553196SKate Hsuan 		  T4KA3_BINNING_VAL(sensor->mode.binning), &ret);
554*fd553196SKate Hsuan 
555*fd553196SKate Hsuan 	return ret;
556*fd553196SKate Hsuan }
557*fd553196SKate Hsuan 
558*fd553196SKate Hsuan static int t4ka3_enable_stream(struct v4l2_subdev *sd,
559*fd553196SKate Hsuan 			       struct v4l2_subdev_state *state,
560*fd553196SKate Hsuan 			       u32 pad, u64 streams_mask)
561*fd553196SKate Hsuan {
562*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
563*fd553196SKate Hsuan 	int ret;
564*fd553196SKate Hsuan 
565*fd553196SKate Hsuan 	ret = pm_runtime_get_sync(sensor->sd.dev);
566*fd553196SKate Hsuan 	if (ret < 0) {
567*fd553196SKate Hsuan 		dev_err(sensor->dev, "power-up err.\n");
568*fd553196SKate Hsuan 		goto error_powerdown;
569*fd553196SKate Hsuan 	}
570*fd553196SKate Hsuan 
571*fd553196SKate Hsuan 	cci_multi_reg_write(sensor->regmap, t4ka3_init_config,
572*fd553196SKate Hsuan 			    ARRAY_SIZE(t4ka3_init_config), &ret);
573*fd553196SKate Hsuan 	/* enable group hold */
574*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_PARAM_HOLD, 1, &ret);
575*fd553196SKate Hsuan 	cci_multi_reg_write(sensor->regmap, t4ka3_pre_mode_set_regs,
576*fd553196SKate Hsuan 			    ARRAY_SIZE(t4ka3_pre_mode_set_regs), &ret);
577*fd553196SKate Hsuan 	if (ret)
578*fd553196SKate Hsuan 		goto error_powerdown;
579*fd553196SKate Hsuan 
580*fd553196SKate Hsuan 	ret = t4ka3_set_mode(sensor, state);
581*fd553196SKate Hsuan 	if (ret)
582*fd553196SKate Hsuan 		goto error_powerdown;
583*fd553196SKate Hsuan 
584*fd553196SKate Hsuan 	ret = cci_multi_reg_write(sensor->regmap, t4ka3_post_mode_set_regs,
585*fd553196SKate Hsuan 				  ARRAY_SIZE(t4ka3_post_mode_set_regs), NULL);
586*fd553196SKate Hsuan 	if (ret)
587*fd553196SKate Hsuan 		goto error_powerdown;
588*fd553196SKate Hsuan 
589*fd553196SKate Hsuan 	/* Restore value of all ctrls */
590*fd553196SKate Hsuan 	ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
591*fd553196SKate Hsuan 	if (ret)
592*fd553196SKate Hsuan 		goto error_powerdown;
593*fd553196SKate Hsuan 
594*fd553196SKate Hsuan 	/* disable group hold */
595*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_PARAM_HOLD, 0, &ret);
596*fd553196SKate Hsuan 	cci_write(sensor->regmap, T4KA3_REG_STREAM, 1, &ret);
597*fd553196SKate Hsuan 	if (ret)
598*fd553196SKate Hsuan 		goto error_powerdown;
599*fd553196SKate Hsuan 
600*fd553196SKate Hsuan 	sensor->streaming = 1;
601*fd553196SKate Hsuan 
602*fd553196SKate Hsuan 	return ret;
603*fd553196SKate Hsuan 
604*fd553196SKate Hsuan error_powerdown:
605*fd553196SKate Hsuan 	pm_runtime_put(sensor->sd.dev);
606*fd553196SKate Hsuan 
607*fd553196SKate Hsuan 	return ret;
608*fd553196SKate Hsuan }
609*fd553196SKate Hsuan 
610*fd553196SKate Hsuan static int t4ka3_disable_stream(struct v4l2_subdev *sd,
611*fd553196SKate Hsuan 				struct v4l2_subdev_state *state,
612*fd553196SKate Hsuan 				u32 pad, u64 streams_mask)
613*fd553196SKate Hsuan {
614*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
615*fd553196SKate Hsuan 	int ret;
616*fd553196SKate Hsuan 
617*fd553196SKate Hsuan 	ret = cci_write(sensor->regmap, T4KA3_REG_STREAM, 0, NULL);
618*fd553196SKate Hsuan 	pm_runtime_put(sensor->sd.dev);
619*fd553196SKate Hsuan 	sensor->streaming = 0;
620*fd553196SKate Hsuan 
621*fd553196SKate Hsuan 	if (ret)
622*fd553196SKate Hsuan 		dev_err(sensor->dev,
623*fd553196SKate Hsuan 			"failed to disable stream with return value: %d\n",
624*fd553196SKate Hsuan 			ret);
625*fd553196SKate Hsuan 
626*fd553196SKate Hsuan 	return 0;
627*fd553196SKate Hsuan }
628*fd553196SKate Hsuan 
629*fd553196SKate Hsuan static int t4ka3_get_selection(struct v4l2_subdev *sd,
630*fd553196SKate Hsuan 			       struct v4l2_subdev_state *state,
631*fd553196SKate Hsuan 			       struct v4l2_subdev_selection *sel)
632*fd553196SKate Hsuan {
633*fd553196SKate Hsuan 	switch (sel->target) {
634*fd553196SKate Hsuan 	case V4L2_SEL_TGT_CROP:
635*fd553196SKate Hsuan 		sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
636*fd553196SKate Hsuan 		break;
637*fd553196SKate Hsuan 	case V4L2_SEL_TGT_NATIVE_SIZE:
638*fd553196SKate Hsuan 	case V4L2_SEL_TGT_CROP_BOUNDS:
639*fd553196SKate Hsuan 		sel->r.top = 0;
640*fd553196SKate Hsuan 		sel->r.left = 0;
641*fd553196SKate Hsuan 		sel->r.width = T4KA3_NATIVE_WIDTH;
642*fd553196SKate Hsuan 		sel->r.height = T4KA3_NATIVE_HEIGHT;
643*fd553196SKate Hsuan 		break;
644*fd553196SKate Hsuan 	case V4L2_SEL_TGT_CROP_DEFAULT:
645*fd553196SKate Hsuan 		sel->r = t4ka3_default_crop;
646*fd553196SKate Hsuan 		break;
647*fd553196SKate Hsuan 	default:
648*fd553196SKate Hsuan 		return -EINVAL;
649*fd553196SKate Hsuan 	}
650*fd553196SKate Hsuan 
651*fd553196SKate Hsuan 	return 0;
652*fd553196SKate Hsuan }
653*fd553196SKate Hsuan 
654*fd553196SKate Hsuan static int t4ka3_set_selection(struct v4l2_subdev *sd,
655*fd553196SKate Hsuan 			       struct v4l2_subdev_state *state,
656*fd553196SKate Hsuan 			       struct v4l2_subdev_selection *sel)
657*fd553196SKate Hsuan {
658*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
659*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *format;
660*fd553196SKate Hsuan 	struct v4l2_rect *crop;
661*fd553196SKate Hsuan 	struct v4l2_rect rect;
662*fd553196SKate Hsuan 
663*fd553196SKate Hsuan 	if (sel->target != V4L2_SEL_TGT_CROP)
664*fd553196SKate Hsuan 		return -EINVAL;
665*fd553196SKate Hsuan 
666*fd553196SKate Hsuan 	/*
667*fd553196SKate Hsuan 	 * Clamp the boundaries of the crop rectangle to the size of the sensor
668*fd553196SKate Hsuan 	 * pixel array. Align to multiples of 2 to ensure Bayer pattern isn't
669*fd553196SKate Hsuan 	 * disrupted.
670*fd553196SKate Hsuan 	 */
671*fd553196SKate Hsuan 	rect.left = clamp_val(ALIGN(sel->r.left, 2),
672*fd553196SKate Hsuan 			      T4KA3_NATIVE_START_LEFT, T4KA3_NATIVE_WIDTH);
673*fd553196SKate Hsuan 	rect.top = clamp_val(ALIGN(sel->r.top, 2),
674*fd553196SKate Hsuan 			     T4KA3_NATIVE_START_TOP, T4KA3_NATIVE_HEIGHT);
675*fd553196SKate Hsuan 	rect.width = clamp_val(ALIGN(sel->r.width, 2), T4KA3_MIN_CROP_WIDTH,
676*fd553196SKate Hsuan 			       T4KA3_NATIVE_WIDTH - rect.left);
677*fd553196SKate Hsuan 	rect.height = clamp_val(ALIGN(sel->r.height, 2), T4KA3_MIN_CROP_HEIGHT,
678*fd553196SKate Hsuan 				T4KA3_NATIVE_HEIGHT - rect.top);
679*fd553196SKate Hsuan 
680*fd553196SKate Hsuan 	crop = v4l2_subdev_state_get_crop(state, sel->pad);
681*fd553196SKate Hsuan 
682*fd553196SKate Hsuan 	if (rect.width != crop->width || rect.height != crop->height) {
683*fd553196SKate Hsuan 		/*
684*fd553196SKate Hsuan 		 * Reset the output image size if the crop rectangle size has
685*fd553196SKate Hsuan 		 * been modified.
686*fd553196SKate Hsuan 		 */
687*fd553196SKate Hsuan 		format = v4l2_subdev_state_get_format(state, sel->pad);
688*fd553196SKate Hsuan 		format->width = rect.width;
689*fd553196SKate Hsuan 		format->height = rect.height;
690*fd553196SKate Hsuan 		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
691*fd553196SKate Hsuan 			t4ka3_calc_mode(sensor, format, crop);
692*fd553196SKate Hsuan 	}
693*fd553196SKate Hsuan 
694*fd553196SKate Hsuan 	sel->r = *crop = rect;
695*fd553196SKate Hsuan 
696*fd553196SKate Hsuan 	return 0;
697*fd553196SKate Hsuan }
698*fd553196SKate Hsuan 
699*fd553196SKate Hsuan static int
700*fd553196SKate Hsuan t4ka3_enum_mbus_code(struct v4l2_subdev *sd,
701*fd553196SKate Hsuan 		     struct v4l2_subdev_state *sd_state,
702*fd553196SKate Hsuan 		     struct v4l2_subdev_mbus_code_enum *code)
703*fd553196SKate Hsuan {
704*fd553196SKate Hsuan 	if (code->index)
705*fd553196SKate Hsuan 		return -EINVAL;
706*fd553196SKate Hsuan 
707*fd553196SKate Hsuan 	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
708*fd553196SKate Hsuan 
709*fd553196SKate Hsuan 	return 0;
710*fd553196SKate Hsuan }
711*fd553196SKate Hsuan 
712*fd553196SKate Hsuan static int t4ka3_enum_frame_size(struct v4l2_subdev *sd,
713*fd553196SKate Hsuan 				 struct v4l2_subdev_state *sd_state,
714*fd553196SKate Hsuan 				 struct v4l2_subdev_frame_size_enum *fse)
715*fd553196SKate Hsuan {
716*fd553196SKate Hsuan 	struct v4l2_rect *crop;
717*fd553196SKate Hsuan 
718*fd553196SKate Hsuan 	if (fse->index >= T4KA3_FRAME_SIZES)
719*fd553196SKate Hsuan 		return -EINVAL;
720*fd553196SKate Hsuan 
721*fd553196SKate Hsuan 	crop = v4l2_subdev_state_get_crop(sd_state, fse->pad);
722*fd553196SKate Hsuan 
723*fd553196SKate Hsuan 	fse->min_width = crop->width / (fse->index + 1);
724*fd553196SKate Hsuan 	fse->min_height = crop->height / (fse->index + 1);
725*fd553196SKate Hsuan 	fse->max_width = fse->min_width;
726*fd553196SKate Hsuan 	fse->max_height = fse->min_height;
727*fd553196SKate Hsuan 
728*fd553196SKate Hsuan 	return 0;
729*fd553196SKate Hsuan }
730*fd553196SKate Hsuan 
731*fd553196SKate Hsuan static int t4ka3_check_hwcfg(struct t4ka3_data *sensor)
732*fd553196SKate Hsuan {
733*fd553196SKate Hsuan 	struct fwnode_handle *fwnode = dev_fwnode(sensor->dev);
734*fd553196SKate Hsuan 	struct v4l2_fwnode_endpoint bus_cfg = {
735*fd553196SKate Hsuan 		.bus_type = V4L2_MBUS_CSI2_DPHY,
736*fd553196SKate Hsuan 	};
737*fd553196SKate Hsuan 	struct fwnode_handle *endpoint;
738*fd553196SKate Hsuan 	unsigned long link_freq_bitmap;
739*fd553196SKate Hsuan 	int ret;
740*fd553196SKate Hsuan 
741*fd553196SKate Hsuan 	endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
742*fd553196SKate Hsuan 
743*fd553196SKate Hsuan 	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
744*fd553196SKate Hsuan 	fwnode_handle_put(endpoint);
745*fd553196SKate Hsuan 	if (ret)
746*fd553196SKate Hsuan 		return ret;
747*fd553196SKate Hsuan 
748*fd553196SKate Hsuan 	ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies,
749*fd553196SKate Hsuan 				       bus_cfg.nr_of_link_frequencies,
750*fd553196SKate Hsuan 				       link_freq_menu_items,
751*fd553196SKate Hsuan 				       ARRAY_SIZE(link_freq_menu_items),
752*fd553196SKate Hsuan 				       &link_freq_bitmap);
753*fd553196SKate Hsuan 
754*fd553196SKate Hsuan 	if (ret < 0)
755*fd553196SKate Hsuan 		goto out_free_bus_cfg;
756*fd553196SKate Hsuan 
757*fd553196SKate Hsuan 	sensor->link_freq_index = ffs(link_freq_bitmap) - 1;
758*fd553196SKate Hsuan 
759*fd553196SKate Hsuan 	/* 4 MIPI lanes */
760*fd553196SKate Hsuan 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
761*fd553196SKate Hsuan 		ret = dev_err_probe(sensor->dev, -EINVAL,
762*fd553196SKate Hsuan 				    "number of CSI2 data lanes %u is not supported\n",
763*fd553196SKate Hsuan 				    bus_cfg.bus.mipi_csi2.num_data_lanes);
764*fd553196SKate Hsuan 		goto out_free_bus_cfg;
765*fd553196SKate Hsuan 	}
766*fd553196SKate Hsuan 
767*fd553196SKate Hsuan 	sensor->mipi_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
768*fd553196SKate Hsuan 
769*fd553196SKate Hsuan out_free_bus_cfg:
770*fd553196SKate Hsuan 	v4l2_fwnode_endpoint_free(&bus_cfg);
771*fd553196SKate Hsuan 
772*fd553196SKate Hsuan 	return ret;
773*fd553196SKate Hsuan }
774*fd553196SKate Hsuan 
775*fd553196SKate Hsuan static int t4ka3_init_state(struct v4l2_subdev *sd,
776*fd553196SKate Hsuan 			    struct v4l2_subdev_state *sd_state)
777*fd553196SKate Hsuan {
778*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
779*fd553196SKate Hsuan 
780*fd553196SKate Hsuan 	*v4l2_subdev_state_get_crop(sd_state, 0) = t4ka3_default_crop;
781*fd553196SKate Hsuan 
782*fd553196SKate Hsuan 	t4ka3_fill_format(sensor, v4l2_subdev_state_get_format(sd_state, 0),
783*fd553196SKate Hsuan 			  T4KA3_ACTIVE_WIDTH, T4KA3_ACTIVE_HEIGHT);
784*fd553196SKate Hsuan 	return 0;
785*fd553196SKate Hsuan }
786*fd553196SKate Hsuan 
787*fd553196SKate Hsuan static const struct v4l2_ctrl_ops t4ka3_ctrl_ops = {
788*fd553196SKate Hsuan 	.s_ctrl = t4ka3_s_ctrl,
789*fd553196SKate Hsuan };
790*fd553196SKate Hsuan 
791*fd553196SKate Hsuan static const struct v4l2_subdev_video_ops t4ka3_video_ops = {
792*fd553196SKate Hsuan 	.s_stream = v4l2_subdev_s_stream_helper,
793*fd553196SKate Hsuan };
794*fd553196SKate Hsuan 
795*fd553196SKate Hsuan static const struct v4l2_subdev_pad_ops t4ka3_pad_ops = {
796*fd553196SKate Hsuan 	.enum_mbus_code = t4ka3_enum_mbus_code,
797*fd553196SKate Hsuan 	.enum_frame_size = t4ka3_enum_frame_size,
798*fd553196SKate Hsuan 	.get_fmt = v4l2_subdev_get_fmt,
799*fd553196SKate Hsuan 	.set_fmt = t4ka3_set_pad_format,
800*fd553196SKate Hsuan 	.get_selection = t4ka3_get_selection,
801*fd553196SKate Hsuan 	.set_selection = t4ka3_set_selection,
802*fd553196SKate Hsuan 	.enable_streams = t4ka3_enable_stream,
803*fd553196SKate Hsuan 	.disable_streams = t4ka3_disable_stream,
804*fd553196SKate Hsuan };
805*fd553196SKate Hsuan 
806*fd553196SKate Hsuan static const struct v4l2_subdev_ops t4ka3_ops = {
807*fd553196SKate Hsuan 	.video = &t4ka3_video_ops,
808*fd553196SKate Hsuan 	.pad = &t4ka3_pad_ops,
809*fd553196SKate Hsuan };
810*fd553196SKate Hsuan 
811*fd553196SKate Hsuan static const struct v4l2_subdev_internal_ops t4ka3_internal_ops = {
812*fd553196SKate Hsuan 	.init_state = t4ka3_init_state,
813*fd553196SKate Hsuan };
814*fd553196SKate Hsuan 
815*fd553196SKate Hsuan static int t4ka3_init_controls(struct t4ka3_data *sensor)
816*fd553196SKate Hsuan {
817*fd553196SKate Hsuan 	const struct v4l2_ctrl_ops *ops = &t4ka3_ctrl_ops;
818*fd553196SKate Hsuan 	struct t4ka3_ctrls *ctrls = &sensor->ctrls;
819*fd553196SKate Hsuan 	struct v4l2_subdev_state *state;
820*fd553196SKate Hsuan 	struct v4l2_mbus_framefmt *fmt;
821*fd553196SKate Hsuan 	struct v4l2_rect *crop;
822*fd553196SKate Hsuan 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
823*fd553196SKate Hsuan 	struct v4l2_fwnode_device_properties props;
824*fd553196SKate Hsuan 	int ret, min, max, def;
825*fd553196SKate Hsuan 	static const char * const test_pattern_menu[] = {
826*fd553196SKate Hsuan 		"Disabled",
827*fd553196SKate Hsuan 		"Solid White",
828*fd553196SKate Hsuan 		"Color Bars",
829*fd553196SKate Hsuan 		"Gradient",
830*fd553196SKate Hsuan 		"Random Data",
831*fd553196SKate Hsuan 	};
832*fd553196SKate Hsuan 
833*fd553196SKate Hsuan 	v4l2_ctrl_handler_init(hdl, 11);
834*fd553196SKate Hsuan 
835*fd553196SKate Hsuan 	hdl->lock = &sensor->lock;
836*fd553196SKate Hsuan 
837*fd553196SKate Hsuan 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
838*fd553196SKate Hsuan 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
839*fd553196SKate Hsuan 
840*fd553196SKate Hsuan 	ctrls->test_pattern =
841*fd553196SKate Hsuan 		v4l2_ctrl_new_std_menu_items(hdl, ops,
842*fd553196SKate Hsuan 					     V4L2_CID_TEST_PATTERN,
843*fd553196SKate Hsuan 					     ARRAY_SIZE(test_pattern_menu) - 1,
844*fd553196SKate Hsuan 					     0, 0, test_pattern_menu);
845*fd553196SKate Hsuan 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, NULL,
846*fd553196SKate Hsuan 						  V4L2_CID_LINK_FREQ,
847*fd553196SKate Hsuan 						  0, 0, link_freq_menu_items);
848*fd553196SKate Hsuan 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE,
849*fd553196SKate Hsuan 					      0, T4KA3_PIXEL_RATE,
850*fd553196SKate Hsuan 					      1, T4KA3_PIXEL_RATE);
851*fd553196SKate Hsuan 
852*fd553196SKate Hsuan 	state = v4l2_subdev_lock_and_get_active_state(&sensor->sd);
853*fd553196SKate Hsuan 	fmt = v4l2_subdev_state_get_format(state, 0);
854*fd553196SKate Hsuan 	crop = v4l2_subdev_state_get_crop(state, 0);
855*fd553196SKate Hsuan 
856*fd553196SKate Hsuan 	t4ka3_calc_mode(sensor, fmt, crop);
857*fd553196SKate Hsuan 	t4ka3_get_vblank_limits(sensor, state, &min, &max, &def);
858*fd553196SKate Hsuan 
859*fd553196SKate Hsuan 	v4l2_subdev_unlock_state(state);
860*fd553196SKate Hsuan 
861*fd553196SKate Hsuan 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
862*fd553196SKate Hsuan 					  min, max, 1, def);
863*fd553196SKate Hsuan 
864*fd553196SKate Hsuan 	def = T4KA3_PIXELS_PER_LINE - T4KA3_ACTIVE_WIDTH;
865*fd553196SKate Hsuan 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
866*fd553196SKate Hsuan 					  def, def, 1, def);
867*fd553196SKate Hsuan 
868*fd553196SKate Hsuan 	max = T4KA3_LINES_PER_FRAME_30FPS -
869*fd553196SKate Hsuan 	      T4KA3_COARSE_INTEGRATION_TIME_MARGIN;
870*fd553196SKate Hsuan 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
871*fd553196SKate Hsuan 					    0, max, 1, max);
872*fd553196SKate Hsuan 
873*fd553196SKate Hsuan 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
874*fd553196SKate Hsuan 					T4KA3_MIN_GLOBAL_GAIN_SUPPORTED,
875*fd553196SKate Hsuan 					T4KA3_MAX_GLOBAL_GAIN_SUPPORTED,
876*fd553196SKate Hsuan 					1, T4KA3_MIN_GLOBAL_GAIN_SUPPORTED);
877*fd553196SKate Hsuan 
878*fd553196SKate Hsuan 	ret = v4l2_fwnode_device_parse(sensor->dev, &props);
879*fd553196SKate Hsuan 	if (ret)
880*fd553196SKate Hsuan 		return ret;
881*fd553196SKate Hsuan 
882*fd553196SKate Hsuan 	v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
883*fd553196SKate Hsuan 
884*fd553196SKate Hsuan 	if (hdl->error)
885*fd553196SKate Hsuan 		return hdl->error;
886*fd553196SKate Hsuan 
887*fd553196SKate Hsuan 	ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
888*fd553196SKate Hsuan 	ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
889*fd553196SKate Hsuan 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
890*fd553196SKate Hsuan 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
891*fd553196SKate Hsuan 
892*fd553196SKate Hsuan 	sensor->sd.ctrl_handler = hdl;
893*fd553196SKate Hsuan 
894*fd553196SKate Hsuan 	return 0;
895*fd553196SKate Hsuan }
896*fd553196SKate Hsuan 
897*fd553196SKate Hsuan static int t4ka3_pm_suspend(struct device *dev)
898*fd553196SKate Hsuan {
899*fd553196SKate Hsuan 	struct t4ka3_data *sensor = dev_get_drvdata(dev);
900*fd553196SKate Hsuan 
901*fd553196SKate Hsuan 	gpiod_set_value_cansleep(sensor->powerdown_gpio, 1);
902*fd553196SKate Hsuan 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
903*fd553196SKate Hsuan 
904*fd553196SKate Hsuan 	return 0;
905*fd553196SKate Hsuan }
906*fd553196SKate Hsuan 
907*fd553196SKate Hsuan static int t4ka3_pm_resume(struct device *dev)
908*fd553196SKate Hsuan {
909*fd553196SKate Hsuan 	struct t4ka3_data *sensor = dev_get_drvdata(dev);
910*fd553196SKate Hsuan 	u16 sensor_id;
911*fd553196SKate Hsuan 	int ret;
912*fd553196SKate Hsuan 
913*fd553196SKate Hsuan 	usleep_range(5000, 6000);
914*fd553196SKate Hsuan 
915*fd553196SKate Hsuan 	gpiod_set_value_cansleep(sensor->powerdown_gpio, 0);
916*fd553196SKate Hsuan 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
917*fd553196SKate Hsuan 
918*fd553196SKate Hsuan 	/* waiting for the sensor after powering up */
919*fd553196SKate Hsuan 	fsleep(20000);
920*fd553196SKate Hsuan 
921*fd553196SKate Hsuan 	ret = t4ka3_detect(sensor, &sensor_id);
922*fd553196SKate Hsuan 	if (ret) {
923*fd553196SKate Hsuan 		dev_err(sensor->dev, "sensor detect failed\n");
924*fd553196SKate Hsuan 		gpiod_set_value_cansleep(sensor->powerdown_gpio, 1);
925*fd553196SKate Hsuan 		gpiod_set_value_cansleep(sensor->reset_gpio, 1);
926*fd553196SKate Hsuan 
927*fd553196SKate Hsuan 		return ret;
928*fd553196SKate Hsuan 	}
929*fd553196SKate Hsuan 
930*fd553196SKate Hsuan 	return 0;
931*fd553196SKate Hsuan }
932*fd553196SKate Hsuan 
933*fd553196SKate Hsuan static DEFINE_RUNTIME_DEV_PM_OPS(t4ka3_pm_ops, t4ka3_pm_suspend,
934*fd553196SKate Hsuan 				 t4ka3_pm_resume, NULL);
935*fd553196SKate Hsuan 
936*fd553196SKate Hsuan static void t4ka3_remove(struct i2c_client *client)
937*fd553196SKate Hsuan {
938*fd553196SKate Hsuan 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
939*fd553196SKate Hsuan 	struct t4ka3_data *sensor = to_t4ka3_sensor(sd);
940*fd553196SKate Hsuan 
941*fd553196SKate Hsuan 	v4l2_async_unregister_subdev(&sensor->sd);
942*fd553196SKate Hsuan 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
943*fd553196SKate Hsuan 	v4l2_subdev_cleanup(sd);
944*fd553196SKate Hsuan 	media_entity_cleanup(&sensor->sd.entity);
945*fd553196SKate Hsuan 
946*fd553196SKate Hsuan 	/*
947*fd553196SKate Hsuan 	 * Disable runtime PM. In case runtime PM is disabled in the kernel,
948*fd553196SKate Hsuan 	 * make sure to turn power off manually.
949*fd553196SKate Hsuan 	 */
950*fd553196SKate Hsuan 	pm_runtime_disable(&client->dev);
951*fd553196SKate Hsuan 	if (!pm_runtime_status_suspended(&client->dev))
952*fd553196SKate Hsuan 		t4ka3_pm_suspend(&client->dev);
953*fd553196SKate Hsuan 	pm_runtime_set_suspended(&client->dev);
954*fd553196SKate Hsuan }
955*fd553196SKate Hsuan 
956*fd553196SKate Hsuan static int t4ka3_probe(struct i2c_client *client)
957*fd553196SKate Hsuan {
958*fd553196SKate Hsuan 	struct t4ka3_data *sensor;
959*fd553196SKate Hsuan 	int ret;
960*fd553196SKate Hsuan 
961*fd553196SKate Hsuan 	/* allocate sensor device & init sub device */
962*fd553196SKate Hsuan 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
963*fd553196SKate Hsuan 	if (!sensor)
964*fd553196SKate Hsuan 		return -ENOMEM;
965*fd553196SKate Hsuan 
966*fd553196SKate Hsuan 	sensor->dev = &client->dev;
967*fd553196SKate Hsuan 
968*fd553196SKate Hsuan 	ret = t4ka3_check_hwcfg(sensor);
969*fd553196SKate Hsuan 	if (ret)
970*fd553196SKate Hsuan 		return ret;
971*fd553196SKate Hsuan 
972*fd553196SKate Hsuan 	mutex_init(&sensor->lock);
973*fd553196SKate Hsuan 
974*fd553196SKate Hsuan 	v4l2_i2c_subdev_init(&sensor->sd, client, &t4ka3_ops);
975*fd553196SKate Hsuan 	sensor->sd.internal_ops = &t4ka3_internal_ops;
976*fd553196SKate Hsuan 
977*fd553196SKate Hsuan 	sensor->powerdown_gpio = devm_gpiod_get(&client->dev, "powerdown",
978*fd553196SKate Hsuan 						GPIOD_OUT_HIGH);
979*fd553196SKate Hsuan 	if (IS_ERR(sensor->powerdown_gpio))
980*fd553196SKate Hsuan 		return dev_err_probe(&client->dev,
981*fd553196SKate Hsuan 				     PTR_ERR(sensor->powerdown_gpio),
982*fd553196SKate Hsuan 				     "getting powerdown GPIO\n");
983*fd553196SKate Hsuan 
984*fd553196SKate Hsuan 	sensor->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
985*fd553196SKate Hsuan 						     GPIOD_OUT_HIGH);
986*fd553196SKate Hsuan 	if (IS_ERR(sensor->reset_gpio))
987*fd553196SKate Hsuan 		return dev_err_probe(&client->dev, PTR_ERR(sensor->reset_gpio),
988*fd553196SKate Hsuan 				     "getting reset GPIO\n");
989*fd553196SKate Hsuan 
990*fd553196SKate Hsuan 	sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
991*fd553196SKate Hsuan 	if (IS_ERR(sensor->regmap))
992*fd553196SKate Hsuan 		return PTR_ERR(sensor->regmap);
993*fd553196SKate Hsuan 
994*fd553196SKate Hsuan 	ret = t4ka3_pm_resume(sensor->dev);
995*fd553196SKate Hsuan 	if (ret)
996*fd553196SKate Hsuan 		return ret;
997*fd553196SKate Hsuan 
998*fd553196SKate Hsuan 	pm_runtime_set_active(&client->dev);
999*fd553196SKate Hsuan 	pm_runtime_enable(&client->dev);
1000*fd553196SKate Hsuan 
1001*fd553196SKate Hsuan 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1002*fd553196SKate Hsuan 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
1003*fd553196SKate Hsuan 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1004*fd553196SKate Hsuan 
1005*fd553196SKate Hsuan 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
1006*fd553196SKate Hsuan 	if (ret)
1007*fd553196SKate Hsuan 		goto err_pm_disable;
1008*fd553196SKate Hsuan 
1009*fd553196SKate Hsuan 	sensor->sd.state_lock = sensor->ctrls.handler.lock;
1010*fd553196SKate Hsuan 	ret = v4l2_subdev_init_finalize(&sensor->sd);
1011*fd553196SKate Hsuan 	if (ret < 0) {
1012*fd553196SKate Hsuan 		dev_err(&client->dev, "failed to init subdev: %d", ret);
1013*fd553196SKate Hsuan 		goto err_media_entity;
1014*fd553196SKate Hsuan 	}
1015*fd553196SKate Hsuan 
1016*fd553196SKate Hsuan 	ret = t4ka3_init_controls(sensor);
1017*fd553196SKate Hsuan 	if (ret)
1018*fd553196SKate Hsuan 		goto err_controls;
1019*fd553196SKate Hsuan 
1020*fd553196SKate Hsuan 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
1021*fd553196SKate Hsuan 	if (ret)
1022*fd553196SKate Hsuan 		goto err_controls;
1023*fd553196SKate Hsuan 
1024*fd553196SKate Hsuan 	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
1025*fd553196SKate Hsuan 	pm_runtime_idle(&client->dev);
1026*fd553196SKate Hsuan 
1027*fd553196SKate Hsuan 	return 0;
1028*fd553196SKate Hsuan 
1029*fd553196SKate Hsuan err_controls:
1030*fd553196SKate Hsuan 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
1031*fd553196SKate Hsuan 	v4l2_subdev_cleanup(&sensor->sd);
1032*fd553196SKate Hsuan 
1033*fd553196SKate Hsuan err_media_entity:
1034*fd553196SKate Hsuan 	media_entity_cleanup(&sensor->sd.entity);
1035*fd553196SKate Hsuan 
1036*fd553196SKate Hsuan err_pm_disable:
1037*fd553196SKate Hsuan 	pm_runtime_disable(&client->dev);
1038*fd553196SKate Hsuan 	pm_runtime_put_noidle(&client->dev);
1039*fd553196SKate Hsuan 	t4ka3_pm_suspend(&client->dev);
1040*fd553196SKate Hsuan 
1041*fd553196SKate Hsuan 	return ret;
1042*fd553196SKate Hsuan }
1043*fd553196SKate Hsuan 
1044*fd553196SKate Hsuan static const struct acpi_device_id t4ka3_acpi_match[] = {
1045*fd553196SKate Hsuan 	{ "XMCC0003" },
1046*fd553196SKate Hsuan 	{}
1047*fd553196SKate Hsuan };
1048*fd553196SKate Hsuan MODULE_DEVICE_TABLE(acpi, t4ka3_acpi_match);
1049*fd553196SKate Hsuan 
1050*fd553196SKate Hsuan static struct i2c_driver t4ka3_driver = {
1051*fd553196SKate Hsuan 	.driver = {
1052*fd553196SKate Hsuan 		.name = "t4ka3",
1053*fd553196SKate Hsuan 		.acpi_match_table = ACPI_PTR(t4ka3_acpi_match),
1054*fd553196SKate Hsuan 		.pm = pm_sleep_ptr(&t4ka3_pm_ops),
1055*fd553196SKate Hsuan 	},
1056*fd553196SKate Hsuan 	.probe = t4ka3_probe,
1057*fd553196SKate Hsuan 	.remove = t4ka3_remove,
1058*fd553196SKate Hsuan };
1059*fd553196SKate Hsuan module_i2c_driver(t4ka3_driver)
1060*fd553196SKate Hsuan 
1061*fd553196SKate Hsuan MODULE_DESCRIPTION("A low-level driver for T4KA3 sensor");
1062*fd553196SKate Hsuan MODULE_AUTHOR("HARVEY LV <harvey.lv@intel.com>");
1063*fd553196SKate Hsuan MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>");
1064*fd553196SKate Hsuan MODULE_LICENSE("GPL");
1065