xref: /openbmc/linux/drivers/media/i2c/mt9m111.c (revision d2820ce0)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c61e74e3SRobert Jarzmik /*
3c61e74e3SRobert Jarzmik  * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
4c61e74e3SRobert Jarzmik  *
5c61e74e3SRobert Jarzmik  * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
6c61e74e3SRobert Jarzmik  */
7ea6300cdSEzequiel Garcia #include <linux/clk.h>
8c61e74e3SRobert Jarzmik #include <linux/videodev2.h>
9c61e74e3SRobert Jarzmik #include <linux/slab.h>
10c61e74e3SRobert Jarzmik #include <linux/i2c.h>
11c61e74e3SRobert Jarzmik #include <linux/log2.h>
12c61e74e3SRobert Jarzmik #include <linux/delay.h>
133a959dcdSRobert Jarzmik #include <linux/regulator/consumer.h>
14c61e74e3SRobert Jarzmik #include <linux/v4l2-mediabus.h>
15c61e74e3SRobert Jarzmik #include <linux/module.h>
1698480d65SEnrico Scholz #include <linux/property.h>
17c61e74e3SRobert Jarzmik 
18c61e74e3SRobert Jarzmik #include <media/v4l2-async.h>
19c61e74e3SRobert Jarzmik #include <media/v4l2-common.h>
20c61e74e3SRobert Jarzmik #include <media/v4l2-ctrls.h>
21c61e74e3SRobert Jarzmik #include <media/v4l2-device.h>
22329d9e35SAkinobu Mita #include <media/v4l2-event.h>
2398480d65SEnrico Scholz #include <media/v4l2-fwnode.h>
24c61e74e3SRobert Jarzmik 
25c61e74e3SRobert Jarzmik /*
26c61e74e3SRobert Jarzmik  * MT9M111, MT9M112 and MT9M131:
27c61e74e3SRobert Jarzmik  * i2c address is 0x48 or 0x5d (depending on SADDR pin)
28c61e74e3SRobert Jarzmik  * The platform has to define struct i2c_board_info objects and link to them
29c61e74e3SRobert Jarzmik  * from struct soc_camera_host_desc
30c61e74e3SRobert Jarzmik  */
31c61e74e3SRobert Jarzmik 
32c61e74e3SRobert Jarzmik /*
33c61e74e3SRobert Jarzmik  * Sensor core register addresses (0x000..0x0ff)
34c61e74e3SRobert Jarzmik  */
35c61e74e3SRobert Jarzmik #define MT9M111_CHIP_VERSION		0x000
36c61e74e3SRobert Jarzmik #define MT9M111_ROW_START		0x001
37c61e74e3SRobert Jarzmik #define MT9M111_COLUMN_START		0x002
38c61e74e3SRobert Jarzmik #define MT9M111_WINDOW_HEIGHT		0x003
39c61e74e3SRobert Jarzmik #define MT9M111_WINDOW_WIDTH		0x004
40c61e74e3SRobert Jarzmik #define MT9M111_HORIZONTAL_BLANKING_B	0x005
41c61e74e3SRobert Jarzmik #define MT9M111_VERTICAL_BLANKING_B	0x006
42c61e74e3SRobert Jarzmik #define MT9M111_HORIZONTAL_BLANKING_A	0x007
43c61e74e3SRobert Jarzmik #define MT9M111_VERTICAL_BLANKING_A	0x008
44c61e74e3SRobert Jarzmik #define MT9M111_SHUTTER_WIDTH		0x009
45c61e74e3SRobert Jarzmik #define MT9M111_ROW_SPEED		0x00a
46c61e74e3SRobert Jarzmik #define MT9M111_EXTRA_DELAY		0x00b
47c61e74e3SRobert Jarzmik #define MT9M111_SHUTTER_DELAY		0x00c
48c61e74e3SRobert Jarzmik #define MT9M111_RESET			0x00d
49c61e74e3SRobert Jarzmik #define MT9M111_READ_MODE_B		0x020
50c61e74e3SRobert Jarzmik #define MT9M111_READ_MODE_A		0x021
51c61e74e3SRobert Jarzmik #define MT9M111_FLASH_CONTROL		0x023
52c61e74e3SRobert Jarzmik #define MT9M111_GREEN1_GAIN		0x02b
53c61e74e3SRobert Jarzmik #define MT9M111_BLUE_GAIN		0x02c
54c61e74e3SRobert Jarzmik #define MT9M111_RED_GAIN		0x02d
55c61e74e3SRobert Jarzmik #define MT9M111_GREEN2_GAIN		0x02e
56c61e74e3SRobert Jarzmik #define MT9M111_GLOBAL_GAIN		0x02f
57c61e74e3SRobert Jarzmik #define MT9M111_CONTEXT_CONTROL		0x0c8
58c61e74e3SRobert Jarzmik #define MT9M111_PAGE_MAP		0x0f0
59c61e74e3SRobert Jarzmik #define MT9M111_BYTE_WISE_ADDR		0x0f1
60c61e74e3SRobert Jarzmik 
61c61e74e3SRobert Jarzmik #define MT9M111_RESET_SYNC_CHANGES	(1 << 15)
62c61e74e3SRobert Jarzmik #define MT9M111_RESET_RESTART_BAD_FRAME	(1 << 9)
63c61e74e3SRobert Jarzmik #define MT9M111_RESET_SHOW_BAD_FRAMES	(1 << 8)
64c61e74e3SRobert Jarzmik #define MT9M111_RESET_RESET_SOC		(1 << 5)
65c61e74e3SRobert Jarzmik #define MT9M111_RESET_OUTPUT_DISABLE	(1 << 4)
66c61e74e3SRobert Jarzmik #define MT9M111_RESET_CHIP_ENABLE	(1 << 3)
67c61e74e3SRobert Jarzmik #define MT9M111_RESET_ANALOG_STANDBY	(1 << 2)
68c61e74e3SRobert Jarzmik #define MT9M111_RESET_RESTART_FRAME	(1 << 1)
69c61e74e3SRobert Jarzmik #define MT9M111_RESET_RESET_MODE	(1 << 0)
70c61e74e3SRobert Jarzmik 
71c61e74e3SRobert Jarzmik #define MT9M111_RM_FULL_POWER_RD	(0 << 10)
72c61e74e3SRobert Jarzmik #define MT9M111_RM_LOW_POWER_RD		(1 << 10)
73c61e74e3SRobert Jarzmik #define MT9M111_RM_COL_SKIP_4X		(1 << 5)
74c61e74e3SRobert Jarzmik #define MT9M111_RM_ROW_SKIP_4X		(1 << 4)
75c61e74e3SRobert Jarzmik #define MT9M111_RM_COL_SKIP_2X		(1 << 3)
76c61e74e3SRobert Jarzmik #define MT9M111_RM_ROW_SKIP_2X		(1 << 2)
77c61e74e3SRobert Jarzmik #define MT9M111_RMB_MIRROR_COLS		(1 << 1)
78c61e74e3SRobert Jarzmik #define MT9M111_RMB_MIRROR_ROWS		(1 << 0)
79c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_RESTART	(1 << 15)
80c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_DEFECTCOR_B	(1 << 12)
81c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_RESIZE_B	(1 << 10)
82c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_CTRL2_B	(1 << 9)
83c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_GAMMA_B	(1 << 8)
84c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_XENON_EN	(1 << 7)
85c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_READ_MODE_B	(1 << 3)
86c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_LED_FLASH_EN	(1 << 2)
87c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_VBLANK_SEL_B	(1 << 1)
88c61e74e3SRobert Jarzmik #define MT9M111_CTXT_CTRL_HBLANK_SEL_B	(1 << 0)
89c61e74e3SRobert Jarzmik 
90c61e74e3SRobert Jarzmik /*
91c61e74e3SRobert Jarzmik  * Colorpipe register addresses (0x100..0x1ff)
92c61e74e3SRobert Jarzmik  */
93c61e74e3SRobert Jarzmik #define MT9M111_OPER_MODE_CTRL		0x106
94c61e74e3SRobert Jarzmik #define MT9M111_OUTPUT_FORMAT_CTRL	0x108
9574e08739SAkinobu Mita #define MT9M111_TPG_CTRL		0x148
96c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_XZOOM_B		0x1a0
97c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_XSIZE_B		0x1a1
98c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_YZOOM_B		0x1a3
99c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_YSIZE_B		0x1a4
100c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_XZOOM_A		0x1a6
101c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_XSIZE_A		0x1a7
102c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_YZOOM_A		0x1a9
103c61e74e3SRobert Jarzmik #define MT9M111_REDUCER_YSIZE_A		0x1aa
104dde64f72SAkinobu Mita #define MT9M111_EFFECTS_MODE		0x1e2
105c61e74e3SRobert Jarzmik 
106c61e74e3SRobert Jarzmik #define MT9M111_OUTPUT_FORMAT_CTRL2_A	0x13a
107c61e74e3SRobert Jarzmik #define MT9M111_OUTPUT_FORMAT_CTRL2_B	0x19b
108c61e74e3SRobert Jarzmik 
109c61e74e3SRobert Jarzmik #define MT9M111_OPMODE_AUTOEXPO_EN	(1 << 14)
110c61e74e3SRobert Jarzmik #define MT9M111_OPMODE_AUTOWHITEBAL_EN	(1 << 1)
111c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_FLIP_BAYER_COL	(1 << 9)
112c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_FLIP_BAYER_ROW	(1 << 8)
113c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_PROCESSED_BAYER	(1 << 14)
114c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_BYPASS_IFP	(1 << 10)
115c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_INV_PIX_CLOCK	(1 << 9)
116c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_RGB		(1 << 8)
117c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_RGB565		(0 << 6)
118c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_RGB555		(1 << 6)
119c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_RGB444x		(2 << 6)
120c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_RGBx444		(3 << 6)
121c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_TST_RAMP_OFF	(0 << 4)
122c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_TST_RAMP_COL	(1 << 4)
123c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_TST_RAMP_ROW	(2 << 4)
124c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_TST_RAMP_FRAME	(3 << 4)
125c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_SHIFT_3_UP	(1 << 3)
126c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_AVG_CHROMA	(1 << 2)
127c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN	(1 << 1)
128c61e74e3SRobert Jarzmik #define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B	(1 << 0)
12974e08739SAkinobu Mita #define MT9M111_TPG_SEL_MASK		GENMASK(2, 0)
130dde64f72SAkinobu Mita #define MT9M111_EFFECTS_MODE_MASK	GENMASK(2, 0)
131937bb425SMichael Grzeschik #define MT9M111_RM_PWR_MASK		BIT(10)
132937bb425SMichael Grzeschik #define MT9M111_RM_SKIP2_MASK		GENMASK(3, 2)
133c61e74e3SRobert Jarzmik 
134c61e74e3SRobert Jarzmik /*
135c61e74e3SRobert Jarzmik  * Camera control register addresses (0x200..0x2ff not implemented)
136c61e74e3SRobert Jarzmik  */
137c61e74e3SRobert Jarzmik 
138c61e74e3SRobert Jarzmik #define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
139c61e74e3SRobert Jarzmik #define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
140c61e74e3SRobert Jarzmik #define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
141c61e74e3SRobert Jarzmik #define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
142c61e74e3SRobert Jarzmik #define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
143c61e74e3SRobert Jarzmik 		(val), (mask))
144c61e74e3SRobert Jarzmik 
145c61e74e3SRobert Jarzmik #define MT9M111_MIN_DARK_ROWS	8
146c61e74e3SRobert Jarzmik #define MT9M111_MIN_DARK_COLS	26
147c61e74e3SRobert Jarzmik #define MT9M111_MAX_HEIGHT	1024
148c61e74e3SRobert Jarzmik #define MT9M111_MAX_WIDTH	1280
149c61e74e3SRobert Jarzmik 
150c61e74e3SRobert Jarzmik struct mt9m111_context {
151c61e74e3SRobert Jarzmik 	u16 read_mode;
152c61e74e3SRobert Jarzmik 	u16 blanking_h;
153c61e74e3SRobert Jarzmik 	u16 blanking_v;
154c61e74e3SRobert Jarzmik 	u16 reducer_xzoom;
155c61e74e3SRobert Jarzmik 	u16 reducer_yzoom;
156c61e74e3SRobert Jarzmik 	u16 reducer_xsize;
157c61e74e3SRobert Jarzmik 	u16 reducer_ysize;
158c61e74e3SRobert Jarzmik 	u16 output_fmt_ctrl2;
159c61e74e3SRobert Jarzmik 	u16 control;
160c61e74e3SRobert Jarzmik };
161c61e74e3SRobert Jarzmik 
162c61e74e3SRobert Jarzmik static struct mt9m111_context context_a = {
163c61e74e3SRobert Jarzmik 	.read_mode		= MT9M111_READ_MODE_A,
164c61e74e3SRobert Jarzmik 	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_A,
165c61e74e3SRobert Jarzmik 	.blanking_v		= MT9M111_VERTICAL_BLANKING_A,
166c61e74e3SRobert Jarzmik 	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_A,
167c61e74e3SRobert Jarzmik 	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_A,
168c61e74e3SRobert Jarzmik 	.reducer_xsize		= MT9M111_REDUCER_XSIZE_A,
169c61e74e3SRobert Jarzmik 	.reducer_ysize		= MT9M111_REDUCER_YSIZE_A,
170c61e74e3SRobert Jarzmik 	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_A,
171c61e74e3SRobert Jarzmik 	.control		= MT9M111_CTXT_CTRL_RESTART,
172c61e74e3SRobert Jarzmik };
173c61e74e3SRobert Jarzmik 
174c61e74e3SRobert Jarzmik static struct mt9m111_context context_b = {
175c61e74e3SRobert Jarzmik 	.read_mode		= MT9M111_READ_MODE_B,
176c61e74e3SRobert Jarzmik 	.blanking_h		= MT9M111_HORIZONTAL_BLANKING_B,
177c61e74e3SRobert Jarzmik 	.blanking_v		= MT9M111_VERTICAL_BLANKING_B,
178c61e74e3SRobert Jarzmik 	.reducer_xzoom		= MT9M111_REDUCER_XZOOM_B,
179c61e74e3SRobert Jarzmik 	.reducer_yzoom		= MT9M111_REDUCER_YZOOM_B,
180c61e74e3SRobert Jarzmik 	.reducer_xsize		= MT9M111_REDUCER_XSIZE_B,
181c61e74e3SRobert Jarzmik 	.reducer_ysize		= MT9M111_REDUCER_YSIZE_B,
182c61e74e3SRobert Jarzmik 	.output_fmt_ctrl2	= MT9M111_OUTPUT_FORMAT_CTRL2_B,
183c61e74e3SRobert Jarzmik 	.control		= MT9M111_CTXT_CTRL_RESTART |
184c61e74e3SRobert Jarzmik 		MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
185c61e74e3SRobert Jarzmik 		MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
186c61e74e3SRobert Jarzmik 		MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
187c61e74e3SRobert Jarzmik 		MT9M111_CTXT_CTRL_HBLANK_SEL_B,
188c61e74e3SRobert Jarzmik };
189c61e74e3SRobert Jarzmik 
190c61e74e3SRobert Jarzmik /* MT9M111 has only one fixed colorspace per pixelcode */
191c61e74e3SRobert Jarzmik struct mt9m111_datafmt {
192c61e74e3SRobert Jarzmik 	u32	code;
193c61e74e3SRobert Jarzmik 	enum v4l2_colorspace		colorspace;
194c61e74e3SRobert Jarzmik };
195c61e74e3SRobert Jarzmik 
196c61e74e3SRobert Jarzmik static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
197c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB},
198c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_SRGB},
199c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB},
200c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_SRGB},
201c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
202c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
203c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
204c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
205c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
206c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
207c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
208c61e74e3SRobert Jarzmik 	{MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
209c61e74e3SRobert Jarzmik };
210c61e74e3SRobert Jarzmik 
211937bb425SMichael Grzeschik enum mt9m111_mode_id {
212937bb425SMichael Grzeschik 	MT9M111_MODE_SXGA_8FPS,
213937bb425SMichael Grzeschik 	MT9M111_MODE_SXGA_15FPS,
214937bb425SMichael Grzeschik 	MT9M111_MODE_QSXGA_30FPS,
215937bb425SMichael Grzeschik 	MT9M111_NUM_MODES,
216937bb425SMichael Grzeschik };
217937bb425SMichael Grzeschik 
218937bb425SMichael Grzeschik struct mt9m111_mode_info {
219937bb425SMichael Grzeschik 	unsigned int sensor_w;
220937bb425SMichael Grzeschik 	unsigned int sensor_h;
221937bb425SMichael Grzeschik 	unsigned int max_image_w;
222937bb425SMichael Grzeschik 	unsigned int max_image_h;
223937bb425SMichael Grzeschik 	unsigned int max_fps;
224937bb425SMichael Grzeschik 	unsigned int reg_val;
225937bb425SMichael Grzeschik 	unsigned int reg_mask;
226937bb425SMichael Grzeschik };
227937bb425SMichael Grzeschik 
228c61e74e3SRobert Jarzmik struct mt9m111 {
229c61e74e3SRobert Jarzmik 	struct v4l2_subdev subdev;
230c61e74e3SRobert Jarzmik 	struct v4l2_ctrl_handler hdl;
231c61e74e3SRobert Jarzmik 	struct v4l2_ctrl *gain;
232c61e74e3SRobert Jarzmik 	struct mt9m111_context *ctx;
233c61e74e3SRobert Jarzmik 	struct v4l2_rect rect;	/* cropping rectangle */
234ea6300cdSEzequiel Garcia 	struct clk *clk;
235c61e74e3SRobert Jarzmik 	unsigned int width;	/* output */
236c61e74e3SRobert Jarzmik 	unsigned int height;	/* sizes */
237937bb425SMichael Grzeschik 	struct v4l2_fract frame_interval;
238937bb425SMichael Grzeschik 	const struct mt9m111_mode_info *current_mode;
239c61e74e3SRobert Jarzmik 	struct mutex power_lock; /* lock to protect power_count */
240c61e74e3SRobert Jarzmik 	int power_count;
241c61e74e3SRobert Jarzmik 	const struct mt9m111_datafmt *fmt;
242c61e74e3SRobert Jarzmik 	int lastpage;	/* PageMap cache value */
2433a959dcdSRobert Jarzmik 	struct regulator *regulator;
2447784b1d2SMarco Felsch 	bool is_streaming;
24598480d65SEnrico Scholz 	/* user point of view - 0: falling 1: rising edge */
24698480d65SEnrico Scholz 	unsigned int pclk_sample:1;
24790411ce4SAkinobu Mita #ifdef CONFIG_MEDIA_CONTROLLER
24890411ce4SAkinobu Mita 	struct media_pad pad;
24990411ce4SAkinobu Mita #endif
250c61e74e3SRobert Jarzmik };
251c61e74e3SRobert Jarzmik 
252937bb425SMichael Grzeschik static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = {
253937bb425SMichael Grzeschik 	[MT9M111_MODE_SXGA_8FPS] = {
254937bb425SMichael Grzeschik 		.sensor_w = 1280,
255937bb425SMichael Grzeschik 		.sensor_h = 1024,
256937bb425SMichael Grzeschik 		.max_image_w = 1280,
257937bb425SMichael Grzeschik 		.max_image_h = 1024,
258937bb425SMichael Grzeschik 		.max_fps = 8,
259937bb425SMichael Grzeschik 		.reg_val = MT9M111_RM_LOW_POWER_RD,
260937bb425SMichael Grzeschik 		.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
261937bb425SMichael Grzeschik 	},
262937bb425SMichael Grzeschik 	[MT9M111_MODE_SXGA_15FPS] = {
263937bb425SMichael Grzeschik 		.sensor_w = 1280,
264937bb425SMichael Grzeschik 		.sensor_h = 1024,
265937bb425SMichael Grzeschik 		.max_image_w = 1280,
266937bb425SMichael Grzeschik 		.max_image_h = 1024,
267937bb425SMichael Grzeschik 		.max_fps = 15,
268937bb425SMichael Grzeschik 		.reg_val = MT9M111_RM_FULL_POWER_RD,
269937bb425SMichael Grzeschik 		.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
270937bb425SMichael Grzeschik 	},
271937bb425SMichael Grzeschik 	[MT9M111_MODE_QSXGA_30FPS] = {
272937bb425SMichael Grzeschik 		.sensor_w = 1280,
273937bb425SMichael Grzeschik 		.sensor_h = 1024,
274937bb425SMichael Grzeschik 		.max_image_w = 640,
275937bb425SMichael Grzeschik 		.max_image_h = 512,
276937bb425SMichael Grzeschik 		.max_fps = 30,
277937bb425SMichael Grzeschik 		.reg_val = MT9M111_RM_LOW_POWER_RD | MT9M111_RM_COL_SKIP_2X |
278937bb425SMichael Grzeschik 			   MT9M111_RM_ROW_SKIP_2X,
279937bb425SMichael Grzeschik 		.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
280937bb425SMichael Grzeschik 	},
281937bb425SMichael Grzeschik };
282937bb425SMichael Grzeschik 
283c61e74e3SRobert Jarzmik /* Find a data format by a pixel code */
mt9m111_find_datafmt(struct mt9m111 * mt9m111,u32 code)284c61e74e3SRobert Jarzmik static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
285c61e74e3SRobert Jarzmik 						u32 code)
286c61e74e3SRobert Jarzmik {
287c61e74e3SRobert Jarzmik 	int i;
288c61e74e3SRobert Jarzmik 	for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
289c61e74e3SRobert Jarzmik 		if (mt9m111_colour_fmts[i].code == code)
290c61e74e3SRobert Jarzmik 			return mt9m111_colour_fmts + i;
291c61e74e3SRobert Jarzmik 
292c61e74e3SRobert Jarzmik 	return mt9m111->fmt;
293c61e74e3SRobert Jarzmik }
294c61e74e3SRobert Jarzmik 
to_mt9m111(const struct i2c_client * client)295c61e74e3SRobert Jarzmik static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
296c61e74e3SRobert Jarzmik {
297c61e74e3SRobert Jarzmik 	return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
298c61e74e3SRobert Jarzmik }
299c61e74e3SRobert Jarzmik 
reg_page_map_set(struct i2c_client * client,const u16 reg)300c61e74e3SRobert Jarzmik static int reg_page_map_set(struct i2c_client *client, const u16 reg)
301c61e74e3SRobert Jarzmik {
302c61e74e3SRobert Jarzmik 	int ret;
303c61e74e3SRobert Jarzmik 	u16 page;
304c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = to_mt9m111(client);
305c61e74e3SRobert Jarzmik 
306c61e74e3SRobert Jarzmik 	page = (reg >> 8);
307c61e74e3SRobert Jarzmik 	if (page == mt9m111->lastpage)
308c61e74e3SRobert Jarzmik 		return 0;
309c61e74e3SRobert Jarzmik 	if (page > 2)
310c61e74e3SRobert Jarzmik 		return -EINVAL;
311c61e74e3SRobert Jarzmik 
312c61e74e3SRobert Jarzmik 	ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
313c61e74e3SRobert Jarzmik 	if (!ret)
314c61e74e3SRobert Jarzmik 		mt9m111->lastpage = page;
315c61e74e3SRobert Jarzmik 	return ret;
316c61e74e3SRobert Jarzmik }
317c61e74e3SRobert Jarzmik 
mt9m111_reg_read(struct i2c_client * client,const u16 reg)318c61e74e3SRobert Jarzmik static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
319c61e74e3SRobert Jarzmik {
320c61e74e3SRobert Jarzmik 	int ret;
321c61e74e3SRobert Jarzmik 
322c61e74e3SRobert Jarzmik 	ret = reg_page_map_set(client, reg);
323c61e74e3SRobert Jarzmik 	if (!ret)
324c61e74e3SRobert Jarzmik 		ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
325c61e74e3SRobert Jarzmik 
326c61e74e3SRobert Jarzmik 	dev_dbg(&client->dev, "read  reg.%03x -> %04x\n", reg, ret);
327c61e74e3SRobert Jarzmik 	return ret;
328c61e74e3SRobert Jarzmik }
329c61e74e3SRobert Jarzmik 
mt9m111_reg_write(struct i2c_client * client,const u16 reg,const u16 data)330c61e74e3SRobert Jarzmik static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
331c61e74e3SRobert Jarzmik 			     const u16 data)
332c61e74e3SRobert Jarzmik {
333c61e74e3SRobert Jarzmik 	int ret;
334c61e74e3SRobert Jarzmik 
335c61e74e3SRobert Jarzmik 	ret = reg_page_map_set(client, reg);
336c61e74e3SRobert Jarzmik 	if (!ret)
337c61e74e3SRobert Jarzmik 		ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data);
338c61e74e3SRobert Jarzmik 	dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
339c61e74e3SRobert Jarzmik 	return ret;
340c61e74e3SRobert Jarzmik }
341c61e74e3SRobert Jarzmik 
mt9m111_reg_set(struct i2c_client * client,const u16 reg,const u16 data)342c61e74e3SRobert Jarzmik static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
343c61e74e3SRobert Jarzmik 			   const u16 data)
344c61e74e3SRobert Jarzmik {
345c61e74e3SRobert Jarzmik 	int ret;
346c61e74e3SRobert Jarzmik 
347c61e74e3SRobert Jarzmik 	ret = mt9m111_reg_read(client, reg);
348c61e74e3SRobert Jarzmik 	if (ret >= 0)
349c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, reg, ret | data);
350c61e74e3SRobert Jarzmik 	return ret;
351c61e74e3SRobert Jarzmik }
352c61e74e3SRobert Jarzmik 
mt9m111_reg_clear(struct i2c_client * client,const u16 reg,const u16 data)353c61e74e3SRobert Jarzmik static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
354c61e74e3SRobert Jarzmik 			     const u16 data)
355c61e74e3SRobert Jarzmik {
356c61e74e3SRobert Jarzmik 	int ret;
357c61e74e3SRobert Jarzmik 
358c61e74e3SRobert Jarzmik 	ret = mt9m111_reg_read(client, reg);
359c61e74e3SRobert Jarzmik 	if (ret >= 0)
360c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, reg, ret & ~data);
361c61e74e3SRobert Jarzmik 	return ret;
362c61e74e3SRobert Jarzmik }
363c61e74e3SRobert Jarzmik 
mt9m111_reg_mask(struct i2c_client * client,const u16 reg,const u16 data,const u16 mask)364c61e74e3SRobert Jarzmik static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
365c61e74e3SRobert Jarzmik 			    const u16 data, const u16 mask)
366c61e74e3SRobert Jarzmik {
367c61e74e3SRobert Jarzmik 	int ret;
368c61e74e3SRobert Jarzmik 
369c61e74e3SRobert Jarzmik 	ret = mt9m111_reg_read(client, reg);
370c61e74e3SRobert Jarzmik 	if (ret >= 0)
371c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
372c61e74e3SRobert Jarzmik 	return ret;
373c61e74e3SRobert Jarzmik }
374c61e74e3SRobert Jarzmik 
mt9m111_set_context(struct mt9m111 * mt9m111,struct mt9m111_context * ctx)375c61e74e3SRobert Jarzmik static int mt9m111_set_context(struct mt9m111 *mt9m111,
376c61e74e3SRobert Jarzmik 			       struct mt9m111_context *ctx)
377c61e74e3SRobert Jarzmik {
378c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
379c61e74e3SRobert Jarzmik 	return reg_write(CONTEXT_CONTROL, ctx->control);
380c61e74e3SRobert Jarzmik }
381c61e74e3SRobert Jarzmik 
mt9m111_setup_rect_ctx(struct mt9m111 * mt9m111,struct mt9m111_context * ctx,struct v4l2_rect * rect,unsigned int width,unsigned int height)382c61e74e3SRobert Jarzmik static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
383c61e74e3SRobert Jarzmik 			struct mt9m111_context *ctx, struct v4l2_rect *rect,
384c61e74e3SRobert Jarzmik 			unsigned int width, unsigned int height)
385c61e74e3SRobert Jarzmik {
386c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
387c61e74e3SRobert Jarzmik 	int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
388c61e74e3SRobert Jarzmik 	if (!ret)
389c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
390c61e74e3SRobert Jarzmik 	if (!ret)
391c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
392c61e74e3SRobert Jarzmik 	if (!ret)
393c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
394c61e74e3SRobert Jarzmik 	return ret;
395c61e74e3SRobert Jarzmik }
396c61e74e3SRobert Jarzmik 
mt9m111_setup_geometry(struct mt9m111 * mt9m111,struct v4l2_rect * rect,int width,int height,u32 code)397c61e74e3SRobert Jarzmik static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
398c61e74e3SRobert Jarzmik 			int width, int height, u32 code)
399c61e74e3SRobert Jarzmik {
400c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
401c61e74e3SRobert Jarzmik 	int ret;
402c61e74e3SRobert Jarzmik 
403c61e74e3SRobert Jarzmik 	ret = reg_write(COLUMN_START, rect->left);
404c61e74e3SRobert Jarzmik 	if (!ret)
405c61e74e3SRobert Jarzmik 		ret = reg_write(ROW_START, rect->top);
406c61e74e3SRobert Jarzmik 
407c61e74e3SRobert Jarzmik 	if (!ret)
408c61e74e3SRobert Jarzmik 		ret = reg_write(WINDOW_WIDTH, rect->width);
409c61e74e3SRobert Jarzmik 	if (!ret)
410c61e74e3SRobert Jarzmik 		ret = reg_write(WINDOW_HEIGHT, rect->height);
411c61e74e3SRobert Jarzmik 
412c61e74e3SRobert Jarzmik 	if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
413c61e74e3SRobert Jarzmik 		/* IFP in use, down-scaling possible */
414c61e74e3SRobert Jarzmik 		if (!ret)
415c61e74e3SRobert Jarzmik 			ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
416c61e74e3SRobert Jarzmik 						     rect, width, height);
417c61e74e3SRobert Jarzmik 		if (!ret)
418c61e74e3SRobert Jarzmik 			ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
419c61e74e3SRobert Jarzmik 						     rect, width, height);
420c61e74e3SRobert Jarzmik 	}
421c61e74e3SRobert Jarzmik 
422c61e74e3SRobert Jarzmik 	dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
423c61e74e3SRobert Jarzmik 		__func__, code, rect->width, rect->height, rect->left, rect->top,
424c61e74e3SRobert Jarzmik 		width, height, ret);
425c61e74e3SRobert Jarzmik 
426c61e74e3SRobert Jarzmik 	return ret;
427c61e74e3SRobert Jarzmik }
428c61e74e3SRobert Jarzmik 
mt9m111_enable(struct mt9m111 * mt9m111)429c61e74e3SRobert Jarzmik static int mt9m111_enable(struct mt9m111 *mt9m111)
430c61e74e3SRobert Jarzmik {
431c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
432c61e74e3SRobert Jarzmik 	return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
433c61e74e3SRobert Jarzmik }
434c61e74e3SRobert Jarzmik 
mt9m111_reset(struct mt9m111 * mt9m111)435c61e74e3SRobert Jarzmik static int mt9m111_reset(struct mt9m111 *mt9m111)
436c61e74e3SRobert Jarzmik {
437c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
438c61e74e3SRobert Jarzmik 	int ret;
439c61e74e3SRobert Jarzmik 
440c61e74e3SRobert Jarzmik 	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
441c61e74e3SRobert Jarzmik 	if (!ret)
442c61e74e3SRobert Jarzmik 		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
443c61e74e3SRobert Jarzmik 	if (!ret)
444c61e74e3SRobert Jarzmik 		ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
445c61e74e3SRobert Jarzmik 				| MT9M111_RESET_RESET_SOC);
446c61e74e3SRobert Jarzmik 
447c61e74e3SRobert Jarzmik 	return ret;
448c61e74e3SRobert Jarzmik }
449c61e74e3SRobert Jarzmik 
mt9m111_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)450c61e74e3SRobert Jarzmik static int mt9m111_set_selection(struct v4l2_subdev *sd,
4510d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
452c61e74e3SRobert Jarzmik 				 struct v4l2_subdev_selection *sel)
453c61e74e3SRobert Jarzmik {
454c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(sd);
455c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = to_mt9m111(client);
456c61e74e3SRobert Jarzmik 	struct v4l2_rect rect = sel->r;
457c61e74e3SRobert Jarzmik 	int width, height;
458c61e74e3SRobert Jarzmik 	int ret, align = 0;
459c61e74e3SRobert Jarzmik 
460c61e74e3SRobert Jarzmik 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
461c61e74e3SRobert Jarzmik 	    sel->target != V4L2_SEL_TGT_CROP)
462c61e74e3SRobert Jarzmik 		return -EINVAL;
463c61e74e3SRobert Jarzmik 
464c61e74e3SRobert Jarzmik 	if (mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
465c61e74e3SRobert Jarzmik 	    mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
466c61e74e3SRobert Jarzmik 		/* Bayer format - even size lengths */
467c61e74e3SRobert Jarzmik 		align = 1;
468c61e74e3SRobert Jarzmik 		/* Let the user play with the starting pixel */
469c61e74e3SRobert Jarzmik 	}
470c61e74e3SRobert Jarzmik 
471c61e74e3SRobert Jarzmik 	/* FIXME: the datasheet doesn't specify minimum sizes */
472c61e74e3SRobert Jarzmik 	v4l_bound_align_image(&rect.width, 2, MT9M111_MAX_WIDTH, align,
473c61e74e3SRobert Jarzmik 			      &rect.height, 2, MT9M111_MAX_HEIGHT, align, 0);
474c61e74e3SRobert Jarzmik 	rect.left = clamp(rect.left, MT9M111_MIN_DARK_COLS,
475c61e74e3SRobert Jarzmik 			  MT9M111_MIN_DARK_COLS + MT9M111_MAX_WIDTH -
476c61e74e3SRobert Jarzmik 			  (__s32)rect.width);
477c61e74e3SRobert Jarzmik 	rect.top = clamp(rect.top, MT9M111_MIN_DARK_ROWS,
478c61e74e3SRobert Jarzmik 			 MT9M111_MIN_DARK_ROWS + MT9M111_MAX_HEIGHT -
479c61e74e3SRobert Jarzmik 			 (__s32)rect.height);
480c61e74e3SRobert Jarzmik 
481c61e74e3SRobert Jarzmik 	width = min(mt9m111->width, rect.width);
482c61e74e3SRobert Jarzmik 	height = min(mt9m111->height, rect.height);
483c61e74e3SRobert Jarzmik 
484c61e74e3SRobert Jarzmik 	ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
485c61e74e3SRobert Jarzmik 	if (!ret) {
486c61e74e3SRobert Jarzmik 		mt9m111->rect = rect;
487c61e74e3SRobert Jarzmik 		mt9m111->width = width;
488c61e74e3SRobert Jarzmik 		mt9m111->height = height;
489c61e74e3SRobert Jarzmik 	}
490c61e74e3SRobert Jarzmik 
491c61e74e3SRobert Jarzmik 	return ret;
492c61e74e3SRobert Jarzmik }
493c61e74e3SRobert Jarzmik 
mt9m111_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)494c61e74e3SRobert Jarzmik static int mt9m111_get_selection(struct v4l2_subdev *sd,
4950d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
496c61e74e3SRobert Jarzmik 				 struct v4l2_subdev_selection *sel)
497c61e74e3SRobert Jarzmik {
498c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(sd);
499c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = to_mt9m111(client);
500c61e74e3SRobert Jarzmik 
501c61e74e3SRobert Jarzmik 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
502c61e74e3SRobert Jarzmik 		return -EINVAL;
503c61e74e3SRobert Jarzmik 
504c61e74e3SRobert Jarzmik 	switch (sel->target) {
505c61e74e3SRobert Jarzmik 	case V4L2_SEL_TGT_CROP_BOUNDS:
506c61e74e3SRobert Jarzmik 		sel->r.left = MT9M111_MIN_DARK_COLS;
507c61e74e3SRobert Jarzmik 		sel->r.top = MT9M111_MIN_DARK_ROWS;
508c61e74e3SRobert Jarzmik 		sel->r.width = MT9M111_MAX_WIDTH;
509c61e74e3SRobert Jarzmik 		sel->r.height = MT9M111_MAX_HEIGHT;
510c61e74e3SRobert Jarzmik 		return 0;
511c61e74e3SRobert Jarzmik 	case V4L2_SEL_TGT_CROP:
512c61e74e3SRobert Jarzmik 		sel->r = mt9m111->rect;
513c61e74e3SRobert Jarzmik 		return 0;
514c61e74e3SRobert Jarzmik 	default:
515c61e74e3SRobert Jarzmik 		return -EINVAL;
516c61e74e3SRobert Jarzmik 	}
517c61e74e3SRobert Jarzmik }
518c61e74e3SRobert Jarzmik 
mt9m111_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)519c61e74e3SRobert Jarzmik static int mt9m111_get_fmt(struct v4l2_subdev *sd,
5200d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
521c61e74e3SRobert Jarzmik 		struct v4l2_subdev_format *format)
522c61e74e3SRobert Jarzmik {
523c61e74e3SRobert Jarzmik 	struct v4l2_mbus_framefmt *mf = &format->format;
524c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
525c61e74e3SRobert Jarzmik 
526c61e74e3SRobert Jarzmik 	if (format->pad)
527c61e74e3SRobert Jarzmik 		return -EINVAL;
528c61e74e3SRobert Jarzmik 
52949410d3aSAkinobu Mita 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
53049410d3aSAkinobu Mita #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
5310d346d2aSTomi Valkeinen 		mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
53249410d3aSAkinobu Mita 		format->format = *mf;
53349410d3aSAkinobu Mita 		return 0;
53449410d3aSAkinobu Mita #else
5352dbcb6fbSHans Verkuil 		return -EINVAL;
53649410d3aSAkinobu Mita #endif
53749410d3aSAkinobu Mita 	}
53849410d3aSAkinobu Mita 
539c61e74e3SRobert Jarzmik 	mf->width	= mt9m111->width;
540c61e74e3SRobert Jarzmik 	mf->height	= mt9m111->height;
541c61e74e3SRobert Jarzmik 	mf->code	= mt9m111->fmt->code;
542c61e74e3SRobert Jarzmik 	mf->colorspace	= mt9m111->fmt->colorspace;
543c61e74e3SRobert Jarzmik 	mf->field	= V4L2_FIELD_NONE;
5442e1566abSAkinobu Mita 	mf->ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT;
5452e1566abSAkinobu Mita 	mf->quantization	= V4L2_QUANTIZATION_DEFAULT;
5462e1566abSAkinobu Mita 	mf->xfer_func	= V4L2_XFER_FUNC_DEFAULT;
547c61e74e3SRobert Jarzmik 
548c61e74e3SRobert Jarzmik 	return 0;
549c61e74e3SRobert Jarzmik }
550c61e74e3SRobert Jarzmik 
mt9m111_set_pixfmt(struct mt9m111 * mt9m111,u32 code)551c61e74e3SRobert Jarzmik static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
552c61e74e3SRobert Jarzmik 			      u32 code)
553c61e74e3SRobert Jarzmik {
554c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
555c61e74e3SRobert Jarzmik 	u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
556c61e74e3SRobert Jarzmik 		MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
557c61e74e3SRobert Jarzmik 		MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
558c61e74e3SRobert Jarzmik 		MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
559c61e74e3SRobert Jarzmik 		MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
560c61e74e3SRobert Jarzmik 		MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
561c61e74e3SRobert Jarzmik 	int ret;
562c61e74e3SRobert Jarzmik 
563c61e74e3SRobert Jarzmik 	switch (code) {
564c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_SBGGR8_1X8:
565c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
566c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_RGB;
567c61e74e3SRobert Jarzmik 		break;
568c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
569c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
570c61e74e3SRobert Jarzmik 		break;
571c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
572c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
573c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
574c61e74e3SRobert Jarzmik 		break;
575c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
576c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
577c61e74e3SRobert Jarzmik 		break;
578c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
579c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
580c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
581c61e74e3SRobert Jarzmik 		break;
582c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
583c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
584c61e74e3SRobert Jarzmik 		break;
585c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_BGR565_2X8_BE:
586c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
587c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
588c61e74e3SRobert Jarzmik 		break;
589c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_BGR565_2X8_LE:
590c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
591c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
592c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
593c61e74e3SRobert Jarzmik 		break;
594c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_UYVY8_2X8:
595c61e74e3SRobert Jarzmik 		data_outfmt2 = 0;
596c61e74e3SRobert Jarzmik 		break;
597c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_VYUY8_2X8:
598c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
599c61e74e3SRobert Jarzmik 		break;
600c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_YUYV8_2X8:
601c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
602c61e74e3SRobert Jarzmik 		break;
603c61e74e3SRobert Jarzmik 	case MEDIA_BUS_FMT_YVYU8_2X8:
604c61e74e3SRobert Jarzmik 		data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
605c61e74e3SRobert Jarzmik 			MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
606c61e74e3SRobert Jarzmik 		break;
607c61e74e3SRobert Jarzmik 	default:
608c61e74e3SRobert Jarzmik 		dev_err(&client->dev, "Pixel format not handled: %x\n", code);
609c61e74e3SRobert Jarzmik 		return -EINVAL;
610c61e74e3SRobert Jarzmik 	}
611c61e74e3SRobert Jarzmik 
61298480d65SEnrico Scholz 	/* receiver samples on falling edge, chip-hw default is rising */
61398480d65SEnrico Scholz 	if (mt9m111->pclk_sample == 0)
61498480d65SEnrico Scholz 		mask_outfmt2 |= MT9M111_OUTFMT_INV_PIX_CLOCK;
61598480d65SEnrico Scholz 
616c61e74e3SRobert Jarzmik 	ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
617c61e74e3SRobert Jarzmik 			       data_outfmt2, mask_outfmt2);
618c61e74e3SRobert Jarzmik 	if (!ret)
619c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
620c61e74e3SRobert Jarzmik 				       data_outfmt2, mask_outfmt2);
621c61e74e3SRobert Jarzmik 
622c61e74e3SRobert Jarzmik 	return ret;
623c61e74e3SRobert Jarzmik }
624c61e74e3SRobert Jarzmik 
mt9m111_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)625c61e74e3SRobert Jarzmik static int mt9m111_set_fmt(struct v4l2_subdev *sd,
6260d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
627c61e74e3SRobert Jarzmik 		struct v4l2_subdev_format *format)
628c61e74e3SRobert Jarzmik {
629c61e74e3SRobert Jarzmik 	struct v4l2_mbus_framefmt *mf = &format->format;
630c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(sd);
631c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
632c61e74e3SRobert Jarzmik 	const struct mt9m111_datafmt *fmt;
633c61e74e3SRobert Jarzmik 	struct v4l2_rect *rect = &mt9m111->rect;
634c61e74e3SRobert Jarzmik 	bool bayer;
635c61e74e3SRobert Jarzmik 	int ret;
636c61e74e3SRobert Jarzmik 
6373c437901SMichael Grzeschik 	if (mt9m111->is_streaming)
6383c437901SMichael Grzeschik 		return -EBUSY;
6393c437901SMichael Grzeschik 
640c61e74e3SRobert Jarzmik 	if (format->pad)
641c61e74e3SRobert Jarzmik 		return -EINVAL;
642c61e74e3SRobert Jarzmik 
643c61e74e3SRobert Jarzmik 	fmt = mt9m111_find_datafmt(mt9m111, mf->code);
644c61e74e3SRobert Jarzmik 
645c61e74e3SRobert Jarzmik 	bayer = fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
646c61e74e3SRobert Jarzmik 		fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE;
647c61e74e3SRobert Jarzmik 
648c61e74e3SRobert Jarzmik 	/*
649c61e74e3SRobert Jarzmik 	 * With Bayer format enforce even side lengths, but let the user play
650c61e74e3SRobert Jarzmik 	 * with the starting pixel
651c61e74e3SRobert Jarzmik 	 */
652c61e74e3SRobert Jarzmik 	if (bayer) {
653c61e74e3SRobert Jarzmik 		rect->width = ALIGN(rect->width, 2);
654c61e74e3SRobert Jarzmik 		rect->height = ALIGN(rect->height, 2);
655c61e74e3SRobert Jarzmik 	}
656c61e74e3SRobert Jarzmik 
657c61e74e3SRobert Jarzmik 	if (fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
658c61e74e3SRobert Jarzmik 		/* IFP bypass mode, no scaling */
659c61e74e3SRobert Jarzmik 		mf->width = rect->width;
660c61e74e3SRobert Jarzmik 		mf->height = rect->height;
661c61e74e3SRobert Jarzmik 	} else {
662c61e74e3SRobert Jarzmik 		/* No upscaling */
663c61e74e3SRobert Jarzmik 		if (mf->width > rect->width)
664c61e74e3SRobert Jarzmik 			mf->width = rect->width;
665c61e74e3SRobert Jarzmik 		if (mf->height > rect->height)
666c61e74e3SRobert Jarzmik 			mf->height = rect->height;
667c61e74e3SRobert Jarzmik 	}
668c61e74e3SRobert Jarzmik 
669c61e74e3SRobert Jarzmik 	dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
670c61e74e3SRobert Jarzmik 		mf->width, mf->height, fmt->code);
671c61e74e3SRobert Jarzmik 
672c61e74e3SRobert Jarzmik 	mf->code = fmt->code;
673c61e74e3SRobert Jarzmik 	mf->colorspace = fmt->colorspace;
6742e1566abSAkinobu Mita 	mf->field	= V4L2_FIELD_NONE;
6752e1566abSAkinobu Mita 	mf->ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT;
6762e1566abSAkinobu Mita 	mf->quantization	= V4L2_QUANTIZATION_DEFAULT;
6772e1566abSAkinobu Mita 	mf->xfer_func	= V4L2_XFER_FUNC_DEFAULT;
678c61e74e3SRobert Jarzmik 
679c61e74e3SRobert Jarzmik 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
6800d346d2aSTomi Valkeinen 		sd_state->pads->try_fmt = *mf;
681c61e74e3SRobert Jarzmik 		return 0;
682c61e74e3SRobert Jarzmik 	}
683c61e74e3SRobert Jarzmik 
684c61e74e3SRobert Jarzmik 	ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
685c61e74e3SRobert Jarzmik 	if (!ret)
686c61e74e3SRobert Jarzmik 		ret = mt9m111_set_pixfmt(mt9m111, mf->code);
687c61e74e3SRobert Jarzmik 	if (!ret) {
688c61e74e3SRobert Jarzmik 		mt9m111->width	= mf->width;
689c61e74e3SRobert Jarzmik 		mt9m111->height	= mf->height;
690c61e74e3SRobert Jarzmik 		mt9m111->fmt	= fmt;
691c61e74e3SRobert Jarzmik 	}
692c61e74e3SRobert Jarzmik 
693c61e74e3SRobert Jarzmik 	return ret;
694c61e74e3SRobert Jarzmik }
695c61e74e3SRobert Jarzmik 
696937bb425SMichael Grzeschik static const struct mt9m111_mode_info *
mt9m111_find_mode(struct mt9m111 * mt9m111,unsigned int req_fps,unsigned int width,unsigned int height)697937bb425SMichael Grzeschik mt9m111_find_mode(struct mt9m111 *mt9m111, unsigned int req_fps,
698937bb425SMichael Grzeschik 		  unsigned int width, unsigned int height)
699937bb425SMichael Grzeschik {
700937bb425SMichael Grzeschik 	const struct mt9m111_mode_info *mode;
701937bb425SMichael Grzeschik 	struct v4l2_rect *sensor_rect = &mt9m111->rect;
702937bb425SMichael Grzeschik 	unsigned int gap, gap_best = (unsigned int) -1;
703937bb425SMichael Grzeschik 	int i, best_gap_idx = MT9M111_MODE_SXGA_15FPS;
704937bb425SMichael Grzeschik 	bool skip_30fps = false;
705937bb425SMichael Grzeschik 
706937bb425SMichael Grzeschik 	/*
707937bb425SMichael Grzeschik 	 * The fps selection is based on the row, column skipping mechanism.
708937bb425SMichael Grzeschik 	 * So ensure that the sensor window is set to default else the fps
709937bb425SMichael Grzeschik 	 * aren't calculated correctly within the sensor hw.
710937bb425SMichael Grzeschik 	 */
711937bb425SMichael Grzeschik 	if (sensor_rect->width != MT9M111_MAX_WIDTH ||
712937bb425SMichael Grzeschik 	    sensor_rect->height != MT9M111_MAX_HEIGHT) {
713937bb425SMichael Grzeschik 		dev_info(mt9m111->subdev.dev,
714937bb425SMichael Grzeschik 			 "Framerate selection is not supported for cropped "
715937bb425SMichael Grzeschik 			 "images\n");
716937bb425SMichael Grzeschik 		return NULL;
717937bb425SMichael Grzeschik 	}
718937bb425SMichael Grzeschik 
719937bb425SMichael Grzeschik 	/* 30fps only supported for images not exceeding 640x512 */
720937bb425SMichael Grzeschik 	if (width > MT9M111_MAX_WIDTH / 2 || height > MT9M111_MAX_HEIGHT / 2) {
721937bb425SMichael Grzeschik 		dev_dbg(mt9m111->subdev.dev,
722937bb425SMichael Grzeschik 			"Framerates > 15fps are supported only for images "
723937bb425SMichael Grzeschik 			"not exceeding 640x512\n");
724937bb425SMichael Grzeschik 		skip_30fps = true;
725937bb425SMichael Grzeschik 	}
726937bb425SMichael Grzeschik 
727937bb425SMichael Grzeschik 	/* find best matched fps */
728937bb425SMichael Grzeschik 	for (i = 0; i < MT9M111_NUM_MODES; i++) {
729937bb425SMichael Grzeschik 		unsigned int fps = mt9m111_mode_data[i].max_fps;
730937bb425SMichael Grzeschik 
731937bb425SMichael Grzeschik 		if (fps == 30 && skip_30fps)
732937bb425SMichael Grzeschik 			continue;
733937bb425SMichael Grzeschik 
734937bb425SMichael Grzeschik 		gap = abs(fps - req_fps);
735937bb425SMichael Grzeschik 		if (gap < gap_best) {
736937bb425SMichael Grzeschik 			best_gap_idx = i;
737937bb425SMichael Grzeschik 			gap_best = gap;
738937bb425SMichael Grzeschik 		}
739937bb425SMichael Grzeschik 	}
740937bb425SMichael Grzeschik 
741937bb425SMichael Grzeschik 	/*
742937bb425SMichael Grzeschik 	 * Use context a/b default timing values instead of calculate blanking
743937bb425SMichael Grzeschik 	 * timing values.
744937bb425SMichael Grzeschik 	 */
745937bb425SMichael Grzeschik 	mode = &mt9m111_mode_data[best_gap_idx];
746937bb425SMichael Grzeschik 	mt9m111->ctx = (best_gap_idx == MT9M111_MODE_QSXGA_30FPS) ? &context_a :
747937bb425SMichael Grzeschik 								    &context_b;
748937bb425SMichael Grzeschik 	return mode;
749937bb425SMichael Grzeschik }
750937bb425SMichael Grzeschik 
751c61e74e3SRobert Jarzmik #ifdef CONFIG_VIDEO_ADV_DEBUG
mt9m111_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)752c61e74e3SRobert Jarzmik static int mt9m111_g_register(struct v4l2_subdev *sd,
753c61e74e3SRobert Jarzmik 			      struct v4l2_dbg_register *reg)
754c61e74e3SRobert Jarzmik {
755c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(sd);
756c61e74e3SRobert Jarzmik 	int val;
757c61e74e3SRobert Jarzmik 
758c61e74e3SRobert Jarzmik 	if (reg->reg > 0x2ff)
759c61e74e3SRobert Jarzmik 		return -EINVAL;
760c61e74e3SRobert Jarzmik 
761c61e74e3SRobert Jarzmik 	val = mt9m111_reg_read(client, reg->reg);
762c61e74e3SRobert Jarzmik 	reg->size = 2;
763c61e74e3SRobert Jarzmik 	reg->val = (u64)val;
764c61e74e3SRobert Jarzmik 
765c61e74e3SRobert Jarzmik 	if (reg->val > 0xffff)
766c61e74e3SRobert Jarzmik 		return -EIO;
767c61e74e3SRobert Jarzmik 
768c61e74e3SRobert Jarzmik 	return 0;
769c61e74e3SRobert Jarzmik }
770c61e74e3SRobert Jarzmik 
mt9m111_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)771c61e74e3SRobert Jarzmik static int mt9m111_s_register(struct v4l2_subdev *sd,
772c61e74e3SRobert Jarzmik 			      const struct v4l2_dbg_register *reg)
773c61e74e3SRobert Jarzmik {
774c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(sd);
775c61e74e3SRobert Jarzmik 
776c61e74e3SRobert Jarzmik 	if (reg->reg > 0x2ff)
777c61e74e3SRobert Jarzmik 		return -EINVAL;
778c61e74e3SRobert Jarzmik 
779c61e74e3SRobert Jarzmik 	if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
780c61e74e3SRobert Jarzmik 		return -EIO;
781c61e74e3SRobert Jarzmik 
782c61e74e3SRobert Jarzmik 	return 0;
783c61e74e3SRobert Jarzmik }
784c61e74e3SRobert Jarzmik #endif
785c61e74e3SRobert Jarzmik 
mt9m111_set_flip(struct mt9m111 * mt9m111,int flip,int mask)786c61e74e3SRobert Jarzmik static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
787c61e74e3SRobert Jarzmik {
788c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
789c61e74e3SRobert Jarzmik 	int ret;
790c61e74e3SRobert Jarzmik 
791c61e74e3SRobert Jarzmik 	if (flip)
792c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
793c61e74e3SRobert Jarzmik 	else
794c61e74e3SRobert Jarzmik 		ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
795c61e74e3SRobert Jarzmik 
796c61e74e3SRobert Jarzmik 	return ret;
797c61e74e3SRobert Jarzmik }
798c61e74e3SRobert Jarzmik 
mt9m111_get_global_gain(struct mt9m111 * mt9m111)799c61e74e3SRobert Jarzmik static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
800c61e74e3SRobert Jarzmik {
801c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
802c61e74e3SRobert Jarzmik 	int data;
803c61e74e3SRobert Jarzmik 
804c61e74e3SRobert Jarzmik 	data = reg_read(GLOBAL_GAIN);
805c61e74e3SRobert Jarzmik 	if (data >= 0)
806c61e74e3SRobert Jarzmik 		return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
807c61e74e3SRobert Jarzmik 			(1 << ((data >> 9) & 1));
808c61e74e3SRobert Jarzmik 	return data;
809c61e74e3SRobert Jarzmik }
810c61e74e3SRobert Jarzmik 
mt9m111_set_global_gain(struct mt9m111 * mt9m111,int gain)811c61e74e3SRobert Jarzmik static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
812c61e74e3SRobert Jarzmik {
813c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
814c61e74e3SRobert Jarzmik 	u16 val;
815c61e74e3SRobert Jarzmik 
816c61e74e3SRobert Jarzmik 	if (gain > 63 * 2 * 2)
817c61e74e3SRobert Jarzmik 		return -EINVAL;
818c61e74e3SRobert Jarzmik 
819c61e74e3SRobert Jarzmik 	if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
820c61e74e3SRobert Jarzmik 		val = (1 << 10) | (1 << 9) | (gain / 4);
821c61e74e3SRobert Jarzmik 	else if ((gain >= 64) && (gain < 64 * 2))
822c61e74e3SRobert Jarzmik 		val = (1 << 9) | (gain / 2);
823c61e74e3SRobert Jarzmik 	else
824c61e74e3SRobert Jarzmik 		val = gain;
825c61e74e3SRobert Jarzmik 
826c61e74e3SRobert Jarzmik 	return reg_write(GLOBAL_GAIN, val);
827c61e74e3SRobert Jarzmik }
828c61e74e3SRobert Jarzmik 
mt9m111_set_autoexposure(struct mt9m111 * mt9m111,int val)829c61e74e3SRobert Jarzmik static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int val)
830c61e74e3SRobert Jarzmik {
831c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
832c61e74e3SRobert Jarzmik 
833c61e74e3SRobert Jarzmik 	if (val == V4L2_EXPOSURE_AUTO)
834c61e74e3SRobert Jarzmik 		return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
835c61e74e3SRobert Jarzmik 	return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
836c61e74e3SRobert Jarzmik }
837c61e74e3SRobert Jarzmik 
mt9m111_set_autowhitebalance(struct mt9m111 * mt9m111,int on)838c61e74e3SRobert Jarzmik static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
839c61e74e3SRobert Jarzmik {
840c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
841c61e74e3SRobert Jarzmik 
842c61e74e3SRobert Jarzmik 	if (on)
843c61e74e3SRobert Jarzmik 		return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
844c61e74e3SRobert Jarzmik 	return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
845c61e74e3SRobert Jarzmik }
846c61e74e3SRobert Jarzmik 
84774e08739SAkinobu Mita static const char * const mt9m111_test_pattern_menu[] = {
84874e08739SAkinobu Mita 	"Disabled",
84974e08739SAkinobu Mita 	"Vertical monochrome gradient",
85074e08739SAkinobu Mita 	"Flat color type 1",
85174e08739SAkinobu Mita 	"Flat color type 2",
85274e08739SAkinobu Mita 	"Flat color type 3",
85374e08739SAkinobu Mita 	"Flat color type 4",
85474e08739SAkinobu Mita 	"Flat color type 5",
85574e08739SAkinobu Mita 	"Color bar",
85674e08739SAkinobu Mita };
85774e08739SAkinobu Mita 
mt9m111_set_test_pattern(struct mt9m111 * mt9m111,int val)85874e08739SAkinobu Mita static int mt9m111_set_test_pattern(struct mt9m111 *mt9m111, int val)
85974e08739SAkinobu Mita {
86074e08739SAkinobu Mita 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
86174e08739SAkinobu Mita 
86274e08739SAkinobu Mita 	return mt9m111_reg_mask(client, MT9M111_TPG_CTRL, val,
86374e08739SAkinobu Mita 				MT9M111_TPG_SEL_MASK);
86474e08739SAkinobu Mita }
86574e08739SAkinobu Mita 
mt9m111_set_colorfx(struct mt9m111 * mt9m111,int val)866dde64f72SAkinobu Mita static int mt9m111_set_colorfx(struct mt9m111 *mt9m111, int val)
867dde64f72SAkinobu Mita {
868dde64f72SAkinobu Mita 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
869dde64f72SAkinobu Mita 	static const struct v4l2_control colorfx[] = {
870dde64f72SAkinobu Mita 		{ V4L2_COLORFX_NONE,		0 },
871dde64f72SAkinobu Mita 		{ V4L2_COLORFX_BW,		1 },
872dde64f72SAkinobu Mita 		{ V4L2_COLORFX_SEPIA,		2 },
873dde64f72SAkinobu Mita 		{ V4L2_COLORFX_NEGATIVE,	3 },
874dde64f72SAkinobu Mita 		{ V4L2_COLORFX_SOLARIZATION,	4 },
875dde64f72SAkinobu Mita 	};
876dde64f72SAkinobu Mita 	int i;
877dde64f72SAkinobu Mita 
878dde64f72SAkinobu Mita 	for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
879dde64f72SAkinobu Mita 		if (colorfx[i].id == val) {
880dde64f72SAkinobu Mita 			return mt9m111_reg_mask(client, MT9M111_EFFECTS_MODE,
881dde64f72SAkinobu Mita 						colorfx[i].value,
882dde64f72SAkinobu Mita 						MT9M111_EFFECTS_MODE_MASK);
883dde64f72SAkinobu Mita 		}
884dde64f72SAkinobu Mita 	}
885dde64f72SAkinobu Mita 
886dde64f72SAkinobu Mita 	return -EINVAL;
887dde64f72SAkinobu Mita }
888dde64f72SAkinobu Mita 
mt9m111_s_ctrl(struct v4l2_ctrl * ctrl)889c61e74e3SRobert Jarzmik static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
890c61e74e3SRobert Jarzmik {
891c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = container_of(ctrl->handler,
892c61e74e3SRobert Jarzmik 					       struct mt9m111, hdl);
893c61e74e3SRobert Jarzmik 
894c61e74e3SRobert Jarzmik 	switch (ctrl->id) {
895c61e74e3SRobert Jarzmik 	case V4L2_CID_VFLIP:
896c61e74e3SRobert Jarzmik 		return mt9m111_set_flip(mt9m111, ctrl->val,
897c61e74e3SRobert Jarzmik 					MT9M111_RMB_MIRROR_ROWS);
898c61e74e3SRobert Jarzmik 	case V4L2_CID_HFLIP:
899c61e74e3SRobert Jarzmik 		return mt9m111_set_flip(mt9m111, ctrl->val,
900c61e74e3SRobert Jarzmik 					MT9M111_RMB_MIRROR_COLS);
901c61e74e3SRobert Jarzmik 	case V4L2_CID_GAIN:
902c61e74e3SRobert Jarzmik 		return mt9m111_set_global_gain(mt9m111, ctrl->val);
903c61e74e3SRobert Jarzmik 	case V4L2_CID_EXPOSURE_AUTO:
904c61e74e3SRobert Jarzmik 		return mt9m111_set_autoexposure(mt9m111, ctrl->val);
905c61e74e3SRobert Jarzmik 	case V4L2_CID_AUTO_WHITE_BALANCE:
906c61e74e3SRobert Jarzmik 		return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
90774e08739SAkinobu Mita 	case V4L2_CID_TEST_PATTERN:
90874e08739SAkinobu Mita 		return mt9m111_set_test_pattern(mt9m111, ctrl->val);
909dde64f72SAkinobu Mita 	case V4L2_CID_COLORFX:
910dde64f72SAkinobu Mita 		return mt9m111_set_colorfx(mt9m111, ctrl->val);
911c61e74e3SRobert Jarzmik 	}
912c61e74e3SRobert Jarzmik 
913c61e74e3SRobert Jarzmik 	return -EINVAL;
914c61e74e3SRobert Jarzmik }
915c61e74e3SRobert Jarzmik 
mt9m111_suspend(struct mt9m111 * mt9m111)916c61e74e3SRobert Jarzmik static int mt9m111_suspend(struct mt9m111 *mt9m111)
917c61e74e3SRobert Jarzmik {
918c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
919c61e74e3SRobert Jarzmik 	int ret;
920c61e74e3SRobert Jarzmik 
921c61e74e3SRobert Jarzmik 	v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
922c61e74e3SRobert Jarzmik 
923c61e74e3SRobert Jarzmik 	ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
924c61e74e3SRobert Jarzmik 	if (!ret)
925c61e74e3SRobert Jarzmik 		ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
926c61e74e3SRobert Jarzmik 			      MT9M111_RESET_OUTPUT_DISABLE |
927c61e74e3SRobert Jarzmik 			      MT9M111_RESET_ANALOG_STANDBY);
928c61e74e3SRobert Jarzmik 	if (!ret)
929c61e74e3SRobert Jarzmik 		ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
930c61e74e3SRobert Jarzmik 
931c61e74e3SRobert Jarzmik 	return ret;
932c61e74e3SRobert Jarzmik }
933c61e74e3SRobert Jarzmik 
mt9m111_restore_state(struct mt9m111 * mt9m111)934c61e74e3SRobert Jarzmik static void mt9m111_restore_state(struct mt9m111 *mt9m111)
935c61e74e3SRobert Jarzmik {
936937bb425SMichael Grzeschik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
937937bb425SMichael Grzeschik 
938c61e74e3SRobert Jarzmik 	mt9m111_set_context(mt9m111, mt9m111->ctx);
939c61e74e3SRobert Jarzmik 	mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
940c61e74e3SRobert Jarzmik 	mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
941c61e74e3SRobert Jarzmik 			mt9m111->width, mt9m111->height, mt9m111->fmt->code);
942c61e74e3SRobert Jarzmik 	v4l2_ctrl_handler_setup(&mt9m111->hdl);
943937bb425SMichael Grzeschik 	mt9m111_reg_mask(client, mt9m111->ctx->read_mode,
944937bb425SMichael Grzeschik 			 mt9m111->current_mode->reg_val,
945937bb425SMichael Grzeschik 			 mt9m111->current_mode->reg_mask);
946c61e74e3SRobert Jarzmik }
947c61e74e3SRobert Jarzmik 
mt9m111_resume(struct mt9m111 * mt9m111)948c61e74e3SRobert Jarzmik static int mt9m111_resume(struct mt9m111 *mt9m111)
949c61e74e3SRobert Jarzmik {
950c61e74e3SRobert Jarzmik 	int ret = mt9m111_enable(mt9m111);
951c61e74e3SRobert Jarzmik 	if (!ret)
952c61e74e3SRobert Jarzmik 		ret = mt9m111_reset(mt9m111);
953c61e74e3SRobert Jarzmik 	if (!ret)
954c61e74e3SRobert Jarzmik 		mt9m111_restore_state(mt9m111);
955c61e74e3SRobert Jarzmik 
956c61e74e3SRobert Jarzmik 	return ret;
957c61e74e3SRobert Jarzmik }
958c61e74e3SRobert Jarzmik 
mt9m111_init(struct mt9m111 * mt9m111)959c61e74e3SRobert Jarzmik static int mt9m111_init(struct mt9m111 *mt9m111)
960c61e74e3SRobert Jarzmik {
961c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
962c61e74e3SRobert Jarzmik 	int ret;
963c61e74e3SRobert Jarzmik 
964c61e74e3SRobert Jarzmik 	ret = mt9m111_enable(mt9m111);
965c61e74e3SRobert Jarzmik 	if (!ret)
966c61e74e3SRobert Jarzmik 		ret = mt9m111_reset(mt9m111);
967c61e74e3SRobert Jarzmik 	if (!ret)
968c61e74e3SRobert Jarzmik 		ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
969c61e74e3SRobert Jarzmik 	if (ret)
970c61e74e3SRobert Jarzmik 		dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
971c61e74e3SRobert Jarzmik 	return ret;
972c61e74e3SRobert Jarzmik }
973c61e74e3SRobert Jarzmik 
mt9m111_power_on(struct mt9m111 * mt9m111)974c61e74e3SRobert Jarzmik static int mt9m111_power_on(struct mt9m111 *mt9m111)
975c61e74e3SRobert Jarzmik {
976c61e74e3SRobert Jarzmik 	struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
977c61e74e3SRobert Jarzmik 	int ret;
978c61e74e3SRobert Jarzmik 
979ea6300cdSEzequiel Garcia 	ret = clk_prepare_enable(mt9m111->clk);
980c61e74e3SRobert Jarzmik 	if (ret < 0)
981c61e74e3SRobert Jarzmik 		return ret;
982c61e74e3SRobert Jarzmik 
9833a959dcdSRobert Jarzmik 	ret = regulator_enable(mt9m111->regulator);
9843a959dcdSRobert Jarzmik 	if (ret < 0)
98504bc4f66SSakari Ailus 		goto out_clk_disable;
9863a959dcdSRobert Jarzmik 
987c61e74e3SRobert Jarzmik 	ret = mt9m111_resume(mt9m111);
98804bc4f66SSakari Ailus 	if (ret < 0)
98904bc4f66SSakari Ailus 		goto out_regulator_disable;
99004bc4f66SSakari Ailus 
99104bc4f66SSakari Ailus 	return 0;
99204bc4f66SSakari Ailus 
99304bc4f66SSakari Ailus out_regulator_disable:
99404bc4f66SSakari Ailus 	regulator_disable(mt9m111->regulator);
99504bc4f66SSakari Ailus 
99604bc4f66SSakari Ailus out_clk_disable:
997ea6300cdSEzequiel Garcia 	clk_disable_unprepare(mt9m111->clk);
99804bc4f66SSakari Ailus 
99904bc4f66SSakari Ailus 	dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
1000c61e74e3SRobert Jarzmik 
1001c61e74e3SRobert Jarzmik 	return ret;
1002c61e74e3SRobert Jarzmik }
1003c61e74e3SRobert Jarzmik 
mt9m111_power_off(struct mt9m111 * mt9m111)1004c61e74e3SRobert Jarzmik static void mt9m111_power_off(struct mt9m111 *mt9m111)
1005c61e74e3SRobert Jarzmik {
1006c61e74e3SRobert Jarzmik 	mt9m111_suspend(mt9m111);
10073a959dcdSRobert Jarzmik 	regulator_disable(mt9m111->regulator);
1008ea6300cdSEzequiel Garcia 	clk_disable_unprepare(mt9m111->clk);
1009c61e74e3SRobert Jarzmik }
1010c61e74e3SRobert Jarzmik 
mt9m111_s_power(struct v4l2_subdev * sd,int on)1011c61e74e3SRobert Jarzmik static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
1012c61e74e3SRobert Jarzmik {
1013c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1014c61e74e3SRobert Jarzmik 	int ret = 0;
1015c61e74e3SRobert Jarzmik 
1016c61e74e3SRobert Jarzmik 	mutex_lock(&mt9m111->power_lock);
1017c61e74e3SRobert Jarzmik 
1018c61e74e3SRobert Jarzmik 	/*
1019c61e74e3SRobert Jarzmik 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
1020c61e74e3SRobert Jarzmik 	 * update the power state.
1021c61e74e3SRobert Jarzmik 	 */
1022c61e74e3SRobert Jarzmik 	if (mt9m111->power_count == !on) {
1023c61e74e3SRobert Jarzmik 		if (on)
1024c61e74e3SRobert Jarzmik 			ret = mt9m111_power_on(mt9m111);
1025c61e74e3SRobert Jarzmik 		else
1026c61e74e3SRobert Jarzmik 			mt9m111_power_off(mt9m111);
1027c61e74e3SRobert Jarzmik 	}
1028c61e74e3SRobert Jarzmik 
1029c61e74e3SRobert Jarzmik 	if (!ret) {
1030c61e74e3SRobert Jarzmik 		/* Update the power count. */
1031c61e74e3SRobert Jarzmik 		mt9m111->power_count += on ? 1 : -1;
1032c61e74e3SRobert Jarzmik 		WARN_ON(mt9m111->power_count < 0);
1033c61e74e3SRobert Jarzmik 	}
1034c61e74e3SRobert Jarzmik 
1035c61e74e3SRobert Jarzmik 	mutex_unlock(&mt9m111->power_lock);
1036c61e74e3SRobert Jarzmik 	return ret;
1037c61e74e3SRobert Jarzmik }
1038c61e74e3SRobert Jarzmik 
1039c61e74e3SRobert Jarzmik static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
1040c61e74e3SRobert Jarzmik 	.s_ctrl = mt9m111_s_ctrl,
1041c61e74e3SRobert Jarzmik };
1042c61e74e3SRobert Jarzmik 
104339229620SJulia Lawall static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
1044c61e74e3SRobert Jarzmik 	.s_power	= mt9m111_s_power,
1045329d9e35SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
1046329d9e35SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1047329d9e35SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1048c61e74e3SRobert Jarzmik #ifdef CONFIG_VIDEO_ADV_DEBUG
1049c61e74e3SRobert Jarzmik 	.g_register	= mt9m111_g_register,
1050c61e74e3SRobert Jarzmik 	.s_register	= mt9m111_s_register,
1051c61e74e3SRobert Jarzmik #endif
1052c61e74e3SRobert Jarzmik };
1053c61e74e3SRobert Jarzmik 
mt9m111_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)1054937bb425SMichael Grzeschik static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
1055937bb425SMichael Grzeschik 				   struct v4l2_subdev_frame_interval *fi)
1056937bb425SMichael Grzeschik {
1057937bb425SMichael Grzeschik 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1058937bb425SMichael Grzeschik 
1059937bb425SMichael Grzeschik 	fi->interval = mt9m111->frame_interval;
1060937bb425SMichael Grzeschik 
1061937bb425SMichael Grzeschik 	return 0;
1062937bb425SMichael Grzeschik }
1063937bb425SMichael Grzeschik 
mt9m111_s_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)1064937bb425SMichael Grzeschik static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
1065937bb425SMichael Grzeschik 				   struct v4l2_subdev_frame_interval *fi)
1066937bb425SMichael Grzeschik {
1067937bb425SMichael Grzeschik 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1068937bb425SMichael Grzeschik 	const struct mt9m111_mode_info *mode;
1069937bb425SMichael Grzeschik 	struct v4l2_fract *fract = &fi->interval;
1070937bb425SMichael Grzeschik 	int fps;
1071937bb425SMichael Grzeschik 
1072937bb425SMichael Grzeschik 	if (mt9m111->is_streaming)
1073937bb425SMichael Grzeschik 		return -EBUSY;
1074937bb425SMichael Grzeschik 
1075937bb425SMichael Grzeschik 	if (fi->pad != 0)
1076937bb425SMichael Grzeschik 		return -EINVAL;
1077937bb425SMichael Grzeschik 
1078937bb425SMichael Grzeschik 	if (fract->numerator == 0) {
1079937bb425SMichael Grzeschik 		fract->denominator = 30;
1080937bb425SMichael Grzeschik 		fract->numerator = 1;
1081937bb425SMichael Grzeschik 	}
1082937bb425SMichael Grzeschik 
1083937bb425SMichael Grzeschik 	fps = DIV_ROUND_CLOSEST(fract->denominator, fract->numerator);
1084937bb425SMichael Grzeschik 
1085937bb425SMichael Grzeschik 	/* Find best fitting mode. Do not update the mode if no one was found. */
1086937bb425SMichael Grzeschik 	mode = mt9m111_find_mode(mt9m111, fps, mt9m111->width, mt9m111->height);
1087937bb425SMichael Grzeschik 	if (!mode)
1088937bb425SMichael Grzeschik 		return 0;
1089937bb425SMichael Grzeschik 
1090937bb425SMichael Grzeschik 	if (mode->max_fps != fps) {
1091937bb425SMichael Grzeschik 		fract->denominator = mode->max_fps;
1092937bb425SMichael Grzeschik 		fract->numerator = 1;
1093937bb425SMichael Grzeschik 	}
1094937bb425SMichael Grzeschik 
1095937bb425SMichael Grzeschik 	mt9m111->current_mode = mode;
1096937bb425SMichael Grzeschik 	mt9m111->frame_interval = fi->interval;
1097937bb425SMichael Grzeschik 
1098937bb425SMichael Grzeschik 	return 0;
1099937bb425SMichael Grzeschik }
1100937bb425SMichael Grzeschik 
mt9m111_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1101c61e74e3SRobert Jarzmik static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
11020d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
1103c61e74e3SRobert Jarzmik 		struct v4l2_subdev_mbus_code_enum *code)
1104c61e74e3SRobert Jarzmik {
1105c61e74e3SRobert Jarzmik 	if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts))
1106c61e74e3SRobert Jarzmik 		return -EINVAL;
1107c61e74e3SRobert Jarzmik 
1108c61e74e3SRobert Jarzmik 	code->code = mt9m111_colour_fmts[code->index].code;
1109c61e74e3SRobert Jarzmik 	return 0;
1110c61e74e3SRobert Jarzmik }
1111c61e74e3SRobert Jarzmik 
mt9m111_s_stream(struct v4l2_subdev * sd,int enable)11127784b1d2SMarco Felsch static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
11137784b1d2SMarco Felsch {
11147784b1d2SMarco Felsch 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
11157784b1d2SMarco Felsch 
11167784b1d2SMarco Felsch 	mt9m111->is_streaming = !!enable;
11177784b1d2SMarco Felsch 	return 0;
11187784b1d2SMarco Felsch }
11197784b1d2SMarco Felsch 
mt9m111_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)112049410d3aSAkinobu Mita static int mt9m111_init_cfg(struct v4l2_subdev *sd,
11210d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state)
112249410d3aSAkinobu Mita {
112349410d3aSAkinobu Mita #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
112449410d3aSAkinobu Mita 	struct v4l2_mbus_framefmt *format =
11250d346d2aSTomi Valkeinen 		v4l2_subdev_get_try_format(sd, sd_state, 0);
112649410d3aSAkinobu Mita 
112749410d3aSAkinobu Mita 	format->width	= MT9M111_MAX_WIDTH;
112849410d3aSAkinobu Mita 	format->height	= MT9M111_MAX_HEIGHT;
112949410d3aSAkinobu Mita 	format->code	= mt9m111_colour_fmts[0].code;
113049410d3aSAkinobu Mita 	format->colorspace	= mt9m111_colour_fmts[0].colorspace;
113149410d3aSAkinobu Mita 	format->field	= V4L2_FIELD_NONE;
113249410d3aSAkinobu Mita 	format->ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT;
113349410d3aSAkinobu Mita 	format->quantization	= V4L2_QUANTIZATION_DEFAULT;
113449410d3aSAkinobu Mita 	format->xfer_func	= V4L2_XFER_FUNC_DEFAULT;
113549410d3aSAkinobu Mita #endif
113649410d3aSAkinobu Mita 	return 0;
113749410d3aSAkinobu Mita }
113849410d3aSAkinobu Mita 
mt9m111_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)11390c3da525SJacopo Mondi static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
11400c3da525SJacopo Mondi 				   unsigned int pad,
1141c61e74e3SRobert Jarzmik 				   struct v4l2_mbus_config *cfg)
1142c61e74e3SRobert Jarzmik {
114398480d65SEnrico Scholz 	struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
114498480d65SEnrico Scholz 
11456a7bdd89SLaurent Pinchart 	cfg->type = V4L2_MBUS_PARALLEL;
11466a7bdd89SLaurent Pinchart 
11476a7bdd89SLaurent Pinchart 	cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
11486a7bdd89SLaurent Pinchart 				  V4L2_MBUS_HSYNC_ACTIVE_HIGH |
11496a7bdd89SLaurent Pinchart 				  V4L2_MBUS_VSYNC_ACTIVE_HIGH |
1150c61e74e3SRobert Jarzmik 				  V4L2_MBUS_DATA_ACTIVE_HIGH;
115198480d65SEnrico Scholz 
11526a7bdd89SLaurent Pinchart 	cfg->bus.parallel.flags |= mt9m111->pclk_sample ?
11536a7bdd89SLaurent Pinchart 				   V4L2_MBUS_PCLK_SAMPLE_RISING :
115498480d65SEnrico Scholz 				   V4L2_MBUS_PCLK_SAMPLE_FALLING;
115598480d65SEnrico Scholz 
1156c61e74e3SRobert Jarzmik 	return 0;
1157c61e74e3SRobert Jarzmik }
1158c61e74e3SRobert Jarzmik 
115939229620SJulia Lawall static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
11607784b1d2SMarco Felsch 	.s_stream	= mt9m111_s_stream,
1161937bb425SMichael Grzeschik 	.g_frame_interval = mt9m111_g_frame_interval,
1162937bb425SMichael Grzeschik 	.s_frame_interval = mt9m111_s_frame_interval,
1163c61e74e3SRobert Jarzmik };
1164c61e74e3SRobert Jarzmik 
1165c61e74e3SRobert Jarzmik static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
116649410d3aSAkinobu Mita 	.init_cfg	= mt9m111_init_cfg,
1167c61e74e3SRobert Jarzmik 	.enum_mbus_code = mt9m111_enum_mbus_code,
1168c61e74e3SRobert Jarzmik 	.get_selection	= mt9m111_get_selection,
1169c61e74e3SRobert Jarzmik 	.set_selection	= mt9m111_set_selection,
1170c61e74e3SRobert Jarzmik 	.get_fmt	= mt9m111_get_fmt,
1171c61e74e3SRobert Jarzmik 	.set_fmt	= mt9m111_set_fmt,
11720c3da525SJacopo Mondi 	.get_mbus_config = mt9m111_get_mbus_config,
1173c61e74e3SRobert Jarzmik };
1174c61e74e3SRobert Jarzmik 
117539229620SJulia Lawall static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
1176c61e74e3SRobert Jarzmik 	.core	= &mt9m111_subdev_core_ops,
1177c61e74e3SRobert Jarzmik 	.video	= &mt9m111_subdev_video_ops,
1178c61e74e3SRobert Jarzmik 	.pad	= &mt9m111_subdev_pad_ops,
1179c61e74e3SRobert Jarzmik };
1180c61e74e3SRobert Jarzmik 
1181c61e74e3SRobert Jarzmik /*
1182c61e74e3SRobert Jarzmik  * Interface active, can use i2c. If it fails, it can indeed mean, that
1183c61e74e3SRobert Jarzmik  * this wasn't our capture interface, so, we wait for the right one
1184c61e74e3SRobert Jarzmik  */
mt9m111_video_probe(struct i2c_client * client)1185c61e74e3SRobert Jarzmik static int mt9m111_video_probe(struct i2c_client *client)
1186c61e74e3SRobert Jarzmik {
1187c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = to_mt9m111(client);
1188c61e74e3SRobert Jarzmik 	s32 data;
1189c61e74e3SRobert Jarzmik 	int ret;
1190c61e74e3SRobert Jarzmik 
1191c61e74e3SRobert Jarzmik 	ret = mt9m111_s_power(&mt9m111->subdev, 1);
1192c61e74e3SRobert Jarzmik 	if (ret < 0)
1193c61e74e3SRobert Jarzmik 		return ret;
1194c61e74e3SRobert Jarzmik 
1195c61e74e3SRobert Jarzmik 	data = reg_read(CHIP_VERSION);
1196c61e74e3SRobert Jarzmik 
1197c61e74e3SRobert Jarzmik 	switch (data) {
1198c61e74e3SRobert Jarzmik 	case 0x143a: /* MT9M111 or MT9M131 */
1199c61e74e3SRobert Jarzmik 		dev_info(&client->dev,
1200c61e74e3SRobert Jarzmik 			"Detected a MT9M111/MT9M131 chip ID %x\n", data);
1201c61e74e3SRobert Jarzmik 		break;
1202c61e74e3SRobert Jarzmik 	case 0x148c: /* MT9M112 */
1203c61e74e3SRobert Jarzmik 		dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
1204c61e74e3SRobert Jarzmik 		break;
1205c61e74e3SRobert Jarzmik 	default:
1206c61e74e3SRobert Jarzmik 		dev_err(&client->dev,
1207c61e74e3SRobert Jarzmik 			"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
1208c61e74e3SRobert Jarzmik 			data);
1209c61e74e3SRobert Jarzmik 		ret = -ENODEV;
1210c61e74e3SRobert Jarzmik 		goto done;
1211c61e74e3SRobert Jarzmik 	}
1212c61e74e3SRobert Jarzmik 
1213c61e74e3SRobert Jarzmik 	ret = mt9m111_init(mt9m111);
1214c61e74e3SRobert Jarzmik 	if (ret)
1215c61e74e3SRobert Jarzmik 		goto done;
1216c61e74e3SRobert Jarzmik 
1217c61e74e3SRobert Jarzmik 	ret = v4l2_ctrl_handler_setup(&mt9m111->hdl);
1218c61e74e3SRobert Jarzmik 
1219c61e74e3SRobert Jarzmik done:
1220c61e74e3SRobert Jarzmik 	mt9m111_s_power(&mt9m111->subdev, 0);
1221c61e74e3SRobert Jarzmik 	return ret;
1222c61e74e3SRobert Jarzmik }
1223c61e74e3SRobert Jarzmik 
mt9m111_probe_fw(struct i2c_client * client,struct mt9m111 * mt9m111)122498480d65SEnrico Scholz static int mt9m111_probe_fw(struct i2c_client *client, struct mt9m111 *mt9m111)
122598480d65SEnrico Scholz {
122698480d65SEnrico Scholz 	struct v4l2_fwnode_endpoint bus_cfg = {
122798480d65SEnrico Scholz 		.bus_type = V4L2_MBUS_PARALLEL
122898480d65SEnrico Scholz 	};
122998480d65SEnrico Scholz 	struct fwnode_handle *np;
123098480d65SEnrico Scholz 	int ret;
123198480d65SEnrico Scholz 
123298480d65SEnrico Scholz 	np = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
123398480d65SEnrico Scholz 	if (!np)
123498480d65SEnrico Scholz 		return -EINVAL;
123598480d65SEnrico Scholz 
123698480d65SEnrico Scholz 	ret = v4l2_fwnode_endpoint_parse(np, &bus_cfg);
123798480d65SEnrico Scholz 	if (ret)
123898480d65SEnrico Scholz 		goto out_put_fw;
123998480d65SEnrico Scholz 
124098480d65SEnrico Scholz 	mt9m111->pclk_sample = !!(bus_cfg.bus.parallel.flags &
124198480d65SEnrico Scholz 				  V4L2_MBUS_PCLK_SAMPLE_RISING);
124298480d65SEnrico Scholz 
124398480d65SEnrico Scholz out_put_fw:
124498480d65SEnrico Scholz 	fwnode_handle_put(np);
124598480d65SEnrico Scholz 	return ret;
124698480d65SEnrico Scholz }
124798480d65SEnrico Scholz 
mt9m111_probe(struct i2c_client * client)1248e6714993SKieran Bingham static int mt9m111_probe(struct i2c_client *client)
1249c61e74e3SRobert Jarzmik {
1250c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111;
125154ed1c18SWolfram Sang 	struct i2c_adapter *adapter = client->adapter;
1252c61e74e3SRobert Jarzmik 	int ret;
1253c61e74e3SRobert Jarzmik 
1254c61e74e3SRobert Jarzmik 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
1255c61e74e3SRobert Jarzmik 		dev_warn(&adapter->dev,
1256c61e74e3SRobert Jarzmik 			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
1257c61e74e3SRobert Jarzmik 		return -EIO;
1258c61e74e3SRobert Jarzmik 	}
1259c61e74e3SRobert Jarzmik 
1260c61e74e3SRobert Jarzmik 	mt9m111 = devm_kzalloc(&client->dev, sizeof(struct mt9m111), GFP_KERNEL);
1261c61e74e3SRobert Jarzmik 	if (!mt9m111)
1262c61e74e3SRobert Jarzmik 		return -ENOMEM;
1263c61e74e3SRobert Jarzmik 
12648d4e29a5SRobert Jarzmik 	if (dev_fwnode(&client->dev)) {
126598480d65SEnrico Scholz 		ret = mt9m111_probe_fw(client, mt9m111);
126698480d65SEnrico Scholz 		if (ret)
126798480d65SEnrico Scholz 			return ret;
12688d4e29a5SRobert Jarzmik 	}
126998480d65SEnrico Scholz 
1270ea6300cdSEzequiel Garcia 	mt9m111->clk = devm_clk_get(&client->dev, "mclk");
1271c61e74e3SRobert Jarzmik 	if (IS_ERR(mt9m111->clk))
1272bddb4b53SFabio Estevam 		return PTR_ERR(mt9m111->clk);
1273c61e74e3SRobert Jarzmik 
12743a959dcdSRobert Jarzmik 	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
12753a959dcdSRobert Jarzmik 	if (IS_ERR(mt9m111->regulator)) {
12763a959dcdSRobert Jarzmik 		dev_err(&client->dev, "regulator not found: %ld\n",
12773a959dcdSRobert Jarzmik 			PTR_ERR(mt9m111->regulator));
12783a959dcdSRobert Jarzmik 		return PTR_ERR(mt9m111->regulator);
12793a959dcdSRobert Jarzmik 	}
12803a959dcdSRobert Jarzmik 
1281c61e74e3SRobert Jarzmik 	/* Default HIGHPOWER context */
1282c61e74e3SRobert Jarzmik 	mt9m111->ctx = &context_b;
1283c61e74e3SRobert Jarzmik 
1284c61e74e3SRobert Jarzmik 	v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
1285329d9e35SAkinobu Mita 	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
1286329d9e35SAkinobu Mita 				 V4L2_SUBDEV_FL_HAS_EVENTS;
12875ed8c224SAkinobu Mita 
1288dde64f72SAkinobu Mita 	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
1289c61e74e3SRobert Jarzmik 	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1290c61e74e3SRobert Jarzmik 			V4L2_CID_VFLIP, 0, 1, 1, 0);
1291c61e74e3SRobert Jarzmik 	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1292c61e74e3SRobert Jarzmik 			V4L2_CID_HFLIP, 0, 1, 1, 0);
1293c61e74e3SRobert Jarzmik 	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1294c61e74e3SRobert Jarzmik 			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
1295c61e74e3SRobert Jarzmik 	mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1296c61e74e3SRobert Jarzmik 			V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
1297c61e74e3SRobert Jarzmik 	v4l2_ctrl_new_std_menu(&mt9m111->hdl,
1298c61e74e3SRobert Jarzmik 			&mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
1299c61e74e3SRobert Jarzmik 			V4L2_EXPOSURE_AUTO);
130074e08739SAkinobu Mita 	v4l2_ctrl_new_std_menu_items(&mt9m111->hdl,
130174e08739SAkinobu Mita 			&mt9m111_ctrl_ops, V4L2_CID_TEST_PATTERN,
130274e08739SAkinobu Mita 			ARRAY_SIZE(mt9m111_test_pattern_menu) - 1, 0, 0,
130374e08739SAkinobu Mita 			mt9m111_test_pattern_menu);
1304dde64f72SAkinobu Mita 	v4l2_ctrl_new_std_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
1305dde64f72SAkinobu Mita 			V4L2_CID_COLORFX, V4L2_COLORFX_SOLARIZATION,
1306dde64f72SAkinobu Mita 			~(BIT(V4L2_COLORFX_NONE) |
1307dde64f72SAkinobu Mita 				BIT(V4L2_COLORFX_BW) |
1308dde64f72SAkinobu Mita 				BIT(V4L2_COLORFX_SEPIA) |
1309dde64f72SAkinobu Mita 				BIT(V4L2_COLORFX_NEGATIVE) |
1310dde64f72SAkinobu Mita 				BIT(V4L2_COLORFX_SOLARIZATION)),
1311dde64f72SAkinobu Mita 			V4L2_COLORFX_NONE);
1312c61e74e3SRobert Jarzmik 	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
1313c61e74e3SRobert Jarzmik 	if (mt9m111->hdl.error) {
1314c61e74e3SRobert Jarzmik 		ret = mt9m111->hdl.error;
1315ea6300cdSEzequiel Garcia 		return ret;
1316c61e74e3SRobert Jarzmik 	}
1317c61e74e3SRobert Jarzmik 
131890411ce4SAkinobu Mita #ifdef CONFIG_MEDIA_CONTROLLER
131990411ce4SAkinobu Mita 	mt9m111->pad.flags = MEDIA_PAD_FL_SOURCE;
132090411ce4SAkinobu Mita 	mt9m111->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
132190411ce4SAkinobu Mita 	ret = media_entity_pads_init(&mt9m111->subdev.entity, 1, &mt9m111->pad);
132290411ce4SAkinobu Mita 	if (ret < 0)
132390411ce4SAkinobu Mita 		goto out_hdlfree;
132490411ce4SAkinobu Mita #endif
132590411ce4SAkinobu Mita 
1326937bb425SMichael Grzeschik 	mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS];
1327937bb425SMichael Grzeschik 	mt9m111->frame_interval.numerator = 1;
1328937bb425SMichael Grzeschik 	mt9m111->frame_interval.denominator = mt9m111->current_mode->max_fps;
1329937bb425SMichael Grzeschik 
1330c61e74e3SRobert Jarzmik 	/* Second stage probe - when a capture adapter is there */
1331c61e74e3SRobert Jarzmik 	mt9m111->rect.left	= MT9M111_MIN_DARK_COLS;
1332c61e74e3SRobert Jarzmik 	mt9m111->rect.top	= MT9M111_MIN_DARK_ROWS;
1333c61e74e3SRobert Jarzmik 	mt9m111->rect.width	= MT9M111_MAX_WIDTH;
1334c61e74e3SRobert Jarzmik 	mt9m111->rect.height	= MT9M111_MAX_HEIGHT;
133529856308SAkinobu Mita 	mt9m111->width		= mt9m111->rect.width;
133629856308SAkinobu Mita 	mt9m111->height		= mt9m111->rect.height;
1337c61e74e3SRobert Jarzmik 	mt9m111->fmt		= &mt9m111_colour_fmts[0];
1338c61e74e3SRobert Jarzmik 	mt9m111->lastpage	= -1;
1339c61e74e3SRobert Jarzmik 	mutex_init(&mt9m111->power_lock);
1340c61e74e3SRobert Jarzmik 
1341c61e74e3SRobert Jarzmik 	ret = mt9m111_video_probe(client);
1342c61e74e3SRobert Jarzmik 	if (ret < 0)
134390411ce4SAkinobu Mita 		goto out_entityclean;
1344c61e74e3SRobert Jarzmik 
1345c61e74e3SRobert Jarzmik 	mt9m111->subdev.dev = &client->dev;
1346c61e74e3SRobert Jarzmik 	ret = v4l2_async_register_subdev(&mt9m111->subdev);
1347c61e74e3SRobert Jarzmik 	if (ret < 0)
134890411ce4SAkinobu Mita 		goto out_entityclean;
1349c61e74e3SRobert Jarzmik 
1350c61e74e3SRobert Jarzmik 	return 0;
1351c61e74e3SRobert Jarzmik 
135290411ce4SAkinobu Mita out_entityclean:
135390411ce4SAkinobu Mita #ifdef CONFIG_MEDIA_CONTROLLER
135490411ce4SAkinobu Mita 	media_entity_cleanup(&mt9m111->subdev.entity);
1355c61e74e3SRobert Jarzmik out_hdlfree:
135690411ce4SAkinobu Mita #endif
1357c61e74e3SRobert Jarzmik 	v4l2_ctrl_handler_free(&mt9m111->hdl);
1358c61e74e3SRobert Jarzmik 
1359c61e74e3SRobert Jarzmik 	return ret;
1360c61e74e3SRobert Jarzmik }
1361c61e74e3SRobert Jarzmik 
mt9m111_remove(struct i2c_client * client)1362ed5c2f5fSUwe Kleine-König static void mt9m111_remove(struct i2c_client *client)
1363c61e74e3SRobert Jarzmik {
1364c61e74e3SRobert Jarzmik 	struct mt9m111 *mt9m111 = to_mt9m111(client);
1365c61e74e3SRobert Jarzmik 
1366c61e74e3SRobert Jarzmik 	v4l2_async_unregister_subdev(&mt9m111->subdev);
136790411ce4SAkinobu Mita 	media_entity_cleanup(&mt9m111->subdev.entity);
1368c61e74e3SRobert Jarzmik 	v4l2_ctrl_handler_free(&mt9m111->hdl);
1369c61e74e3SRobert Jarzmik }
1370c61e74e3SRobert Jarzmik static const struct of_device_id mt9m111_of_match[] = {
1371c61e74e3SRobert Jarzmik 	{ .compatible = "micron,mt9m111", },
1372c61e74e3SRobert Jarzmik 	{},
1373c61e74e3SRobert Jarzmik };
1374c61e74e3SRobert Jarzmik MODULE_DEVICE_TABLE(of, mt9m111_of_match);
1375c61e74e3SRobert Jarzmik 
1376c61e74e3SRobert Jarzmik static const struct i2c_device_id mt9m111_id[] = {
1377c61e74e3SRobert Jarzmik 	{ "mt9m111", 0 },
1378c61e74e3SRobert Jarzmik 	{ }
1379c61e74e3SRobert Jarzmik };
1380c61e74e3SRobert Jarzmik MODULE_DEVICE_TABLE(i2c, mt9m111_id);
1381c61e74e3SRobert Jarzmik 
1382c61e74e3SRobert Jarzmik static struct i2c_driver mt9m111_i2c_driver = {
1383c61e74e3SRobert Jarzmik 	.driver = {
1384c61e74e3SRobert Jarzmik 		.name = "mt9m111",
1385*d2820ce0SKrzysztof Kozlowski 		.of_match_table = mt9m111_of_match,
1386c61e74e3SRobert Jarzmik 	},
1387aaeb31c0SUwe Kleine-König 	.probe		= mt9m111_probe,
1388c61e74e3SRobert Jarzmik 	.remove		= mt9m111_remove,
1389c61e74e3SRobert Jarzmik 	.id_table	= mt9m111_id,
1390c61e74e3SRobert Jarzmik };
1391c61e74e3SRobert Jarzmik 
1392c61e74e3SRobert Jarzmik module_i2c_driver(mt9m111_i2c_driver);
1393c61e74e3SRobert Jarzmik 
1394c61e74e3SRobert Jarzmik MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
1395c61e74e3SRobert Jarzmik MODULE_AUTHOR("Robert Jarzmik");
1396c61e74e3SRobert Jarzmik MODULE_LICENSE("GPL");
1397