xref: /openbmc/linux/drivers/media/i2c/mt9p031.c (revision cb7a01ac324bf2ee2c666f37ac867e4135f9785a)
1*cb7a01acSMauro Carvalho Chehab /*
2*cb7a01acSMauro Carvalho Chehab  * Driver for MT9P031 CMOS Image Sensor from Aptina
3*cb7a01acSMauro Carvalho Chehab  *
4*cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
5*cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com>
6*cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
7*cb7a01acSMauro Carvalho Chehab  *
8*cb7a01acSMauro Carvalho Chehab  * Based on the MT9V032 driver and Bastian Hecht's code.
9*cb7a01acSMauro Carvalho Chehab  *
10*cb7a01acSMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or modify
11*cb7a01acSMauro Carvalho Chehab  * it under the terms of the GNU General Public License version 2 as
12*cb7a01acSMauro Carvalho Chehab  * published by the Free Software Foundation.
13*cb7a01acSMauro Carvalho Chehab  */
14*cb7a01acSMauro Carvalho Chehab 
15*cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
16*cb7a01acSMauro Carvalho Chehab #include <linux/device.h>
17*cb7a01acSMauro Carvalho Chehab #include <linux/gpio.h>
18*cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
19*cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
20*cb7a01acSMauro Carvalho Chehab #include <linux/log2.h>
21*cb7a01acSMauro Carvalho Chehab #include <linux/pm.h>
22*cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
23*cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
24*cb7a01acSMauro Carvalho Chehab 
25*cb7a01acSMauro Carvalho Chehab #include <media/mt9p031.h>
26*cb7a01acSMauro Carvalho Chehab #include <media/v4l2-chip-ident.h>
27*cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
28*cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
29*cb7a01acSMauro Carvalho Chehab #include <media/v4l2-subdev.h>
30*cb7a01acSMauro Carvalho Chehab 
31*cb7a01acSMauro Carvalho Chehab #include "aptina-pll.h"
32*cb7a01acSMauro Carvalho Chehab 
33*cb7a01acSMauro Carvalho Chehab #define MT9P031_PIXEL_ARRAY_WIDTH			2752
34*cb7a01acSMauro Carvalho Chehab #define MT9P031_PIXEL_ARRAY_HEIGHT			2004
35*cb7a01acSMauro Carvalho Chehab 
36*cb7a01acSMauro Carvalho Chehab #define MT9P031_CHIP_VERSION				0x00
37*cb7a01acSMauro Carvalho Chehab #define		MT9P031_CHIP_VERSION_VALUE		0x1801
38*cb7a01acSMauro Carvalho Chehab #define MT9P031_ROW_START				0x01
39*cb7a01acSMauro Carvalho Chehab #define		MT9P031_ROW_START_MIN			0
40*cb7a01acSMauro Carvalho Chehab #define		MT9P031_ROW_START_MAX			2004
41*cb7a01acSMauro Carvalho Chehab #define		MT9P031_ROW_START_DEF			54
42*cb7a01acSMauro Carvalho Chehab #define MT9P031_COLUMN_START				0x02
43*cb7a01acSMauro Carvalho Chehab #define		MT9P031_COLUMN_START_MIN		0
44*cb7a01acSMauro Carvalho Chehab #define		MT9P031_COLUMN_START_MAX		2750
45*cb7a01acSMauro Carvalho Chehab #define		MT9P031_COLUMN_START_DEF		16
46*cb7a01acSMauro Carvalho Chehab #define MT9P031_WINDOW_HEIGHT				0x03
47*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_HEIGHT_MIN		2
48*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_HEIGHT_MAX		2006
49*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_HEIGHT_DEF		1944
50*cb7a01acSMauro Carvalho Chehab #define MT9P031_WINDOW_WIDTH				0x04
51*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_WIDTH_MIN		2
52*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_WIDTH_MAX		2752
53*cb7a01acSMauro Carvalho Chehab #define		MT9P031_WINDOW_WIDTH_DEF		2592
54*cb7a01acSMauro Carvalho Chehab #define MT9P031_HORIZONTAL_BLANK			0x05
55*cb7a01acSMauro Carvalho Chehab #define		MT9P031_HORIZONTAL_BLANK_MIN		0
56*cb7a01acSMauro Carvalho Chehab #define		MT9P031_HORIZONTAL_BLANK_MAX		4095
57*cb7a01acSMauro Carvalho Chehab #define MT9P031_VERTICAL_BLANK				0x06
58*cb7a01acSMauro Carvalho Chehab #define		MT9P031_VERTICAL_BLANK_MIN		0
59*cb7a01acSMauro Carvalho Chehab #define		MT9P031_VERTICAL_BLANK_MAX		4095
60*cb7a01acSMauro Carvalho Chehab #define		MT9P031_VERTICAL_BLANK_DEF		25
61*cb7a01acSMauro Carvalho Chehab #define MT9P031_OUTPUT_CONTROL				0x07
62*cb7a01acSMauro Carvalho Chehab #define		MT9P031_OUTPUT_CONTROL_CEN		2
63*cb7a01acSMauro Carvalho Chehab #define		MT9P031_OUTPUT_CONTROL_SYN		1
64*cb7a01acSMauro Carvalho Chehab #define		MT9P031_OUTPUT_CONTROL_DEF		0x1f82
65*cb7a01acSMauro Carvalho Chehab #define MT9P031_SHUTTER_WIDTH_UPPER			0x08
66*cb7a01acSMauro Carvalho Chehab #define MT9P031_SHUTTER_WIDTH_LOWER			0x09
67*cb7a01acSMauro Carvalho Chehab #define		MT9P031_SHUTTER_WIDTH_MIN		1
68*cb7a01acSMauro Carvalho Chehab #define		MT9P031_SHUTTER_WIDTH_MAX		1048575
69*cb7a01acSMauro Carvalho Chehab #define		MT9P031_SHUTTER_WIDTH_DEF		1943
70*cb7a01acSMauro Carvalho Chehab #define	MT9P031_PLL_CONTROL				0x10
71*cb7a01acSMauro Carvalho Chehab #define		MT9P031_PLL_CONTROL_PWROFF		0x0050
72*cb7a01acSMauro Carvalho Chehab #define		MT9P031_PLL_CONTROL_PWRON		0x0051
73*cb7a01acSMauro Carvalho Chehab #define		MT9P031_PLL_CONTROL_USEPLL		0x0052
74*cb7a01acSMauro Carvalho Chehab #define	MT9P031_PLL_CONFIG_1				0x11
75*cb7a01acSMauro Carvalho Chehab #define	MT9P031_PLL_CONFIG_2				0x12
76*cb7a01acSMauro Carvalho Chehab #define MT9P031_PIXEL_CLOCK_CONTROL			0x0a
77*cb7a01acSMauro Carvalho Chehab #define MT9P031_FRAME_RESTART				0x0b
78*cb7a01acSMauro Carvalho Chehab #define MT9P031_SHUTTER_DELAY				0x0c
79*cb7a01acSMauro Carvalho Chehab #define MT9P031_RST					0x0d
80*cb7a01acSMauro Carvalho Chehab #define		MT9P031_RST_ENABLE			1
81*cb7a01acSMauro Carvalho Chehab #define		MT9P031_RST_DISABLE			0
82*cb7a01acSMauro Carvalho Chehab #define MT9P031_READ_MODE_1				0x1e
83*cb7a01acSMauro Carvalho Chehab #define MT9P031_READ_MODE_2				0x20
84*cb7a01acSMauro Carvalho Chehab #define		MT9P031_READ_MODE_2_ROW_MIR		(1 << 15)
85*cb7a01acSMauro Carvalho Chehab #define		MT9P031_READ_MODE_2_COL_MIR		(1 << 14)
86*cb7a01acSMauro Carvalho Chehab #define		MT9P031_READ_MODE_2_ROW_BLC		(1 << 6)
87*cb7a01acSMauro Carvalho Chehab #define MT9P031_ROW_ADDRESS_MODE			0x22
88*cb7a01acSMauro Carvalho Chehab #define MT9P031_COLUMN_ADDRESS_MODE			0x23
89*cb7a01acSMauro Carvalho Chehab #define MT9P031_GLOBAL_GAIN				0x35
90*cb7a01acSMauro Carvalho Chehab #define		MT9P031_GLOBAL_GAIN_MIN			8
91*cb7a01acSMauro Carvalho Chehab #define		MT9P031_GLOBAL_GAIN_MAX			1024
92*cb7a01acSMauro Carvalho Chehab #define		MT9P031_GLOBAL_GAIN_DEF			8
93*cb7a01acSMauro Carvalho Chehab #define		MT9P031_GLOBAL_GAIN_MULT		(1 << 6)
94*cb7a01acSMauro Carvalho Chehab #define MT9P031_ROW_BLACK_TARGET			0x49
95*cb7a01acSMauro Carvalho Chehab #define MT9P031_ROW_BLACK_DEF_OFFSET			0x4b
96*cb7a01acSMauro Carvalho Chehab #define MT9P031_GREEN1_OFFSET				0x60
97*cb7a01acSMauro Carvalho Chehab #define MT9P031_GREEN2_OFFSET				0x61
98*cb7a01acSMauro Carvalho Chehab #define MT9P031_BLACK_LEVEL_CALIBRATION			0x62
99*cb7a01acSMauro Carvalho Chehab #define		MT9P031_BLC_MANUAL_BLC			(1 << 0)
100*cb7a01acSMauro Carvalho Chehab #define MT9P031_RED_OFFSET				0x63
101*cb7a01acSMauro Carvalho Chehab #define MT9P031_BLUE_OFFSET				0x64
102*cb7a01acSMauro Carvalho Chehab #define MT9P031_TEST_PATTERN				0xa0
103*cb7a01acSMauro Carvalho Chehab #define		MT9P031_TEST_PATTERN_SHIFT		3
104*cb7a01acSMauro Carvalho Chehab #define		MT9P031_TEST_PATTERN_ENABLE		(1 << 0)
105*cb7a01acSMauro Carvalho Chehab #define		MT9P031_TEST_PATTERN_DISABLE		(0 << 0)
106*cb7a01acSMauro Carvalho Chehab #define MT9P031_TEST_PATTERN_GREEN			0xa1
107*cb7a01acSMauro Carvalho Chehab #define MT9P031_TEST_PATTERN_RED			0xa2
108*cb7a01acSMauro Carvalho Chehab #define MT9P031_TEST_PATTERN_BLUE			0xa3
109*cb7a01acSMauro Carvalho Chehab 
110*cb7a01acSMauro Carvalho Chehab enum mt9p031_model {
111*cb7a01acSMauro Carvalho Chehab 	MT9P031_MODEL_COLOR,
112*cb7a01acSMauro Carvalho Chehab 	MT9P031_MODEL_MONOCHROME,
113*cb7a01acSMauro Carvalho Chehab };
114*cb7a01acSMauro Carvalho Chehab 
115*cb7a01acSMauro Carvalho Chehab struct mt9p031 {
116*cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev subdev;
117*cb7a01acSMauro Carvalho Chehab 	struct media_pad pad;
118*cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect crop;  /* Sensor window */
119*cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt format;
120*cb7a01acSMauro Carvalho Chehab 	struct mt9p031_platform_data *pdata;
121*cb7a01acSMauro Carvalho Chehab 	struct mutex power_lock; /* lock to protect power_count */
122*cb7a01acSMauro Carvalho Chehab 	int power_count;
123*cb7a01acSMauro Carvalho Chehab 
124*cb7a01acSMauro Carvalho Chehab 	enum mt9p031_model model;
125*cb7a01acSMauro Carvalho Chehab 	struct aptina_pll pll;
126*cb7a01acSMauro Carvalho Chehab 	int reset;
127*cb7a01acSMauro Carvalho Chehab 
128*cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler ctrls;
129*cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl *blc_auto;
130*cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl *blc_offset;
131*cb7a01acSMauro Carvalho Chehab 
132*cb7a01acSMauro Carvalho Chehab 	/* Registers cache */
133*cb7a01acSMauro Carvalho Chehab 	u16 output_control;
134*cb7a01acSMauro Carvalho Chehab 	u16 mode2;
135*cb7a01acSMauro Carvalho Chehab };
136*cb7a01acSMauro Carvalho Chehab 
137*cb7a01acSMauro Carvalho Chehab static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
138*cb7a01acSMauro Carvalho Chehab {
139*cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct mt9p031, subdev);
140*cb7a01acSMauro Carvalho Chehab }
141*cb7a01acSMauro Carvalho Chehab 
142*cb7a01acSMauro Carvalho Chehab static int mt9p031_read(struct i2c_client *client, u8 reg)
143*cb7a01acSMauro Carvalho Chehab {
144*cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_read_word_swapped(client, reg);
145*cb7a01acSMauro Carvalho Chehab }
146*cb7a01acSMauro Carvalho Chehab 
147*cb7a01acSMauro Carvalho Chehab static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
148*cb7a01acSMauro Carvalho Chehab {
149*cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_write_word_swapped(client, reg, data);
150*cb7a01acSMauro Carvalho Chehab }
151*cb7a01acSMauro Carvalho Chehab 
152*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
153*cb7a01acSMauro Carvalho Chehab 				      u16 set)
154*cb7a01acSMauro Carvalho Chehab {
155*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
156*cb7a01acSMauro Carvalho Chehab 	u16 value = (mt9p031->output_control & ~clear) | set;
157*cb7a01acSMauro Carvalho Chehab 	int ret;
158*cb7a01acSMauro Carvalho Chehab 
159*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_OUTPUT_CONTROL, value);
160*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
161*cb7a01acSMauro Carvalho Chehab 		return ret;
162*cb7a01acSMauro Carvalho Chehab 
163*cb7a01acSMauro Carvalho Chehab 	mt9p031->output_control = value;
164*cb7a01acSMauro Carvalho Chehab 	return 0;
165*cb7a01acSMauro Carvalho Chehab }
166*cb7a01acSMauro Carvalho Chehab 
167*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_mode2(struct mt9p031 *mt9p031, u16 clear, u16 set)
168*cb7a01acSMauro Carvalho Chehab {
169*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
170*cb7a01acSMauro Carvalho Chehab 	u16 value = (mt9p031->mode2 & ~clear) | set;
171*cb7a01acSMauro Carvalho Chehab 	int ret;
172*cb7a01acSMauro Carvalho Chehab 
173*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_READ_MODE_2, value);
174*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
175*cb7a01acSMauro Carvalho Chehab 		return ret;
176*cb7a01acSMauro Carvalho Chehab 
177*cb7a01acSMauro Carvalho Chehab 	mt9p031->mode2 = value;
178*cb7a01acSMauro Carvalho Chehab 	return 0;
179*cb7a01acSMauro Carvalho Chehab }
180*cb7a01acSMauro Carvalho Chehab 
181*cb7a01acSMauro Carvalho Chehab static int mt9p031_reset(struct mt9p031 *mt9p031)
182*cb7a01acSMauro Carvalho Chehab {
183*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
184*cb7a01acSMauro Carvalho Chehab 	int ret;
185*cb7a01acSMauro Carvalho Chehab 
186*cb7a01acSMauro Carvalho Chehab 	/* Disable chip output, synchronous option update */
187*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE);
188*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
189*cb7a01acSMauro Carvalho Chehab 		return ret;
190*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_DISABLE);
191*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
192*cb7a01acSMauro Carvalho Chehab 		return ret;
193*cb7a01acSMauro Carvalho Chehab 
194*cb7a01acSMauro Carvalho Chehab 	return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
195*cb7a01acSMauro Carvalho Chehab 					  0);
196*cb7a01acSMauro Carvalho Chehab }
197*cb7a01acSMauro Carvalho Chehab 
198*cb7a01acSMauro Carvalho Chehab static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
199*cb7a01acSMauro Carvalho Chehab {
200*cb7a01acSMauro Carvalho Chehab 	static const struct aptina_pll_limits limits = {
201*cb7a01acSMauro Carvalho Chehab 		.ext_clock_min = 6000000,
202*cb7a01acSMauro Carvalho Chehab 		.ext_clock_max = 27000000,
203*cb7a01acSMauro Carvalho Chehab 		.int_clock_min = 2000000,
204*cb7a01acSMauro Carvalho Chehab 		.int_clock_max = 13500000,
205*cb7a01acSMauro Carvalho Chehab 		.out_clock_min = 180000000,
206*cb7a01acSMauro Carvalho Chehab 		.out_clock_max = 360000000,
207*cb7a01acSMauro Carvalho Chehab 		.pix_clock_max = 96000000,
208*cb7a01acSMauro Carvalho Chehab 		.n_min = 1,
209*cb7a01acSMauro Carvalho Chehab 		.n_max = 64,
210*cb7a01acSMauro Carvalho Chehab 		.m_min = 16,
211*cb7a01acSMauro Carvalho Chehab 		.m_max = 255,
212*cb7a01acSMauro Carvalho Chehab 		.p1_min = 1,
213*cb7a01acSMauro Carvalho Chehab 		.p1_max = 128,
214*cb7a01acSMauro Carvalho Chehab 	};
215*cb7a01acSMauro Carvalho Chehab 
216*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
217*cb7a01acSMauro Carvalho Chehab 	struct mt9p031_platform_data *pdata = mt9p031->pdata;
218*cb7a01acSMauro Carvalho Chehab 
219*cb7a01acSMauro Carvalho Chehab 	mt9p031->pll.ext_clock = pdata->ext_freq;
220*cb7a01acSMauro Carvalho Chehab 	mt9p031->pll.pix_clock = pdata->target_freq;
221*cb7a01acSMauro Carvalho Chehab 
222*cb7a01acSMauro Carvalho Chehab 	return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
223*cb7a01acSMauro Carvalho Chehab }
224*cb7a01acSMauro Carvalho Chehab 
225*cb7a01acSMauro Carvalho Chehab static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
226*cb7a01acSMauro Carvalho Chehab {
227*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
228*cb7a01acSMauro Carvalho Chehab 	int ret;
229*cb7a01acSMauro Carvalho Chehab 
230*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
231*cb7a01acSMauro Carvalho Chehab 			    MT9P031_PLL_CONTROL_PWRON);
232*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
233*cb7a01acSMauro Carvalho Chehab 		return ret;
234*cb7a01acSMauro Carvalho Chehab 
235*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
236*cb7a01acSMauro Carvalho Chehab 			    (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
237*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
238*cb7a01acSMauro Carvalho Chehab 		return ret;
239*cb7a01acSMauro Carvalho Chehab 
240*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
241*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
242*cb7a01acSMauro Carvalho Chehab 		return ret;
243*cb7a01acSMauro Carvalho Chehab 
244*cb7a01acSMauro Carvalho Chehab 	usleep_range(1000, 2000);
245*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
246*cb7a01acSMauro Carvalho Chehab 			    MT9P031_PLL_CONTROL_PWRON |
247*cb7a01acSMauro Carvalho Chehab 			    MT9P031_PLL_CONTROL_USEPLL);
248*cb7a01acSMauro Carvalho Chehab 	return ret;
249*cb7a01acSMauro Carvalho Chehab }
250*cb7a01acSMauro Carvalho Chehab 
251*cb7a01acSMauro Carvalho Chehab static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
252*cb7a01acSMauro Carvalho Chehab {
253*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
254*cb7a01acSMauro Carvalho Chehab 
255*cb7a01acSMauro Carvalho Chehab 	return mt9p031_write(client, MT9P031_PLL_CONTROL,
256*cb7a01acSMauro Carvalho Chehab 			     MT9P031_PLL_CONTROL_PWROFF);
257*cb7a01acSMauro Carvalho Chehab }
258*cb7a01acSMauro Carvalho Chehab 
259*cb7a01acSMauro Carvalho Chehab static int mt9p031_power_on(struct mt9p031 *mt9p031)
260*cb7a01acSMauro Carvalho Chehab {
261*cb7a01acSMauro Carvalho Chehab 	/* Ensure RESET_BAR is low */
262*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->reset != -1) {
263*cb7a01acSMauro Carvalho Chehab 		gpio_set_value(mt9p031->reset, 0);
264*cb7a01acSMauro Carvalho Chehab 		usleep_range(1000, 2000);
265*cb7a01acSMauro Carvalho Chehab 	}
266*cb7a01acSMauro Carvalho Chehab 
267*cb7a01acSMauro Carvalho Chehab 	/* Emable clock */
268*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->pdata->set_xclk)
269*cb7a01acSMauro Carvalho Chehab 		mt9p031->pdata->set_xclk(&mt9p031->subdev,
270*cb7a01acSMauro Carvalho Chehab 					 mt9p031->pdata->ext_freq);
271*cb7a01acSMauro Carvalho Chehab 
272*cb7a01acSMauro Carvalho Chehab 	/* Now RESET_BAR must be high */
273*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->reset != -1) {
274*cb7a01acSMauro Carvalho Chehab 		gpio_set_value(mt9p031->reset, 1);
275*cb7a01acSMauro Carvalho Chehab 		usleep_range(1000, 2000);
276*cb7a01acSMauro Carvalho Chehab 	}
277*cb7a01acSMauro Carvalho Chehab 
278*cb7a01acSMauro Carvalho Chehab 	return 0;
279*cb7a01acSMauro Carvalho Chehab }
280*cb7a01acSMauro Carvalho Chehab 
281*cb7a01acSMauro Carvalho Chehab static void mt9p031_power_off(struct mt9p031 *mt9p031)
282*cb7a01acSMauro Carvalho Chehab {
283*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->reset != -1) {
284*cb7a01acSMauro Carvalho Chehab 		gpio_set_value(mt9p031->reset, 0);
285*cb7a01acSMauro Carvalho Chehab 		usleep_range(1000, 2000);
286*cb7a01acSMauro Carvalho Chehab 	}
287*cb7a01acSMauro Carvalho Chehab 
288*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->pdata->set_xclk)
289*cb7a01acSMauro Carvalho Chehab 		mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
290*cb7a01acSMauro Carvalho Chehab }
291*cb7a01acSMauro Carvalho Chehab 
292*cb7a01acSMauro Carvalho Chehab static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
293*cb7a01acSMauro Carvalho Chehab {
294*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
295*cb7a01acSMauro Carvalho Chehab 	int ret;
296*cb7a01acSMauro Carvalho Chehab 
297*cb7a01acSMauro Carvalho Chehab 	if (!on) {
298*cb7a01acSMauro Carvalho Chehab 		mt9p031_power_off(mt9p031);
299*cb7a01acSMauro Carvalho Chehab 		return 0;
300*cb7a01acSMauro Carvalho Chehab 	}
301*cb7a01acSMauro Carvalho Chehab 
302*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_power_on(mt9p031);
303*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
304*cb7a01acSMauro Carvalho Chehab 		return ret;
305*cb7a01acSMauro Carvalho Chehab 
306*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_reset(mt9p031);
307*cb7a01acSMauro Carvalho Chehab 	if (ret < 0) {
308*cb7a01acSMauro Carvalho Chehab 		dev_err(&client->dev, "Failed to reset the camera\n");
309*cb7a01acSMauro Carvalho Chehab 		return ret;
310*cb7a01acSMauro Carvalho Chehab 	}
311*cb7a01acSMauro Carvalho Chehab 
312*cb7a01acSMauro Carvalho Chehab 	return v4l2_ctrl_handler_setup(&mt9p031->ctrls);
313*cb7a01acSMauro Carvalho Chehab }
314*cb7a01acSMauro Carvalho Chehab 
315*cb7a01acSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
316*cb7a01acSMauro Carvalho Chehab  * V4L2 subdev video operations
317*cb7a01acSMauro Carvalho Chehab  */
318*cb7a01acSMauro Carvalho Chehab 
319*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_params(struct mt9p031 *mt9p031)
320*cb7a01acSMauro Carvalho Chehab {
321*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
322*cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt *format = &mt9p031->format;
323*cb7a01acSMauro Carvalho Chehab 	const struct v4l2_rect *crop = &mt9p031->crop;
324*cb7a01acSMauro Carvalho Chehab 	unsigned int hblank;
325*cb7a01acSMauro Carvalho Chehab 	unsigned int vblank;
326*cb7a01acSMauro Carvalho Chehab 	unsigned int xskip;
327*cb7a01acSMauro Carvalho Chehab 	unsigned int yskip;
328*cb7a01acSMauro Carvalho Chehab 	unsigned int xbin;
329*cb7a01acSMauro Carvalho Chehab 	unsigned int ybin;
330*cb7a01acSMauro Carvalho Chehab 	int ret;
331*cb7a01acSMauro Carvalho Chehab 
332*cb7a01acSMauro Carvalho Chehab 	/* Windows position and size.
333*cb7a01acSMauro Carvalho Chehab 	 *
334*cb7a01acSMauro Carvalho Chehab 	 * TODO: Make sure the start coordinates and window size match the
335*cb7a01acSMauro Carvalho Chehab 	 * skipping, binning and mirroring (see description of registers 2 and 4
336*cb7a01acSMauro Carvalho Chehab 	 * in table 13, and Binning section on page 41).
337*cb7a01acSMauro Carvalho Chehab 	 */
338*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left);
339*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
340*cb7a01acSMauro Carvalho Chehab 		return ret;
341*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_ROW_START, crop->top);
342*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
343*cb7a01acSMauro Carvalho Chehab 		return ret;
344*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1);
345*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
346*cb7a01acSMauro Carvalho Chehab 		return ret;
347*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1);
348*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
349*cb7a01acSMauro Carvalho Chehab 		return ret;
350*cb7a01acSMauro Carvalho Chehab 
351*cb7a01acSMauro Carvalho Chehab 	/* Row and column binning and skipping. Use the maximum binning value
352*cb7a01acSMauro Carvalho Chehab 	 * compatible with the skipping settings.
353*cb7a01acSMauro Carvalho Chehab 	 */
354*cb7a01acSMauro Carvalho Chehab 	xskip = DIV_ROUND_CLOSEST(crop->width, format->width);
355*cb7a01acSMauro Carvalho Chehab 	yskip = DIV_ROUND_CLOSEST(crop->height, format->height);
356*cb7a01acSMauro Carvalho Chehab 	xbin = 1 << (ffs(xskip) - 1);
357*cb7a01acSMauro Carvalho Chehab 	ybin = 1 << (ffs(yskip) - 1);
358*cb7a01acSMauro Carvalho Chehab 
359*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_COLUMN_ADDRESS_MODE,
360*cb7a01acSMauro Carvalho Chehab 			    ((xbin - 1) << 4) | (xskip - 1));
361*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
362*cb7a01acSMauro Carvalho Chehab 		return ret;
363*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_ROW_ADDRESS_MODE,
364*cb7a01acSMauro Carvalho Chehab 			    ((ybin - 1) << 4) | (yskip - 1));
365*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
366*cb7a01acSMauro Carvalho Chehab 		return ret;
367*cb7a01acSMauro Carvalho Chehab 
368*cb7a01acSMauro Carvalho Chehab 	/* Blanking - use minimum value for horizontal blanking and default
369*cb7a01acSMauro Carvalho Chehab 	 * value for vertical blanking.
370*cb7a01acSMauro Carvalho Chehab 	 */
371*cb7a01acSMauro Carvalho Chehab 	hblank = 346 * ybin + 64 + (80 >> max_t(unsigned int, xbin, 3));
372*cb7a01acSMauro Carvalho Chehab 	vblank = MT9P031_VERTICAL_BLANK_DEF;
373*cb7a01acSMauro Carvalho Chehab 
374*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank);
375*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
376*cb7a01acSMauro Carvalho Chehab 		return ret;
377*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank);
378*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
379*cb7a01acSMauro Carvalho Chehab 		return ret;
380*cb7a01acSMauro Carvalho Chehab 
381*cb7a01acSMauro Carvalho Chehab 	return ret;
382*cb7a01acSMauro Carvalho Chehab }
383*cb7a01acSMauro Carvalho Chehab 
384*cb7a01acSMauro Carvalho Chehab static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
385*cb7a01acSMauro Carvalho Chehab {
386*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
387*cb7a01acSMauro Carvalho Chehab 	int ret;
388*cb7a01acSMauro Carvalho Chehab 
389*cb7a01acSMauro Carvalho Chehab 	if (!enable) {
390*cb7a01acSMauro Carvalho Chehab 		/* Stop sensor readout */
391*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_set_output_control(mt9p031,
392*cb7a01acSMauro Carvalho Chehab 						 MT9P031_OUTPUT_CONTROL_CEN, 0);
393*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
394*cb7a01acSMauro Carvalho Chehab 			return ret;
395*cb7a01acSMauro Carvalho Chehab 
396*cb7a01acSMauro Carvalho Chehab 		return mt9p031_pll_disable(mt9p031);
397*cb7a01acSMauro Carvalho Chehab 	}
398*cb7a01acSMauro Carvalho Chehab 
399*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_set_params(mt9p031);
400*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
401*cb7a01acSMauro Carvalho Chehab 		return ret;
402*cb7a01acSMauro Carvalho Chehab 
403*cb7a01acSMauro Carvalho Chehab 	/* Switch to master "normal" mode */
404*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_set_output_control(mt9p031, 0,
405*cb7a01acSMauro Carvalho Chehab 					 MT9P031_OUTPUT_CONTROL_CEN);
406*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
407*cb7a01acSMauro Carvalho Chehab 		return ret;
408*cb7a01acSMauro Carvalho Chehab 
409*cb7a01acSMauro Carvalho Chehab 	return mt9p031_pll_enable(mt9p031);
410*cb7a01acSMauro Carvalho Chehab }
411*cb7a01acSMauro Carvalho Chehab 
412*cb7a01acSMauro Carvalho Chehab static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
413*cb7a01acSMauro Carvalho Chehab 				  struct v4l2_subdev_fh *fh,
414*cb7a01acSMauro Carvalho Chehab 				  struct v4l2_subdev_mbus_code_enum *code)
415*cb7a01acSMauro Carvalho Chehab {
416*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
417*cb7a01acSMauro Carvalho Chehab 
418*cb7a01acSMauro Carvalho Chehab 	if (code->pad || code->index)
419*cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
420*cb7a01acSMauro Carvalho Chehab 
421*cb7a01acSMauro Carvalho Chehab 	code->code = mt9p031->format.code;
422*cb7a01acSMauro Carvalho Chehab 	return 0;
423*cb7a01acSMauro Carvalho Chehab }
424*cb7a01acSMauro Carvalho Chehab 
425*cb7a01acSMauro Carvalho Chehab static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
426*cb7a01acSMauro Carvalho Chehab 				   struct v4l2_subdev_fh *fh,
427*cb7a01acSMauro Carvalho Chehab 				   struct v4l2_subdev_frame_size_enum *fse)
428*cb7a01acSMauro Carvalho Chehab {
429*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
430*cb7a01acSMauro Carvalho Chehab 
431*cb7a01acSMauro Carvalho Chehab 	if (fse->index >= 8 || fse->code != mt9p031->format.code)
432*cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
433*cb7a01acSMauro Carvalho Chehab 
434*cb7a01acSMauro Carvalho Chehab 	fse->min_width = MT9P031_WINDOW_WIDTH_DEF
435*cb7a01acSMauro Carvalho Chehab 		       / min_t(unsigned int, 7, fse->index + 1);
436*cb7a01acSMauro Carvalho Chehab 	fse->max_width = fse->min_width;
437*cb7a01acSMauro Carvalho Chehab 	fse->min_height = MT9P031_WINDOW_HEIGHT_DEF / (fse->index + 1);
438*cb7a01acSMauro Carvalho Chehab 	fse->max_height = fse->min_height;
439*cb7a01acSMauro Carvalho Chehab 
440*cb7a01acSMauro Carvalho Chehab 	return 0;
441*cb7a01acSMauro Carvalho Chehab }
442*cb7a01acSMauro Carvalho Chehab 
443*cb7a01acSMauro Carvalho Chehab static struct v4l2_mbus_framefmt *
444*cb7a01acSMauro Carvalho Chehab __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
445*cb7a01acSMauro Carvalho Chehab 			 unsigned int pad, u32 which)
446*cb7a01acSMauro Carvalho Chehab {
447*cb7a01acSMauro Carvalho Chehab 	switch (which) {
448*cb7a01acSMauro Carvalho Chehab 	case V4L2_SUBDEV_FORMAT_TRY:
449*cb7a01acSMauro Carvalho Chehab 		return v4l2_subdev_get_try_format(fh, pad);
450*cb7a01acSMauro Carvalho Chehab 	case V4L2_SUBDEV_FORMAT_ACTIVE:
451*cb7a01acSMauro Carvalho Chehab 		return &mt9p031->format;
452*cb7a01acSMauro Carvalho Chehab 	default:
453*cb7a01acSMauro Carvalho Chehab 		return NULL;
454*cb7a01acSMauro Carvalho Chehab 	}
455*cb7a01acSMauro Carvalho Chehab }
456*cb7a01acSMauro Carvalho Chehab 
457*cb7a01acSMauro Carvalho Chehab static struct v4l2_rect *
458*cb7a01acSMauro Carvalho Chehab __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh,
459*cb7a01acSMauro Carvalho Chehab 		     unsigned int pad, u32 which)
460*cb7a01acSMauro Carvalho Chehab {
461*cb7a01acSMauro Carvalho Chehab 	switch (which) {
462*cb7a01acSMauro Carvalho Chehab 	case V4L2_SUBDEV_FORMAT_TRY:
463*cb7a01acSMauro Carvalho Chehab 		return v4l2_subdev_get_try_crop(fh, pad);
464*cb7a01acSMauro Carvalho Chehab 	case V4L2_SUBDEV_FORMAT_ACTIVE:
465*cb7a01acSMauro Carvalho Chehab 		return &mt9p031->crop;
466*cb7a01acSMauro Carvalho Chehab 	default:
467*cb7a01acSMauro Carvalho Chehab 		return NULL;
468*cb7a01acSMauro Carvalho Chehab 	}
469*cb7a01acSMauro Carvalho Chehab }
470*cb7a01acSMauro Carvalho Chehab 
471*cb7a01acSMauro Carvalho Chehab static int mt9p031_get_format(struct v4l2_subdev *subdev,
472*cb7a01acSMauro Carvalho Chehab 			      struct v4l2_subdev_fh *fh,
473*cb7a01acSMauro Carvalho Chehab 			      struct v4l2_subdev_format *fmt)
474*cb7a01acSMauro Carvalho Chehab {
475*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
476*cb7a01acSMauro Carvalho Chehab 
477*cb7a01acSMauro Carvalho Chehab 	fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad,
478*cb7a01acSMauro Carvalho Chehab 						fmt->which);
479*cb7a01acSMauro Carvalho Chehab 	return 0;
480*cb7a01acSMauro Carvalho Chehab }
481*cb7a01acSMauro Carvalho Chehab 
482*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_format(struct v4l2_subdev *subdev,
483*cb7a01acSMauro Carvalho Chehab 			      struct v4l2_subdev_fh *fh,
484*cb7a01acSMauro Carvalho Chehab 			      struct v4l2_subdev_format *format)
485*cb7a01acSMauro Carvalho Chehab {
486*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
487*cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt *__format;
488*cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect *__crop;
489*cb7a01acSMauro Carvalho Chehab 	unsigned int width;
490*cb7a01acSMauro Carvalho Chehab 	unsigned int height;
491*cb7a01acSMauro Carvalho Chehab 	unsigned int hratio;
492*cb7a01acSMauro Carvalho Chehab 	unsigned int vratio;
493*cb7a01acSMauro Carvalho Chehab 
494*cb7a01acSMauro Carvalho Chehab 	__crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad,
495*cb7a01acSMauro Carvalho Chehab 					format->which);
496*cb7a01acSMauro Carvalho Chehab 
497*cb7a01acSMauro Carvalho Chehab 	/* Clamp the width and height to avoid dividing by zero. */
498*cb7a01acSMauro Carvalho Chehab 	width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
499*cb7a01acSMauro Carvalho Chehab 			max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN),
500*cb7a01acSMauro Carvalho Chehab 			__crop->width);
501*cb7a01acSMauro Carvalho Chehab 	height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
502*cb7a01acSMauro Carvalho Chehab 			max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN),
503*cb7a01acSMauro Carvalho Chehab 			__crop->height);
504*cb7a01acSMauro Carvalho Chehab 
505*cb7a01acSMauro Carvalho Chehab 	hratio = DIV_ROUND_CLOSEST(__crop->width, width);
506*cb7a01acSMauro Carvalho Chehab 	vratio = DIV_ROUND_CLOSEST(__crop->height, height);
507*cb7a01acSMauro Carvalho Chehab 
508*cb7a01acSMauro Carvalho Chehab 	__format = __mt9p031_get_pad_format(mt9p031, fh, format->pad,
509*cb7a01acSMauro Carvalho Chehab 					    format->which);
510*cb7a01acSMauro Carvalho Chehab 	__format->width = __crop->width / hratio;
511*cb7a01acSMauro Carvalho Chehab 	__format->height = __crop->height / vratio;
512*cb7a01acSMauro Carvalho Chehab 
513*cb7a01acSMauro Carvalho Chehab 	format->format = *__format;
514*cb7a01acSMauro Carvalho Chehab 
515*cb7a01acSMauro Carvalho Chehab 	return 0;
516*cb7a01acSMauro Carvalho Chehab }
517*cb7a01acSMauro Carvalho Chehab 
518*cb7a01acSMauro Carvalho Chehab static int mt9p031_get_crop(struct v4l2_subdev *subdev,
519*cb7a01acSMauro Carvalho Chehab 			    struct v4l2_subdev_fh *fh,
520*cb7a01acSMauro Carvalho Chehab 			    struct v4l2_subdev_crop *crop)
521*cb7a01acSMauro Carvalho Chehab {
522*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
523*cb7a01acSMauro Carvalho Chehab 
524*cb7a01acSMauro Carvalho Chehab 	crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
525*cb7a01acSMauro Carvalho Chehab 					     crop->which);
526*cb7a01acSMauro Carvalho Chehab 	return 0;
527*cb7a01acSMauro Carvalho Chehab }
528*cb7a01acSMauro Carvalho Chehab 
529*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_crop(struct v4l2_subdev *subdev,
530*cb7a01acSMauro Carvalho Chehab 			    struct v4l2_subdev_fh *fh,
531*cb7a01acSMauro Carvalho Chehab 			    struct v4l2_subdev_crop *crop)
532*cb7a01acSMauro Carvalho Chehab {
533*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
534*cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt *__format;
535*cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect *__crop;
536*cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect rect;
537*cb7a01acSMauro Carvalho Chehab 
538*cb7a01acSMauro Carvalho Chehab 	/* Clamp the crop rectangle boundaries and align them to a multiple of 2
539*cb7a01acSMauro Carvalho Chehab 	 * pixels to ensure a GRBG Bayer pattern.
540*cb7a01acSMauro Carvalho Chehab 	 */
541*cb7a01acSMauro Carvalho Chehab 	rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN,
542*cb7a01acSMauro Carvalho Chehab 			  MT9P031_COLUMN_START_MAX);
543*cb7a01acSMauro Carvalho Chehab 	rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
544*cb7a01acSMauro Carvalho Chehab 			 MT9P031_ROW_START_MAX);
545*cb7a01acSMauro Carvalho Chehab 	rect.width = clamp(ALIGN(crop->rect.width, 2),
546*cb7a01acSMauro Carvalho Chehab 			   MT9P031_WINDOW_WIDTH_MIN,
547*cb7a01acSMauro Carvalho Chehab 			   MT9P031_WINDOW_WIDTH_MAX);
548*cb7a01acSMauro Carvalho Chehab 	rect.height = clamp(ALIGN(crop->rect.height, 2),
549*cb7a01acSMauro Carvalho Chehab 			    MT9P031_WINDOW_HEIGHT_MIN,
550*cb7a01acSMauro Carvalho Chehab 			    MT9P031_WINDOW_HEIGHT_MAX);
551*cb7a01acSMauro Carvalho Chehab 
552*cb7a01acSMauro Carvalho Chehab 	rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
553*cb7a01acSMauro Carvalho Chehab 	rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
554*cb7a01acSMauro Carvalho Chehab 
555*cb7a01acSMauro Carvalho Chehab 	__crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
556*cb7a01acSMauro Carvalho Chehab 
557*cb7a01acSMauro Carvalho Chehab 	if (rect.width != __crop->width || rect.height != __crop->height) {
558*cb7a01acSMauro Carvalho Chehab 		/* Reset the output image size if the crop rectangle size has
559*cb7a01acSMauro Carvalho Chehab 		 * been modified.
560*cb7a01acSMauro Carvalho Chehab 		 */
561*cb7a01acSMauro Carvalho Chehab 		__format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad,
562*cb7a01acSMauro Carvalho Chehab 						    crop->which);
563*cb7a01acSMauro Carvalho Chehab 		__format->width = rect.width;
564*cb7a01acSMauro Carvalho Chehab 		__format->height = rect.height;
565*cb7a01acSMauro Carvalho Chehab 	}
566*cb7a01acSMauro Carvalho Chehab 
567*cb7a01acSMauro Carvalho Chehab 	*__crop = rect;
568*cb7a01acSMauro Carvalho Chehab 	crop->rect = rect;
569*cb7a01acSMauro Carvalho Chehab 
570*cb7a01acSMauro Carvalho Chehab 	return 0;
571*cb7a01acSMauro Carvalho Chehab }
572*cb7a01acSMauro Carvalho Chehab 
573*cb7a01acSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
574*cb7a01acSMauro Carvalho Chehab  * V4L2 subdev control operations
575*cb7a01acSMauro Carvalho Chehab  */
576*cb7a01acSMauro Carvalho Chehab 
577*cb7a01acSMauro Carvalho Chehab #define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
578*cb7a01acSMauro Carvalho Chehab #define V4L2_CID_BLC_AUTO		(V4L2_CID_USER_BASE | 0x1002)
579*cb7a01acSMauro Carvalho Chehab #define V4L2_CID_BLC_TARGET_LEVEL	(V4L2_CID_USER_BASE | 0x1003)
580*cb7a01acSMauro Carvalho Chehab #define V4L2_CID_BLC_ANALOG_OFFSET	(V4L2_CID_USER_BASE | 0x1004)
581*cb7a01acSMauro Carvalho Chehab #define V4L2_CID_BLC_DIGITAL_OFFSET	(V4L2_CID_USER_BASE | 0x1005)
582*cb7a01acSMauro Carvalho Chehab 
583*cb7a01acSMauro Carvalho Chehab static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
584*cb7a01acSMauro Carvalho Chehab {
585*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 =
586*cb7a01acSMauro Carvalho Chehab 			container_of(ctrl->handler, struct mt9p031, ctrls);
587*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
588*cb7a01acSMauro Carvalho Chehab 	u16 data;
589*cb7a01acSMauro Carvalho Chehab 	int ret;
590*cb7a01acSMauro Carvalho Chehab 
591*cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
592*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_EXPOSURE:
593*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
594*cb7a01acSMauro Carvalho Chehab 				    (ctrl->val >> 16) & 0xffff);
595*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
596*cb7a01acSMauro Carvalho Chehab 			return ret;
597*cb7a01acSMauro Carvalho Chehab 
598*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER,
599*cb7a01acSMauro Carvalho Chehab 				     ctrl->val & 0xffff);
600*cb7a01acSMauro Carvalho Chehab 
601*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_GAIN:
602*cb7a01acSMauro Carvalho Chehab 		/* Gain is controlled by 2 analog stages and a digital stage.
603*cb7a01acSMauro Carvalho Chehab 		 * Valid values for the 3 stages are
604*cb7a01acSMauro Carvalho Chehab 		 *
605*cb7a01acSMauro Carvalho Chehab 		 * Stage                Min     Max     Step
606*cb7a01acSMauro Carvalho Chehab 		 * ------------------------------------------
607*cb7a01acSMauro Carvalho Chehab 		 * First analog stage   x1      x2      1
608*cb7a01acSMauro Carvalho Chehab 		 * Second analog stage  x1      x4      0.125
609*cb7a01acSMauro Carvalho Chehab 		 * Digital stage        x1      x16     0.125
610*cb7a01acSMauro Carvalho Chehab 		 *
611*cb7a01acSMauro Carvalho Chehab 		 * To minimize noise, the gain stages should be used in the
612*cb7a01acSMauro Carvalho Chehab 		 * second analog stage, first analog stage, digital stage order.
613*cb7a01acSMauro Carvalho Chehab 		 * Gain from a previous stage should be pushed to its maximum
614*cb7a01acSMauro Carvalho Chehab 		 * value before the next stage is used.
615*cb7a01acSMauro Carvalho Chehab 		 */
616*cb7a01acSMauro Carvalho Chehab 		if (ctrl->val <= 32) {
617*cb7a01acSMauro Carvalho Chehab 			data = ctrl->val;
618*cb7a01acSMauro Carvalho Chehab 		} else if (ctrl->val <= 64) {
619*cb7a01acSMauro Carvalho Chehab 			ctrl->val &= ~1;
620*cb7a01acSMauro Carvalho Chehab 			data = (1 << 6) | (ctrl->val >> 1);
621*cb7a01acSMauro Carvalho Chehab 		} else {
622*cb7a01acSMauro Carvalho Chehab 			ctrl->val &= ~7;
623*cb7a01acSMauro Carvalho Chehab 			data = ((ctrl->val - 64) << 5) | (1 << 6) | 32;
624*cb7a01acSMauro Carvalho Chehab 		}
625*cb7a01acSMauro Carvalho Chehab 
626*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_GLOBAL_GAIN, data);
627*cb7a01acSMauro Carvalho Chehab 
628*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HFLIP:
629*cb7a01acSMauro Carvalho Chehab 		if (ctrl->val)
630*cb7a01acSMauro Carvalho Chehab 			return mt9p031_set_mode2(mt9p031,
631*cb7a01acSMauro Carvalho Chehab 					0, MT9P031_READ_MODE_2_COL_MIR);
632*cb7a01acSMauro Carvalho Chehab 		else
633*cb7a01acSMauro Carvalho Chehab 			return mt9p031_set_mode2(mt9p031,
634*cb7a01acSMauro Carvalho Chehab 					MT9P031_READ_MODE_2_COL_MIR, 0);
635*cb7a01acSMauro Carvalho Chehab 
636*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_VFLIP:
637*cb7a01acSMauro Carvalho Chehab 		if (ctrl->val)
638*cb7a01acSMauro Carvalho Chehab 			return mt9p031_set_mode2(mt9p031,
639*cb7a01acSMauro Carvalho Chehab 					0, MT9P031_READ_MODE_2_ROW_MIR);
640*cb7a01acSMauro Carvalho Chehab 		else
641*cb7a01acSMauro Carvalho Chehab 			return mt9p031_set_mode2(mt9p031,
642*cb7a01acSMauro Carvalho Chehab 					MT9P031_READ_MODE_2_ROW_MIR, 0);
643*cb7a01acSMauro Carvalho Chehab 
644*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_TEST_PATTERN:
645*cb7a01acSMauro Carvalho Chehab 		if (!ctrl->val) {
646*cb7a01acSMauro Carvalho Chehab 			/* Restore the black level compensation settings. */
647*cb7a01acSMauro Carvalho Chehab 			if (mt9p031->blc_auto->cur.val != 0) {
648*cb7a01acSMauro Carvalho Chehab 				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
649*cb7a01acSMauro Carvalho Chehab 				if (ret < 0)
650*cb7a01acSMauro Carvalho Chehab 					return ret;
651*cb7a01acSMauro Carvalho Chehab 			}
652*cb7a01acSMauro Carvalho Chehab 			if (mt9p031->blc_offset->cur.val != 0) {
653*cb7a01acSMauro Carvalho Chehab 				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
654*cb7a01acSMauro Carvalho Chehab 				if (ret < 0)
655*cb7a01acSMauro Carvalho Chehab 					return ret;
656*cb7a01acSMauro Carvalho Chehab 			}
657*cb7a01acSMauro Carvalho Chehab 			return mt9p031_write(client, MT9P031_TEST_PATTERN,
658*cb7a01acSMauro Carvalho Chehab 					     MT9P031_TEST_PATTERN_DISABLE);
659*cb7a01acSMauro Carvalho Chehab 		}
660*cb7a01acSMauro Carvalho Chehab 
661*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0);
662*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
663*cb7a01acSMauro Carvalho Chehab 			return ret;
664*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_RED, 0x0a50);
665*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
666*cb7a01acSMauro Carvalho Chehab 			return ret;
667*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_TEST_PATTERN_BLUE, 0x0aa0);
668*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
669*cb7a01acSMauro Carvalho Chehab 			return ret;
670*cb7a01acSMauro Carvalho Chehab 
671*cb7a01acSMauro Carvalho Chehab 		/* Disable digital black level compensation when using a test
672*cb7a01acSMauro Carvalho Chehab 		 * pattern.
673*cb7a01acSMauro Carvalho Chehab 		 */
674*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
675*cb7a01acSMauro Carvalho Chehab 					0);
676*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
677*cb7a01acSMauro Carvalho Chehab 			return ret;
678*cb7a01acSMauro Carvalho Chehab 
679*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
680*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
681*cb7a01acSMauro Carvalho Chehab 			return ret;
682*cb7a01acSMauro Carvalho Chehab 
683*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_TEST_PATTERN,
684*cb7a01acSMauro Carvalho Chehab 				((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
685*cb7a01acSMauro Carvalho Chehab 				| MT9P031_TEST_PATTERN_ENABLE);
686*cb7a01acSMauro Carvalho Chehab 
687*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BLC_AUTO:
688*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_set_mode2(mt9p031,
689*cb7a01acSMauro Carvalho Chehab 				ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
690*cb7a01acSMauro Carvalho Chehab 				ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
691*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
692*cb7a01acSMauro Carvalho Chehab 			return ret;
693*cb7a01acSMauro Carvalho Chehab 
694*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
695*cb7a01acSMauro Carvalho Chehab 				     ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
696*cb7a01acSMauro Carvalho Chehab 
697*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BLC_TARGET_LEVEL:
698*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
699*cb7a01acSMauro Carvalho Chehab 				     ctrl->val);
700*cb7a01acSMauro Carvalho Chehab 
701*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BLC_ANALOG_OFFSET:
702*cb7a01acSMauro Carvalho Chehab 		data = ctrl->val & ((1 << 9) - 1);
703*cb7a01acSMauro Carvalho Chehab 
704*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
705*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
706*cb7a01acSMauro Carvalho Chehab 			return ret;
707*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
708*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
709*cb7a01acSMauro Carvalho Chehab 			return ret;
710*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
711*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
712*cb7a01acSMauro Carvalho Chehab 			return ret;
713*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
714*cb7a01acSMauro Carvalho Chehab 
715*cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BLC_DIGITAL_OFFSET:
716*cb7a01acSMauro Carvalho Chehab 		return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
717*cb7a01acSMauro Carvalho Chehab 				     ctrl->val & ((1 << 12) - 1));
718*cb7a01acSMauro Carvalho Chehab 	}
719*cb7a01acSMauro Carvalho Chehab 
720*cb7a01acSMauro Carvalho Chehab 	return 0;
721*cb7a01acSMauro Carvalho Chehab }
722*cb7a01acSMauro Carvalho Chehab 
723*cb7a01acSMauro Carvalho Chehab static struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
724*cb7a01acSMauro Carvalho Chehab 	.s_ctrl = mt9p031_s_ctrl,
725*cb7a01acSMauro Carvalho Chehab };
726*cb7a01acSMauro Carvalho Chehab 
727*cb7a01acSMauro Carvalho Chehab static const char * const mt9p031_test_pattern_menu[] = {
728*cb7a01acSMauro Carvalho Chehab 	"Disabled",
729*cb7a01acSMauro Carvalho Chehab 	"Color Field",
730*cb7a01acSMauro Carvalho Chehab 	"Horizontal Gradient",
731*cb7a01acSMauro Carvalho Chehab 	"Vertical Gradient",
732*cb7a01acSMauro Carvalho Chehab 	"Diagonal Gradient",
733*cb7a01acSMauro Carvalho Chehab 	"Classic Test Pattern",
734*cb7a01acSMauro Carvalho Chehab 	"Walking 1s",
735*cb7a01acSMauro Carvalho Chehab 	"Monochrome Horizontal Bars",
736*cb7a01acSMauro Carvalho Chehab 	"Monochrome Vertical Bars",
737*cb7a01acSMauro Carvalho Chehab 	"Vertical Color Bars",
738*cb7a01acSMauro Carvalho Chehab };
739*cb7a01acSMauro Carvalho Chehab 
740*cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
741*cb7a01acSMauro Carvalho Chehab 	{
742*cb7a01acSMauro Carvalho Chehab 		.ops		= &mt9p031_ctrl_ops,
743*cb7a01acSMauro Carvalho Chehab 		.id		= V4L2_CID_TEST_PATTERN,
744*cb7a01acSMauro Carvalho Chehab 		.type		= V4L2_CTRL_TYPE_MENU,
745*cb7a01acSMauro Carvalho Chehab 		.name		= "Test Pattern",
746*cb7a01acSMauro Carvalho Chehab 		.min		= 0,
747*cb7a01acSMauro Carvalho Chehab 		.max		= ARRAY_SIZE(mt9p031_test_pattern_menu) - 1,
748*cb7a01acSMauro Carvalho Chehab 		.step		= 0,
749*cb7a01acSMauro Carvalho Chehab 		.def		= 0,
750*cb7a01acSMauro Carvalho Chehab 		.flags		= 0,
751*cb7a01acSMauro Carvalho Chehab 		.menu_skip_mask	= 0,
752*cb7a01acSMauro Carvalho Chehab 		.qmenu		= mt9p031_test_pattern_menu,
753*cb7a01acSMauro Carvalho Chehab 	}, {
754*cb7a01acSMauro Carvalho Chehab 		.ops		= &mt9p031_ctrl_ops,
755*cb7a01acSMauro Carvalho Chehab 		.id		= V4L2_CID_BLC_AUTO,
756*cb7a01acSMauro Carvalho Chehab 		.type		= V4L2_CTRL_TYPE_BOOLEAN,
757*cb7a01acSMauro Carvalho Chehab 		.name		= "BLC, Auto",
758*cb7a01acSMauro Carvalho Chehab 		.min		= 0,
759*cb7a01acSMauro Carvalho Chehab 		.max		= 1,
760*cb7a01acSMauro Carvalho Chehab 		.step		= 1,
761*cb7a01acSMauro Carvalho Chehab 		.def		= 1,
762*cb7a01acSMauro Carvalho Chehab 		.flags		= 0,
763*cb7a01acSMauro Carvalho Chehab 	}, {
764*cb7a01acSMauro Carvalho Chehab 		.ops		= &mt9p031_ctrl_ops,
765*cb7a01acSMauro Carvalho Chehab 		.id		= V4L2_CID_BLC_TARGET_LEVEL,
766*cb7a01acSMauro Carvalho Chehab 		.type		= V4L2_CTRL_TYPE_INTEGER,
767*cb7a01acSMauro Carvalho Chehab 		.name		= "BLC Target Level",
768*cb7a01acSMauro Carvalho Chehab 		.min		= 0,
769*cb7a01acSMauro Carvalho Chehab 		.max		= 4095,
770*cb7a01acSMauro Carvalho Chehab 		.step		= 1,
771*cb7a01acSMauro Carvalho Chehab 		.def		= 168,
772*cb7a01acSMauro Carvalho Chehab 		.flags		= 0,
773*cb7a01acSMauro Carvalho Chehab 	}, {
774*cb7a01acSMauro Carvalho Chehab 		.ops		= &mt9p031_ctrl_ops,
775*cb7a01acSMauro Carvalho Chehab 		.id		= V4L2_CID_BLC_ANALOG_OFFSET,
776*cb7a01acSMauro Carvalho Chehab 		.type		= V4L2_CTRL_TYPE_INTEGER,
777*cb7a01acSMauro Carvalho Chehab 		.name		= "BLC Analog Offset",
778*cb7a01acSMauro Carvalho Chehab 		.min		= -255,
779*cb7a01acSMauro Carvalho Chehab 		.max		= 255,
780*cb7a01acSMauro Carvalho Chehab 		.step		= 1,
781*cb7a01acSMauro Carvalho Chehab 		.def		= 32,
782*cb7a01acSMauro Carvalho Chehab 		.flags		= 0,
783*cb7a01acSMauro Carvalho Chehab 	}, {
784*cb7a01acSMauro Carvalho Chehab 		.ops		= &mt9p031_ctrl_ops,
785*cb7a01acSMauro Carvalho Chehab 		.id		= V4L2_CID_BLC_DIGITAL_OFFSET,
786*cb7a01acSMauro Carvalho Chehab 		.type		= V4L2_CTRL_TYPE_INTEGER,
787*cb7a01acSMauro Carvalho Chehab 		.name		= "BLC Digital Offset",
788*cb7a01acSMauro Carvalho Chehab 		.min		= -2048,
789*cb7a01acSMauro Carvalho Chehab 		.max		= 2047,
790*cb7a01acSMauro Carvalho Chehab 		.step		= 1,
791*cb7a01acSMauro Carvalho Chehab 		.def		= 40,
792*cb7a01acSMauro Carvalho Chehab 		.flags		= 0,
793*cb7a01acSMauro Carvalho Chehab 	}
794*cb7a01acSMauro Carvalho Chehab };
795*cb7a01acSMauro Carvalho Chehab 
796*cb7a01acSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
797*cb7a01acSMauro Carvalho Chehab  * V4L2 subdev core operations
798*cb7a01acSMauro Carvalho Chehab  */
799*cb7a01acSMauro Carvalho Chehab 
800*cb7a01acSMauro Carvalho Chehab static int mt9p031_set_power(struct v4l2_subdev *subdev, int on)
801*cb7a01acSMauro Carvalho Chehab {
802*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
803*cb7a01acSMauro Carvalho Chehab 	int ret = 0;
804*cb7a01acSMauro Carvalho Chehab 
805*cb7a01acSMauro Carvalho Chehab 	mutex_lock(&mt9p031->power_lock);
806*cb7a01acSMauro Carvalho Chehab 
807*cb7a01acSMauro Carvalho Chehab 	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
808*cb7a01acSMauro Carvalho Chehab 	 * update the power state.
809*cb7a01acSMauro Carvalho Chehab 	 */
810*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->power_count == !on) {
811*cb7a01acSMauro Carvalho Chehab 		ret = __mt9p031_set_power(mt9p031, !!on);
812*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
813*cb7a01acSMauro Carvalho Chehab 			goto out;
814*cb7a01acSMauro Carvalho Chehab 	}
815*cb7a01acSMauro Carvalho Chehab 
816*cb7a01acSMauro Carvalho Chehab 	/* Update the power count. */
817*cb7a01acSMauro Carvalho Chehab 	mt9p031->power_count += on ? 1 : -1;
818*cb7a01acSMauro Carvalho Chehab 	WARN_ON(mt9p031->power_count < 0);
819*cb7a01acSMauro Carvalho Chehab 
820*cb7a01acSMauro Carvalho Chehab out:
821*cb7a01acSMauro Carvalho Chehab 	mutex_unlock(&mt9p031->power_lock);
822*cb7a01acSMauro Carvalho Chehab 	return ret;
823*cb7a01acSMauro Carvalho Chehab }
824*cb7a01acSMauro Carvalho Chehab 
825*cb7a01acSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
826*cb7a01acSMauro Carvalho Chehab  * V4L2 subdev internal operations
827*cb7a01acSMauro Carvalho Chehab  */
828*cb7a01acSMauro Carvalho Chehab 
829*cb7a01acSMauro Carvalho Chehab static int mt9p031_registered(struct v4l2_subdev *subdev)
830*cb7a01acSMauro Carvalho Chehab {
831*cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(subdev);
832*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
833*cb7a01acSMauro Carvalho Chehab 	s32 data;
834*cb7a01acSMauro Carvalho Chehab 	int ret;
835*cb7a01acSMauro Carvalho Chehab 
836*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_power_on(mt9p031);
837*cb7a01acSMauro Carvalho Chehab 	if (ret < 0) {
838*cb7a01acSMauro Carvalho Chehab 		dev_err(&client->dev, "MT9P031 power up failed\n");
839*cb7a01acSMauro Carvalho Chehab 		return ret;
840*cb7a01acSMauro Carvalho Chehab 	}
841*cb7a01acSMauro Carvalho Chehab 
842*cb7a01acSMauro Carvalho Chehab 	/* Read out the chip version register */
843*cb7a01acSMauro Carvalho Chehab 	data = mt9p031_read(client, MT9P031_CHIP_VERSION);
844*cb7a01acSMauro Carvalho Chehab 	if (data != MT9P031_CHIP_VERSION_VALUE) {
845*cb7a01acSMauro Carvalho Chehab 		dev_err(&client->dev, "MT9P031 not detected, wrong version "
846*cb7a01acSMauro Carvalho Chehab 			"0x%04x\n", data);
847*cb7a01acSMauro Carvalho Chehab 		return -ENODEV;
848*cb7a01acSMauro Carvalho Chehab 	}
849*cb7a01acSMauro Carvalho Chehab 
850*cb7a01acSMauro Carvalho Chehab 	mt9p031_power_off(mt9p031);
851*cb7a01acSMauro Carvalho Chehab 
852*cb7a01acSMauro Carvalho Chehab 	dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
853*cb7a01acSMauro Carvalho Chehab 		 client->addr);
854*cb7a01acSMauro Carvalho Chehab 
855*cb7a01acSMauro Carvalho Chehab 	return ret;
856*cb7a01acSMauro Carvalho Chehab }
857*cb7a01acSMauro Carvalho Chehab 
858*cb7a01acSMauro Carvalho Chehab static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
859*cb7a01acSMauro Carvalho Chehab {
860*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
861*cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt *format;
862*cb7a01acSMauro Carvalho Chehab 	struct v4l2_rect *crop;
863*cb7a01acSMauro Carvalho Chehab 
864*cb7a01acSMauro Carvalho Chehab 	crop = v4l2_subdev_get_try_crop(fh, 0);
865*cb7a01acSMauro Carvalho Chehab 	crop->left = MT9P031_COLUMN_START_DEF;
866*cb7a01acSMauro Carvalho Chehab 	crop->top = MT9P031_ROW_START_DEF;
867*cb7a01acSMauro Carvalho Chehab 	crop->width = MT9P031_WINDOW_WIDTH_DEF;
868*cb7a01acSMauro Carvalho Chehab 	crop->height = MT9P031_WINDOW_HEIGHT_DEF;
869*cb7a01acSMauro Carvalho Chehab 
870*cb7a01acSMauro Carvalho Chehab 	format = v4l2_subdev_get_try_format(fh, 0);
871*cb7a01acSMauro Carvalho Chehab 
872*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
873*cb7a01acSMauro Carvalho Chehab 		format->code = V4L2_MBUS_FMT_Y12_1X12;
874*cb7a01acSMauro Carvalho Chehab 	else
875*cb7a01acSMauro Carvalho Chehab 		format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
876*cb7a01acSMauro Carvalho Chehab 
877*cb7a01acSMauro Carvalho Chehab 	format->width = MT9P031_WINDOW_WIDTH_DEF;
878*cb7a01acSMauro Carvalho Chehab 	format->height = MT9P031_WINDOW_HEIGHT_DEF;
879*cb7a01acSMauro Carvalho Chehab 	format->field = V4L2_FIELD_NONE;
880*cb7a01acSMauro Carvalho Chehab 	format->colorspace = V4L2_COLORSPACE_SRGB;
881*cb7a01acSMauro Carvalho Chehab 
882*cb7a01acSMauro Carvalho Chehab 	return mt9p031_set_power(subdev, 1);
883*cb7a01acSMauro Carvalho Chehab }
884*cb7a01acSMauro Carvalho Chehab 
885*cb7a01acSMauro Carvalho Chehab static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
886*cb7a01acSMauro Carvalho Chehab {
887*cb7a01acSMauro Carvalho Chehab 	return mt9p031_set_power(subdev, 0);
888*cb7a01acSMauro Carvalho Chehab }
889*cb7a01acSMauro Carvalho Chehab 
890*cb7a01acSMauro Carvalho Chehab static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
891*cb7a01acSMauro Carvalho Chehab 	.s_power        = mt9p031_set_power,
892*cb7a01acSMauro Carvalho Chehab };
893*cb7a01acSMauro Carvalho Chehab 
894*cb7a01acSMauro Carvalho Chehab static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
895*cb7a01acSMauro Carvalho Chehab 	.s_stream       = mt9p031_s_stream,
896*cb7a01acSMauro Carvalho Chehab };
897*cb7a01acSMauro Carvalho Chehab 
898*cb7a01acSMauro Carvalho Chehab static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
899*cb7a01acSMauro Carvalho Chehab 	.enum_mbus_code = mt9p031_enum_mbus_code,
900*cb7a01acSMauro Carvalho Chehab 	.enum_frame_size = mt9p031_enum_frame_size,
901*cb7a01acSMauro Carvalho Chehab 	.get_fmt = mt9p031_get_format,
902*cb7a01acSMauro Carvalho Chehab 	.set_fmt = mt9p031_set_format,
903*cb7a01acSMauro Carvalho Chehab 	.get_crop = mt9p031_get_crop,
904*cb7a01acSMauro Carvalho Chehab 	.set_crop = mt9p031_set_crop,
905*cb7a01acSMauro Carvalho Chehab };
906*cb7a01acSMauro Carvalho Chehab 
907*cb7a01acSMauro Carvalho Chehab static struct v4l2_subdev_ops mt9p031_subdev_ops = {
908*cb7a01acSMauro Carvalho Chehab 	.core   = &mt9p031_subdev_core_ops,
909*cb7a01acSMauro Carvalho Chehab 	.video  = &mt9p031_subdev_video_ops,
910*cb7a01acSMauro Carvalho Chehab 	.pad    = &mt9p031_subdev_pad_ops,
911*cb7a01acSMauro Carvalho Chehab };
912*cb7a01acSMauro Carvalho Chehab 
913*cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
914*cb7a01acSMauro Carvalho Chehab 	.registered = mt9p031_registered,
915*cb7a01acSMauro Carvalho Chehab 	.open = mt9p031_open,
916*cb7a01acSMauro Carvalho Chehab 	.close = mt9p031_close,
917*cb7a01acSMauro Carvalho Chehab };
918*cb7a01acSMauro Carvalho Chehab 
919*cb7a01acSMauro Carvalho Chehab /* -----------------------------------------------------------------------------
920*cb7a01acSMauro Carvalho Chehab  * Driver initialization and probing
921*cb7a01acSMauro Carvalho Chehab  */
922*cb7a01acSMauro Carvalho Chehab 
923*cb7a01acSMauro Carvalho Chehab static int mt9p031_probe(struct i2c_client *client,
924*cb7a01acSMauro Carvalho Chehab 			 const struct i2c_device_id *did)
925*cb7a01acSMauro Carvalho Chehab {
926*cb7a01acSMauro Carvalho Chehab 	struct mt9p031_platform_data *pdata = client->dev.platform_data;
927*cb7a01acSMauro Carvalho Chehab 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
928*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031;
929*cb7a01acSMauro Carvalho Chehab 	unsigned int i;
930*cb7a01acSMauro Carvalho Chehab 	int ret;
931*cb7a01acSMauro Carvalho Chehab 
932*cb7a01acSMauro Carvalho Chehab 	if (pdata == NULL) {
933*cb7a01acSMauro Carvalho Chehab 		dev_err(&client->dev, "No platform data\n");
934*cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
935*cb7a01acSMauro Carvalho Chehab 	}
936*cb7a01acSMauro Carvalho Chehab 
937*cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
938*cb7a01acSMauro Carvalho Chehab 		dev_warn(&client->dev,
939*cb7a01acSMauro Carvalho Chehab 			"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
940*cb7a01acSMauro Carvalho Chehab 		return -EIO;
941*cb7a01acSMauro Carvalho Chehab 	}
942*cb7a01acSMauro Carvalho Chehab 
943*cb7a01acSMauro Carvalho Chehab 	mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL);
944*cb7a01acSMauro Carvalho Chehab 	if (mt9p031 == NULL)
945*cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
946*cb7a01acSMauro Carvalho Chehab 
947*cb7a01acSMauro Carvalho Chehab 	mt9p031->pdata = pdata;
948*cb7a01acSMauro Carvalho Chehab 	mt9p031->output_control	= MT9P031_OUTPUT_CONTROL_DEF;
949*cb7a01acSMauro Carvalho Chehab 	mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
950*cb7a01acSMauro Carvalho Chehab 	mt9p031->model = did->driver_data;
951*cb7a01acSMauro Carvalho Chehab 	mt9p031->reset = -1;
952*cb7a01acSMauro Carvalho Chehab 
953*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5);
954*cb7a01acSMauro Carvalho Chehab 
955*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
956*cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
957*cb7a01acSMauro Carvalho Chehab 			  MT9P031_SHUTTER_WIDTH_MAX, 1,
958*cb7a01acSMauro Carvalho Chehab 			  MT9P031_SHUTTER_WIDTH_DEF);
959*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
960*cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_GAIN, MT9P031_GLOBAL_GAIN_MIN,
961*cb7a01acSMauro Carvalho Chehab 			  MT9P031_GLOBAL_GAIN_MAX, 1, MT9P031_GLOBAL_GAIN_DEF);
962*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
963*cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_HFLIP, 0, 1, 1, 0);
964*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
965*cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_VFLIP, 0, 1, 1, 0);
966*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
967*cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_PIXEL_RATE, pdata->target_freq,
968*cb7a01acSMauro Carvalho Chehab 			  pdata->target_freq, 1, pdata->target_freq);
969*cb7a01acSMauro Carvalho Chehab 
970*cb7a01acSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
971*cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
972*cb7a01acSMauro Carvalho Chehab 
973*cb7a01acSMauro Carvalho Chehab 	mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
974*cb7a01acSMauro Carvalho Chehab 
975*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->ctrls.error) {
976*cb7a01acSMauro Carvalho Chehab 		printk(KERN_INFO "%s: control initialization error %d\n",
977*cb7a01acSMauro Carvalho Chehab 		       __func__, mt9p031->ctrls.error);
978*cb7a01acSMauro Carvalho Chehab 		ret = mt9p031->ctrls.error;
979*cb7a01acSMauro Carvalho Chehab 		goto done;
980*cb7a01acSMauro Carvalho Chehab 	}
981*cb7a01acSMauro Carvalho Chehab 
982*cb7a01acSMauro Carvalho Chehab 	mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
983*cb7a01acSMauro Carvalho Chehab 	mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
984*cb7a01acSMauro Carvalho Chehab 					     V4L2_CID_BLC_DIGITAL_OFFSET);
985*cb7a01acSMauro Carvalho Chehab 
986*cb7a01acSMauro Carvalho Chehab 	mutex_init(&mt9p031->power_lock);
987*cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
988*cb7a01acSMauro Carvalho Chehab 	mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
989*cb7a01acSMauro Carvalho Chehab 
990*cb7a01acSMauro Carvalho Chehab 	mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
991*cb7a01acSMauro Carvalho Chehab 	ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
992*cb7a01acSMauro Carvalho Chehab 	if (ret < 0)
993*cb7a01acSMauro Carvalho Chehab 		goto done;
994*cb7a01acSMauro Carvalho Chehab 
995*cb7a01acSMauro Carvalho Chehab 	mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
996*cb7a01acSMauro Carvalho Chehab 
997*cb7a01acSMauro Carvalho Chehab 	mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF;
998*cb7a01acSMauro Carvalho Chehab 	mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF;
999*cb7a01acSMauro Carvalho Chehab 	mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
1000*cb7a01acSMauro Carvalho Chehab 	mt9p031->crop.top = MT9P031_ROW_START_DEF;
1001*cb7a01acSMauro Carvalho Chehab 
1002*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
1003*cb7a01acSMauro Carvalho Chehab 		mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
1004*cb7a01acSMauro Carvalho Chehab 	else
1005*cb7a01acSMauro Carvalho Chehab 		mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
1006*cb7a01acSMauro Carvalho Chehab 
1007*cb7a01acSMauro Carvalho Chehab 	mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
1008*cb7a01acSMauro Carvalho Chehab 	mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
1009*cb7a01acSMauro Carvalho Chehab 	mt9p031->format.field = V4L2_FIELD_NONE;
1010*cb7a01acSMauro Carvalho Chehab 	mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
1011*cb7a01acSMauro Carvalho Chehab 
1012*cb7a01acSMauro Carvalho Chehab 	if (pdata->reset != -1) {
1013*cb7a01acSMauro Carvalho Chehab 		ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
1014*cb7a01acSMauro Carvalho Chehab 				       "mt9p031_rst");
1015*cb7a01acSMauro Carvalho Chehab 		if (ret < 0)
1016*cb7a01acSMauro Carvalho Chehab 			goto done;
1017*cb7a01acSMauro Carvalho Chehab 
1018*cb7a01acSMauro Carvalho Chehab 		mt9p031->reset = pdata->reset;
1019*cb7a01acSMauro Carvalho Chehab 	}
1020*cb7a01acSMauro Carvalho Chehab 
1021*cb7a01acSMauro Carvalho Chehab 	ret = mt9p031_pll_setup(mt9p031);
1022*cb7a01acSMauro Carvalho Chehab 
1023*cb7a01acSMauro Carvalho Chehab done:
1024*cb7a01acSMauro Carvalho Chehab 	if (ret < 0) {
1025*cb7a01acSMauro Carvalho Chehab 		if (mt9p031->reset != -1)
1026*cb7a01acSMauro Carvalho Chehab 			gpio_free(mt9p031->reset);
1027*cb7a01acSMauro Carvalho Chehab 
1028*cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(&mt9p031->ctrls);
1029*cb7a01acSMauro Carvalho Chehab 		media_entity_cleanup(&mt9p031->subdev.entity);
1030*cb7a01acSMauro Carvalho Chehab 		kfree(mt9p031);
1031*cb7a01acSMauro Carvalho Chehab 	}
1032*cb7a01acSMauro Carvalho Chehab 
1033*cb7a01acSMauro Carvalho Chehab 	return ret;
1034*cb7a01acSMauro Carvalho Chehab }
1035*cb7a01acSMauro Carvalho Chehab 
1036*cb7a01acSMauro Carvalho Chehab static int mt9p031_remove(struct i2c_client *client)
1037*cb7a01acSMauro Carvalho Chehab {
1038*cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
1039*cb7a01acSMauro Carvalho Chehab 	struct mt9p031 *mt9p031 = to_mt9p031(subdev);
1040*cb7a01acSMauro Carvalho Chehab 
1041*cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&mt9p031->ctrls);
1042*cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(subdev);
1043*cb7a01acSMauro Carvalho Chehab 	media_entity_cleanup(&subdev->entity);
1044*cb7a01acSMauro Carvalho Chehab 	if (mt9p031->reset != -1)
1045*cb7a01acSMauro Carvalho Chehab 		gpio_free(mt9p031->reset);
1046*cb7a01acSMauro Carvalho Chehab 	kfree(mt9p031);
1047*cb7a01acSMauro Carvalho Chehab 
1048*cb7a01acSMauro Carvalho Chehab 	return 0;
1049*cb7a01acSMauro Carvalho Chehab }
1050*cb7a01acSMauro Carvalho Chehab 
1051*cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id mt9p031_id[] = {
1052*cb7a01acSMauro Carvalho Chehab 	{ "mt9p031", MT9P031_MODEL_COLOR },
1053*cb7a01acSMauro Carvalho Chehab 	{ "mt9p031m", MT9P031_MODEL_MONOCHROME },
1054*cb7a01acSMauro Carvalho Chehab 	{ }
1055*cb7a01acSMauro Carvalho Chehab };
1056*cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, mt9p031_id);
1057*cb7a01acSMauro Carvalho Chehab 
1058*cb7a01acSMauro Carvalho Chehab static struct i2c_driver mt9p031_i2c_driver = {
1059*cb7a01acSMauro Carvalho Chehab 	.driver = {
1060*cb7a01acSMauro Carvalho Chehab 		.name = "mt9p031",
1061*cb7a01acSMauro Carvalho Chehab 	},
1062*cb7a01acSMauro Carvalho Chehab 	.probe          = mt9p031_probe,
1063*cb7a01acSMauro Carvalho Chehab 	.remove         = mt9p031_remove,
1064*cb7a01acSMauro Carvalho Chehab 	.id_table       = mt9p031_id,
1065*cb7a01acSMauro Carvalho Chehab };
1066*cb7a01acSMauro Carvalho Chehab 
1067*cb7a01acSMauro Carvalho Chehab module_i2c_driver(mt9p031_i2c_driver);
1068*cb7a01acSMauro Carvalho Chehab 
1069*cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
1070*cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
1071*cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
1072