blob: d639b9bcf64a8ced3e0fe19a6f1c49ed70982bb9 [file] [log] [blame]
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001/*
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -03002 * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
Robert Jarzmik77110ab2008-08-14 12:02:51 -03003 *
4 * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/videodev2.h>
11#include <linux/slab.h>
12#include <linux/i2c.h>
13#include <linux/log2.h>
14#include <linux/gpio.h>
15#include <linux/delay.h>
Guennadi Liakhovetski95d20102011-09-09 13:56:04 -030016#include <linux/v4l2-mediabus.h>
Paul Gortmaker7a707b82011-07-03 14:03:12 -040017#include <linux/module.h>
Enrico Scholz98480d62018-11-27 05:02:53 -050018#include <linux/property.h>
Robert Jarzmik77110ab2008-08-14 12:02:51 -030019
Robert Jarzmik5d7cc012016-09-06 06:04:11 -030020#include <media/v4l2-async.h>
Guennadi Liakhovetski9aea4702012-12-21 13:01:55 -030021#include <media/v4l2-clk.h>
Robert Jarzmik77110ab2008-08-14 12:02:51 -030022#include <media/v4l2-common.h>
Hans Verkuilaf8425c2011-09-07 06:56:57 -030023#include <media/v4l2-ctrls.h>
Robert Jarzmik5d7cc012016-09-06 06:04:11 -030024#include <media/v4l2-device.h>
Akinobu Mita329d9e352018-11-12 11:00:48 -050025#include <media/v4l2-event.h>
Enrico Scholz98480d62018-11-27 05:02:53 -050026#include <media/v4l2-fwnode.h>
Robert Jarzmik77110ab2008-08-14 12:02:51 -030027
28/*
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -030029 * MT9M111, MT9M112 and MT9M131:
30 * i2c address is 0x48 or 0x5d (depending on SADDR pin)
Guennadi Liakhovetski25a34812012-12-21 08:11:48 -030031 * The platform has to define struct i2c_board_info objects and link to them
32 * from struct soc_camera_host_desc
Robert Jarzmik77110ab2008-08-14 12:02:51 -030033 */
34
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -030035/*
36 * Sensor core register addresses (0x000..0x0ff)
37 */
Robert Jarzmik77110ab2008-08-14 12:02:51 -030038#define MT9M111_CHIP_VERSION 0x000
39#define MT9M111_ROW_START 0x001
40#define MT9M111_COLUMN_START 0x002
41#define MT9M111_WINDOW_HEIGHT 0x003
42#define MT9M111_WINDOW_WIDTH 0x004
43#define MT9M111_HORIZONTAL_BLANKING_B 0x005
44#define MT9M111_VERTICAL_BLANKING_B 0x006
45#define MT9M111_HORIZONTAL_BLANKING_A 0x007
46#define MT9M111_VERTICAL_BLANKING_A 0x008
47#define MT9M111_SHUTTER_WIDTH 0x009
48#define MT9M111_ROW_SPEED 0x00a
49#define MT9M111_EXTRA_DELAY 0x00b
50#define MT9M111_SHUTTER_DELAY 0x00c
51#define MT9M111_RESET 0x00d
52#define MT9M111_READ_MODE_B 0x020
53#define MT9M111_READ_MODE_A 0x021
54#define MT9M111_FLASH_CONTROL 0x023
55#define MT9M111_GREEN1_GAIN 0x02b
56#define MT9M111_BLUE_GAIN 0x02c
57#define MT9M111_RED_GAIN 0x02d
58#define MT9M111_GREEN2_GAIN 0x02e
59#define MT9M111_GLOBAL_GAIN 0x02f
60#define MT9M111_CONTEXT_CONTROL 0x0c8
61#define MT9M111_PAGE_MAP 0x0f0
62#define MT9M111_BYTE_WISE_ADDR 0x0f1
63
64#define MT9M111_RESET_SYNC_CHANGES (1 << 15)
65#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9)
66#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8)
67#define MT9M111_RESET_RESET_SOC (1 << 5)
68#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4)
69#define MT9M111_RESET_CHIP_ENABLE (1 << 3)
70#define MT9M111_RESET_ANALOG_STANDBY (1 << 2)
71#define MT9M111_RESET_RESTART_FRAME (1 << 1)
72#define MT9M111_RESET_RESET_MODE (1 << 0)
73
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -030074#define MT9M111_RM_FULL_POWER_RD (0 << 10)
75#define MT9M111_RM_LOW_POWER_RD (1 << 10)
76#define MT9M111_RM_COL_SKIP_4X (1 << 5)
77#define MT9M111_RM_ROW_SKIP_4X (1 << 4)
78#define MT9M111_RM_COL_SKIP_2X (1 << 3)
79#define MT9M111_RM_ROW_SKIP_2X (1 << 2)
Robert Jarzmik77110ab2008-08-14 12:02:51 -030080#define MT9M111_RMB_MIRROR_COLS (1 << 1)
81#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
82#define MT9M111_CTXT_CTRL_RESTART (1 << 15)
83#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12)
84#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10)
85#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9)
86#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8)
87#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7)
88#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3)
89#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
90#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
91#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -030092
Robert Jarzmik77110ab2008-08-14 12:02:51 -030093/*
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -030094 * Colorpipe register addresses (0x100..0x1ff)
Robert Jarzmik77110ab2008-08-14 12:02:51 -030095 */
96#define MT9M111_OPER_MODE_CTRL 0x106
97#define MT9M111_OUTPUT_FORMAT_CTRL 0x108
Akinobu Mita74e08732018-01-03 13:22:47 -050098#define MT9M111_TPG_CTRL 0x148
Robert Jarzmik77110ab2008-08-14 12:02:51 -030099#define MT9M111_REDUCER_XZOOM_B 0x1a0
100#define MT9M111_REDUCER_XSIZE_B 0x1a1
101#define MT9M111_REDUCER_YZOOM_B 0x1a3
102#define MT9M111_REDUCER_YSIZE_B 0x1a4
103#define MT9M111_REDUCER_XZOOM_A 0x1a6
104#define MT9M111_REDUCER_XSIZE_A 0x1a7
105#define MT9M111_REDUCER_YZOOM_A 0x1a9
106#define MT9M111_REDUCER_YSIZE_A 0x1aa
Akinobu Mitadde64f72018-11-12 11:00:49 -0500107#define MT9M111_EFFECTS_MODE 0x1e2
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300108
109#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
110#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
111
112#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300113#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300114#define MT9M111_OUTFMT_FLIP_BAYER_COL (1 << 9)
115#define MT9M111_OUTFMT_FLIP_BAYER_ROW (1 << 8)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300116#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
117#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
118#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
119#define MT9M111_OUTFMT_RGB (1 << 8)
Michael Grzeschikec733652010-08-03 07:57:41 -0300120#define MT9M111_OUTFMT_RGB565 (0 << 6)
121#define MT9M111_OUTFMT_RGB555 (1 << 6)
122#define MT9M111_OUTFMT_RGB444x (2 << 6)
123#define MT9M111_OUTFMT_RGBx444 (3 << 6)
124#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4)
125#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4)
126#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4)
127#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300128#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
129#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300130#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
131#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0)
Akinobu Mita74e08732018-01-03 13:22:47 -0500132#define MT9M111_TPG_SEL_MASK GENMASK(2, 0)
Akinobu Mitadde64f72018-11-12 11:00:49 -0500133#define MT9M111_EFFECTS_MODE_MASK GENMASK(2, 0)
Michael Grzeschik937bb422018-11-27 05:02:50 -0500134#define MT9M111_RM_PWR_MASK BIT(10)
135#define MT9M111_RM_SKIP2_MASK GENMASK(3, 2)
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -0300136
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300137/*
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -0300138 * Camera control register addresses (0x200..0x2ff not implemented)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300139 */
140
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300141#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
142#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
143#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
144#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300145#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
146 (val), (mask))
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300147
148#define MT9M111_MIN_DARK_ROWS 8
Michael Grzeschik669470a2010-08-03 07:57:43 -0300149#define MT9M111_MIN_DARK_COLS 26
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300150#define MT9M111_MAX_HEIGHT 1024
151#define MT9M111_MAX_WIDTH 1280
152
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300153struct mt9m111_context {
154 u16 read_mode;
155 u16 blanking_h;
156 u16 blanking_v;
157 u16 reducer_xzoom;
158 u16 reducer_yzoom;
159 u16 reducer_xsize;
160 u16 reducer_ysize;
161 u16 output_fmt_ctrl2;
162 u16 control;
163};
164
165static struct mt9m111_context context_a = {
166 .read_mode = MT9M111_READ_MODE_A,
167 .blanking_h = MT9M111_HORIZONTAL_BLANKING_A,
168 .blanking_v = MT9M111_VERTICAL_BLANKING_A,
169 .reducer_xzoom = MT9M111_REDUCER_XZOOM_A,
170 .reducer_yzoom = MT9M111_REDUCER_YZOOM_A,
171 .reducer_xsize = MT9M111_REDUCER_XSIZE_A,
172 .reducer_ysize = MT9M111_REDUCER_YSIZE_A,
173 .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_A,
174 .control = MT9M111_CTXT_CTRL_RESTART,
175};
176
177static struct mt9m111_context context_b = {
178 .read_mode = MT9M111_READ_MODE_B,
179 .blanking_h = MT9M111_HORIZONTAL_BLANKING_B,
180 .blanking_v = MT9M111_VERTICAL_BLANKING_B,
181 .reducer_xzoom = MT9M111_REDUCER_XZOOM_B,
182 .reducer_yzoom = MT9M111_REDUCER_YZOOM_B,
183 .reducer_xsize = MT9M111_REDUCER_XSIZE_B,
184 .reducer_ysize = MT9M111_REDUCER_YSIZE_B,
185 .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_B,
186 .control = MT9M111_CTXT_CTRL_RESTART |
187 MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
188 MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
189 MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
190 MT9M111_CTXT_CTRL_HBLANK_SEL_B,
191};
192
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300193/* MT9M111 has only one fixed colorspace per pixelcode */
194struct mt9m111_datafmt {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300195 u32 code;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300196 enum v4l2_colorspace colorspace;
197};
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300198
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300199static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
Robert Jarzmik1a412fa2016-09-06 06:04:12 -0300200 {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB},
201 {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_SRGB},
202 {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB},
203 {MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_SRGB},
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300204 {MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
205 {MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
206 {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
207 {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
208 {MEDIA_BUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
209 {MEDIA_BUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
210 {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
211 {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300212};
213
Michael Grzeschik937bb422018-11-27 05:02:50 -0500214enum mt9m111_mode_id {
215 MT9M111_MODE_SXGA_8FPS,
216 MT9M111_MODE_SXGA_15FPS,
217 MT9M111_MODE_QSXGA_30FPS,
218 MT9M111_NUM_MODES,
219};
220
221struct mt9m111_mode_info {
222 unsigned int sensor_w;
223 unsigned int sensor_h;
224 unsigned int max_image_w;
225 unsigned int max_image_h;
226 unsigned int max_fps;
227 unsigned int reg_val;
228 unsigned int reg_mask;
229};
230
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300231struct mt9m111 {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300232 struct v4l2_subdev subdev;
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300233 struct v4l2_ctrl_handler hdl;
234 struct v4l2_ctrl *gain;
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300235 struct mt9m111_context *ctx;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300236 struct v4l2_rect rect; /* cropping rectangle */
Guennadi Liakhovetski9aea4702012-12-21 13:01:55 -0300237 struct v4l2_clk *clk;
Ricardo Ribaldaf90580c2013-11-26 05:31:42 -0300238 unsigned int width; /* output */
239 unsigned int height; /* sizes */
Michael Grzeschik937bb422018-11-27 05:02:50 -0500240 struct v4l2_fract frame_interval;
241 const struct mt9m111_mode_info *current_mode;
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300242 struct mutex power_lock; /* lock to protect power_count */
243 int power_count;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300244 const struct mt9m111_datafmt *fmt;
Michael Grzeschik096b7032011-07-19 09:26:35 -0300245 int lastpage; /* PageMap cache value */
Marco Felsch7784b1d2018-11-27 05:02:48 -0500246 bool is_streaming;
Enrico Scholz98480d62018-11-27 05:02:53 -0500247 /* user point of view - 0: falling 1: rising edge */
248 unsigned int pclk_sample:1;
Akinobu Mita90411ce2018-01-03 13:22:45 -0500249#ifdef CONFIG_MEDIA_CONTROLLER
250 struct media_pad pad;
251#endif
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300252};
253
Michael Grzeschik937bb422018-11-27 05:02:50 -0500254static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = {
255 [MT9M111_MODE_SXGA_8FPS] = {
256 .sensor_w = 1280,
257 .sensor_h = 1024,
258 .max_image_w = 1280,
259 .max_image_h = 1024,
260 .max_fps = 8,
261 .reg_val = MT9M111_RM_LOW_POWER_RD,
262 .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
263 },
264 [MT9M111_MODE_SXGA_15FPS] = {
265 .sensor_w = 1280,
266 .sensor_h = 1024,
267 .max_image_w = 1280,
268 .max_image_h = 1024,
269 .max_fps = 15,
270 .reg_val = MT9M111_RM_FULL_POWER_RD,
271 .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
272 },
273 [MT9M111_MODE_QSXGA_30FPS] = {
274 .sensor_w = 1280,
275 .sensor_h = 1024,
276 .max_image_w = 640,
277 .max_image_h = 512,
278 .max_fps = 30,
279 .reg_val = MT9M111_RM_LOW_POWER_RD | MT9M111_RM_COL_SKIP_2X |
280 MT9M111_RM_ROW_SKIP_2X,
281 .reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
282 },
283};
284
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300285/* Find a data format by a pixel code */
286static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300287 u32 code)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300288{
289 int i;
290 for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
291 if (mt9m111_colour_fmts[i].code == code)
292 return mt9m111_colour_fmts + i;
293
294 return mt9m111->fmt;
295}
296
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300297static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
298{
299 return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
300}
301
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300302static int reg_page_map_set(struct i2c_client *client, const u16 reg)
303{
304 int ret;
305 u16 page;
Michael Grzeschik096b7032011-07-19 09:26:35 -0300306 struct mt9m111 *mt9m111 = to_mt9m111(client);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300307
308 page = (reg >> 8);
Michael Grzeschik096b7032011-07-19 09:26:35 -0300309 if (page == mt9m111->lastpage)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300310 return 0;
311 if (page > 2)
312 return -EINVAL;
313
Jonathan Cameron3f877042011-10-21 09:30:25 -0300314 ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300315 if (!ret)
Michael Grzeschik096b7032011-07-19 09:26:35 -0300316 mt9m111->lastpage = page;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300317 return ret;
318}
319
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300320static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300321{
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300322 int ret;
323
324 ret = reg_page_map_set(client, reg);
325 if (!ret)
Jonathan Cameron3f877042011-10-21 09:30:25 -0300326 ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300327
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300328 dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300329 return ret;
330}
331
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300332static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300333 const u16 data)
334{
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300335 int ret;
336
337 ret = reg_page_map_set(client, reg);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300338 if (!ret)
Jonathan Cameron3f877042011-10-21 09:30:25 -0300339 ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data);
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300340 dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300341 return ret;
342}
343
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300344static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300345 const u16 data)
346{
347 int ret;
348
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300349 ret = mt9m111_reg_read(client, reg);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300350 if (ret >= 0)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300351 ret = mt9m111_reg_write(client, reg, ret | data);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300352 return ret;
353}
354
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300355static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300356 const u16 data)
357{
358 int ret;
359
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300360 ret = mt9m111_reg_read(client, reg);
Michael Grzeschik9c56cbf2011-07-12 12:39:03 -0300361 if (ret >= 0)
362 ret = mt9m111_reg_write(client, reg, ret & ~data);
363 return ret;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300364}
365
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300366static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
367 const u16 data, const u16 mask)
368{
369 int ret;
370
371 ret = mt9m111_reg_read(client, reg);
372 if (ret >= 0)
373 ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
374 return ret;
375}
376
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300377static int mt9m111_set_context(struct mt9m111 *mt9m111,
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300378 struct mt9m111_context *ctx)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300379{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300380 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300381 return reg_write(CONTEXT_CONTROL, ctx->control);
382}
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300383
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300384static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300385 struct mt9m111_context *ctx, struct v4l2_rect *rect,
386 unsigned int width, unsigned int height)
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300387{
388 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300389 int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300390 if (!ret)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300391 ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300392 if (!ret)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300393 ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300394 if (!ret)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300395 ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300396 return ret;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300397}
398
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300399static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300400 int width, int height, u32 code)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300401{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300402 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300403 int ret;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300404
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300405 ret = reg_write(COLUMN_START, rect->left);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300406 if (!ret)
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300407 ret = reg_write(ROW_START, rect->top);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300408
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300409 if (!ret)
410 ret = reg_write(WINDOW_WIDTH, rect->width);
411 if (!ret)
412 ret = reg_write(WINDOW_HEIGHT, rect->height);
413
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300414 if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300415 /* IFP in use, down-scaling possible */
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300416 if (!ret)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300417 ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
418 rect, width, height);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300419 if (!ret)
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300420 ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
421 rect, width, height);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300422 }
423
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300424 dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
425 __func__, code, rect->width, rect->height, rect->left, rect->top,
426 width, height, ret);
427
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300428 return ret;
429}
430
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300431static int mt9m111_enable(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300432{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300433 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Guennadi Liakhovetskia650bf12011-11-03 08:19:18 -0300434 return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300435}
436
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300437static int mt9m111_reset(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300438{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300439 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300440 int ret;
441
442 ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300443 if (!ret)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300444 ret = reg_set(RESET, MT9M111_RESET_RESET_SOC);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300445 if (!ret)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300446 ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
447 | MT9M111_RESET_RESET_SOC);
Antonio Ospiteafb13682009-02-23 12:13:24 -0300448
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300449 return ret;
450}
451
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200452static int mt9m111_set_selection(struct v4l2_subdev *sd,
453 struct v4l2_subdev_pad_config *cfg,
454 struct v4l2_subdev_selection *sel)
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300455{
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200456 struct i2c_client *client = v4l2_get_subdevdata(sd);
457 struct mt9m111 *mt9m111 = to_mt9m111(client);
458 struct v4l2_rect rect = sel->r;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300459 int width, height;
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300460 int ret, align = 0;
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300461
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200462 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
463 sel->target != V4L2_SEL_TGT_CROP)
Michael Grzeschik6b6d33c2010-08-03 07:57:44 -0300464 return -EINVAL;
465
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300466 if (mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
467 mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300468 /* Bayer format - even size lengths */
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300469 align = 1;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300470 /* Let the user play with the starting pixel */
471 }
472
473 /* FIXME: the datasheet doesn't specify minimum sizes */
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300474 v4l_bound_align_image(&rect.width, 2, MT9M111_MAX_WIDTH, align,
475 &rect.height, 2, MT9M111_MAX_HEIGHT, align, 0);
476 rect.left = clamp(rect.left, MT9M111_MIN_DARK_COLS,
477 MT9M111_MIN_DARK_COLS + MT9M111_MAX_WIDTH -
478 (__s32)rect.width);
479 rect.top = clamp(rect.top, MT9M111_MIN_DARK_ROWS,
480 MT9M111_MIN_DARK_ROWS + MT9M111_MAX_HEIGHT -
481 (__s32)rect.height);
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300482
483 width = min(mt9m111->width, rect.width);
484 height = min(mt9m111->height, rect.height);
485
486 ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
487 if (!ret) {
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300488 mt9m111->rect = rect;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300489 mt9m111->width = width;
490 mt9m111->height = height;
491 }
492
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300493 return ret;
494}
495
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200496static int mt9m111_get_selection(struct v4l2_subdev *sd,
497 struct v4l2_subdev_pad_config *cfg,
498 struct v4l2_subdev_selection *sel)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300499{
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200500 struct i2c_client *client = v4l2_get_subdevdata(sd);
501 struct mt9m111 *mt9m111 = to_mt9m111(client);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300502
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200503 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
Michael Grzeschik6b6d33c2010-08-03 07:57:44 -0300504 return -EINVAL;
505
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200506 switch (sel->target) {
507 case V4L2_SEL_TGT_CROP_BOUNDS:
Hans Verkuil10d5509c2015-12-14 08:25:32 -0200508 sel->r.left = MT9M111_MIN_DARK_COLS;
509 sel->r.top = MT9M111_MIN_DARK_ROWS;
510 sel->r.width = MT9M111_MAX_WIDTH;
511 sel->r.height = MT9M111_MAX_HEIGHT;
512 return 0;
513 case V4L2_SEL_TGT_CROP:
514 sel->r = mt9m111->rect;
515 return 0;
516 default:
517 return -EINVAL;
518 }
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300519}
520
Hans Verkuilda298c62015-04-09 04:02:34 -0300521static int mt9m111_get_fmt(struct v4l2_subdev *sd,
522 struct v4l2_subdev_pad_config *cfg,
523 struct v4l2_subdev_format *format)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300524{
Hans Verkuilda298c62015-04-09 04:02:34 -0300525 struct v4l2_mbus_framefmt *mf = &format->format;
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300526 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300527
Hans Verkuilda298c62015-04-09 04:02:34 -0300528 if (format->pad)
529 return -EINVAL;
530
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300531 mf->width = mt9m111->width;
532 mf->height = mt9m111->height;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300533 mf->code = mt9m111->fmt->code;
Michael Grzeschik01f5a392010-08-03 07:57:45 -0300534 mf->colorspace = mt9m111->fmt->colorspace;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300535 mf->field = V4L2_FIELD_NONE;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300536
537 return 0;
538}
539
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300540static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300541 u32 code)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300542{
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300543 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
544 u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
545 MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
546 MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
547 MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
548 MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
549 MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300550 int ret;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300551
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300552 switch (code) {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300553 case MEDIA_BUS_FMT_SBGGR8_1X8:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300554 data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
555 MT9M111_OUTFMT_RGB;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300556 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300557 case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300558 data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300559 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300560 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300561 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
562 MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
563 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300564 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300565 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300566 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300567 case MEDIA_BUS_FMT_RGB565_2X8_LE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300568 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
569 MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
570 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300571 case MEDIA_BUS_FMT_RGB565_2X8_BE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300572 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
573 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300574 case MEDIA_BUS_FMT_BGR565_2X8_BE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300575 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
576 MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
577 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300578 case MEDIA_BUS_FMT_BGR565_2X8_LE:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300579 data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
580 MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
581 MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300582 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300583 case MEDIA_BUS_FMT_UYVY8_2X8:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300584 data_outfmt2 = 0;
Robert Jarzmik88f4b892008-12-17 14:05:31 -0300585 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300586 case MEDIA_BUS_FMT_VYUY8_2X8:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300587 data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
Robert Jarzmik88f4b892008-12-17 14:05:31 -0300588 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300589 case MEDIA_BUS_FMT_YUYV8_2X8:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300590 data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
Robert Jarzmik88f4b892008-12-17 14:05:31 -0300591 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300592 case MEDIA_BUS_FMT_YVYU8_2X8:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300593 data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
594 MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300595 break;
596 default:
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300597 dev_err(&client->dev, "Pixel format not handled: %x\n", code);
598 return -EINVAL;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300599 }
600
Enrico Scholz98480d62018-11-27 05:02:53 -0500601 /* receiver samples on falling edge, chip-hw default is rising */
602 if (mt9m111->pclk_sample == 0)
603 mask_outfmt2 |= MT9M111_OUTFMT_INV_PIX_CLOCK;
604
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300605 ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
606 data_outfmt2, mask_outfmt2);
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300607 if (!ret)
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300608 ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
609 data_outfmt2, mask_outfmt2);
Michael Grzeschik7c58e7d2011-07-12 12:39:05 -0300610
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300611 return ret;
612}
613
Hans Verkuil717fd5b2015-04-09 06:24:36 -0300614static int mt9m111_set_fmt(struct v4l2_subdev *sd,
615 struct v4l2_subdev_pad_config *cfg,
616 struct v4l2_subdev_format *format)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300617{
Hans Verkuil717fd5b2015-04-09 06:24:36 -0300618 struct v4l2_mbus_framefmt *mf = &format->format;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300619 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300620 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300621 const struct mt9m111_datafmt *fmt;
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300622 struct v4l2_rect *rect = &mt9m111->rect;
623 bool bayer;
Hans Verkuil717fd5b2015-04-09 06:24:36 -0300624 int ret;
625
Michael Grzeschik3c4379012018-11-27 05:02:49 -0500626 if (mt9m111->is_streaming)
627 return -EBUSY;
628
Hans Verkuil717fd5b2015-04-09 06:24:36 -0300629 if (format->pad)
630 return -EINVAL;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300631
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300632 fmt = mt9m111_find_datafmt(mt9m111, mf->code);
633
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300634 bayer = fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
635 fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300636
637 /*
638 * With Bayer format enforce even side lengths, but let the user play
639 * with the starting pixel
640 */
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300641 if (bayer) {
642 rect->width = ALIGN(rect->width, 2);
643 rect->height = ALIGN(rect->height, 2);
644 }
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300645
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300646 if (fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300647 /* IFP bypass mode, no scaling */
648 mf->width = rect->width;
649 mf->height = rect->height;
650 } else {
651 /* No upscaling */
652 if (mf->width > rect->width)
653 mf->width = rect->width;
654 if (mf->height > rect->height)
655 mf->height = rect->height;
656 }
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300657
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300658 dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
659 mf->width, mf->height, fmt->code);
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300660
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300661 mf->code = fmt->code;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300662 mf->colorspace = fmt->colorspace;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300663
Hans Verkuil717fd5b2015-04-09 06:24:36 -0300664 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
665 cfg->try_fmt = *mf;
666 return 0;
667 }
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300668
669 ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
670 if (!ret)
671 ret = mt9m111_set_pixfmt(mt9m111, mf->code);
672 if (!ret) {
673 mt9m111->width = mf->width;
674 mt9m111->height = mf->height;
675 mt9m111->fmt = fmt;
676 }
677
678 return ret;
679}
680
Michael Grzeschik937bb422018-11-27 05:02:50 -0500681static const struct mt9m111_mode_info *
682mt9m111_find_mode(struct mt9m111 *mt9m111, unsigned int req_fps,
683 unsigned int width, unsigned int height)
684{
685 const struct mt9m111_mode_info *mode;
686 struct v4l2_rect *sensor_rect = &mt9m111->rect;
687 unsigned int gap, gap_best = (unsigned int) -1;
688 int i, best_gap_idx = MT9M111_MODE_SXGA_15FPS;
689 bool skip_30fps = false;
690
691 /*
692 * The fps selection is based on the row, column skipping mechanism.
693 * So ensure that the sensor window is set to default else the fps
694 * aren't calculated correctly within the sensor hw.
695 */
696 if (sensor_rect->width != MT9M111_MAX_WIDTH ||
697 sensor_rect->height != MT9M111_MAX_HEIGHT) {
698 dev_info(mt9m111->subdev.dev,
699 "Framerate selection is not supported for cropped "
700 "images\n");
701 return NULL;
702 }
703
704 /* 30fps only supported for images not exceeding 640x512 */
705 if (width > MT9M111_MAX_WIDTH / 2 || height > MT9M111_MAX_HEIGHT / 2) {
706 dev_dbg(mt9m111->subdev.dev,
707 "Framerates > 15fps are supported only for images "
708 "not exceeding 640x512\n");
709 skip_30fps = true;
710 }
711
712 /* find best matched fps */
713 for (i = 0; i < MT9M111_NUM_MODES; i++) {
714 unsigned int fps = mt9m111_mode_data[i].max_fps;
715
716 if (fps == 30 && skip_30fps)
717 continue;
718
719 gap = abs(fps - req_fps);
720 if (gap < gap_best) {
721 best_gap_idx = i;
722 gap_best = gap;
723 }
724 }
725
726 /*
727 * Use context a/b default timing values instead of calculate blanking
728 * timing values.
729 */
730 mode = &mt9m111_mode_data[best_gap_idx];
731 mt9m111->ctx = (best_gap_idx == MT9M111_MODE_QSXGA_30FPS) ? &context_a :
732 &context_b;
733 return mode;
734}
735
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300736#ifdef CONFIG_VIDEO_ADV_DEBUG
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300737static int mt9m111_g_register(struct v4l2_subdev *sd,
738 struct v4l2_dbg_register *reg)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300739{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300740 struct i2c_client *client = v4l2_get_subdevdata(sd);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300741 int val;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300742
Hans Verkuil6be89da2013-05-29 06:59:50 -0300743 if (reg->reg > 0x2ff)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300744 return -EINVAL;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300745
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300746 val = mt9m111_reg_read(client, reg->reg);
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300747 reg->size = 2;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300748 reg->val = (u64)val;
749
750 if (reg->val > 0xffff)
751 return -EIO;
752
753 return 0;
754}
755
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300756static int mt9m111_s_register(struct v4l2_subdev *sd,
Hans Verkuil977ba3b12013-03-24 08:28:46 -0300757 const struct v4l2_dbg_register *reg)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300758{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300759 struct i2c_client *client = v4l2_get_subdevdata(sd);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300760
Hans Verkuil6be89da2013-05-29 06:59:50 -0300761 if (reg->reg > 0x2ff)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300762 return -EINVAL;
763
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300764 if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300765 return -EIO;
766
767 return 0;
768}
769#endif
770
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300771static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300772{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300773 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300774 int ret;
775
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300776 if (flip)
777 ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
778 else
779 ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300780
781 return ret;
782}
783
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300784static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300785{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300786 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
roel kluin0f28b792008-12-17 14:01:07 -0300787 int data;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300788
789 data = reg_read(GLOBAL_GAIN);
790 if (data >= 0)
roel kluin0f28b792008-12-17 14:01:07 -0300791 return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
792 (1 << ((data >> 9) & 1));
793 return data;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300794}
roel kluin0f28b792008-12-17 14:01:07 -0300795
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300796static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300797{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300798 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300799 u16 val;
800
801 if (gain > 63 * 2 * 2)
802 return -EINVAL;
803
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300804 if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
805 val = (1 << 10) | (1 << 9) | (gain / 4);
806 else if ((gain >= 64) && (gain < 64 * 2))
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300807 val = (1 << 9) | (gain / 2);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300808 else
809 val = gain;
810
811 return reg_write(GLOBAL_GAIN, val);
812}
813
Benoît Thébaudeaucbaa5c52013-02-26 15:32:49 -0300814static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int val)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300815{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300816 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300817
Benoît Thébaudeaucbaa5c52013-02-26 15:32:49 -0300818 if (val == V4L2_EXPOSURE_AUTO)
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300819 return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
820 return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300821}
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300822
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300823static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300824{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300825 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300826
827 if (on)
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300828 return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
829 return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300830}
831
Akinobu Mita74e08732018-01-03 13:22:47 -0500832static const char * const mt9m111_test_pattern_menu[] = {
833 "Disabled",
834 "Vertical monochrome gradient",
835 "Flat color type 1",
836 "Flat color type 2",
837 "Flat color type 3",
838 "Flat color type 4",
839 "Flat color type 5",
840 "Color bar",
841};
842
843static int mt9m111_set_test_pattern(struct mt9m111 *mt9m111, int val)
844{
845 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
846
847 return mt9m111_reg_mask(client, MT9M111_TPG_CTRL, val,
848 MT9M111_TPG_SEL_MASK);
849}
850
Akinobu Mitadde64f72018-11-12 11:00:49 -0500851static int mt9m111_set_colorfx(struct mt9m111 *mt9m111, int val)
852{
853 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
854 static const struct v4l2_control colorfx[] = {
855 { V4L2_COLORFX_NONE, 0 },
856 { V4L2_COLORFX_BW, 1 },
857 { V4L2_COLORFX_SEPIA, 2 },
858 { V4L2_COLORFX_NEGATIVE, 3 },
859 { V4L2_COLORFX_SOLARIZATION, 4 },
860 };
861 int i;
862
863 for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
864 if (colorfx[i].id == val) {
865 return mt9m111_reg_mask(client, MT9M111_EFFECTS_MODE,
866 colorfx[i].value,
867 MT9M111_EFFECTS_MODE_MASK);
868 }
869 }
870
871 return -EINVAL;
872}
873
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300874static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300875{
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300876 struct mt9m111 *mt9m111 = container_of(ctrl->handler,
877 struct mt9m111, hdl);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300878
879 switch (ctrl->id) {
880 case V4L2_CID_VFLIP:
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300881 return mt9m111_set_flip(mt9m111, ctrl->val,
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300882 MT9M111_RMB_MIRROR_ROWS);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300883 case V4L2_CID_HFLIP:
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300884 return mt9m111_set_flip(mt9m111, ctrl->val,
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300885 MT9M111_RMB_MIRROR_COLS);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300886 case V4L2_CID_GAIN:
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300887 return mt9m111_set_global_gain(mt9m111, ctrl->val);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300888 case V4L2_CID_EXPOSURE_AUTO:
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300889 return mt9m111_set_autoexposure(mt9m111, ctrl->val);
Robert Jarzmik39bf3722008-12-18 11:29:05 -0300890 case V4L2_CID_AUTO_WHITE_BALANCE:
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300891 return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
Akinobu Mita74e08732018-01-03 13:22:47 -0500892 case V4L2_CID_TEST_PATTERN:
893 return mt9m111_set_test_pattern(mt9m111, ctrl->val);
Akinobu Mitadde64f72018-11-12 11:00:49 -0500894 case V4L2_CID_COLORFX:
895 return mt9m111_set_colorfx(mt9m111, ctrl->val);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300896 }
897
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300898 return -EINVAL;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300899}
900
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300901static int mt9m111_suspend(struct mt9m111 *mt9m111)
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300902{
Guennadi Liakhovetskia650bf12011-11-03 08:19:18 -0300903 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
904 int ret;
905
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300906 v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300907
Guennadi Liakhovetskia650bf12011-11-03 08:19:18 -0300908 ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
909 if (!ret)
910 ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
911 MT9M111_RESET_OUTPUT_DISABLE |
912 MT9M111_RESET_ANALOG_STANDBY);
913 if (!ret)
914 ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
915
916 return ret;
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300917}
918
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300919static void mt9m111_restore_state(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300920{
Michael Grzeschik937bb422018-11-27 05:02:50 -0500921 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
922
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300923 mt9m111_set_context(mt9m111, mt9m111->ctx);
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300924 mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
Guennadi Liakhovetskida673e62011-11-04 15:13:18 -0300925 mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
926 mt9m111->width, mt9m111->height, mt9m111->fmt->code);
Hans Verkuilaf8425c2011-09-07 06:56:57 -0300927 v4l2_ctrl_handler_setup(&mt9m111->hdl);
Michael Grzeschik937bb422018-11-27 05:02:50 -0500928 mt9m111_reg_mask(client, mt9m111->ctx->read_mode,
929 mt9m111->current_mode->reg_val,
930 mt9m111->current_mode->reg_mask);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300931}
932
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300933static int mt9m111_resume(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300934{
Guennadi Liakhovetskia650bf12011-11-03 08:19:18 -0300935 int ret = mt9m111_enable(mt9m111);
936 if (!ret)
937 ret = mt9m111_reset(mt9m111);
938 if (!ret)
939 mt9m111_restore_state(mt9m111);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300940
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300941 return ret;
942}
943
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300944static int mt9m111_init(struct mt9m111 *mt9m111)
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300945{
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300946 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300947 int ret;
948
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300949 ret = mt9m111_enable(mt9m111);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300950 if (!ret)
Guennadi Liakhovetski2768cbb2011-06-07 06:47:30 -0300951 ret = mt9m111_reset(mt9m111);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300952 if (!ret)
Guennadi Liakhovetski47921932011-11-03 08:14:56 -0300953 ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300954 if (ret)
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -0300955 dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
Guennadi Liakhovetski506c6292008-08-14 12:03:49 -0300956 return ret;
Robert Jarzmik77110ab2008-08-14 12:02:51 -0300957}
958
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300959static int mt9m111_power_on(struct mt9m111 *mt9m111)
960{
961 struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300962 int ret;
963
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300964 ret = v4l2_clk_enable(mt9m111->clk);
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300965 if (ret < 0)
966 return ret;
967
968 ret = mt9m111_resume(mt9m111);
969 if (ret < 0) {
970 dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300971 v4l2_clk_disable(mt9m111->clk);
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300972 }
973
974 return ret;
975}
976
977static void mt9m111_power_off(struct mt9m111 *mt9m111)
978{
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300979 mt9m111_suspend(mt9m111);
Robert Jarzmik5d7cc012016-09-06 06:04:11 -0300980 v4l2_clk_disable(mt9m111->clk);
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300981}
982
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300983static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
984{
985 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300986 int ret = 0;
987
988 mutex_lock(&mt9m111->power_lock);
989
990 /*
991 * If the power count is modified from 0 to != 0 or from != 0 to 0,
992 * update the power state.
993 */
994 if (mt9m111->power_count == !on) {
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -0300995 if (on)
996 ret = mt9m111_power_on(mt9m111);
997 else
998 mt9m111_power_off(mt9m111);
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -0300999 }
1000
Laurent Pinchart4ec10ba2012-07-20 10:19:50 -03001001 if (!ret) {
1002 /* Update the power count. */
1003 mt9m111->power_count += on ? 1 : -1;
1004 WARN_ON(mt9m111->power_count < 0);
1005 }
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -03001006
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -03001007 mutex_unlock(&mt9m111->power_lock);
1008 return ret;
1009}
1010
Hans Verkuilaf8425c2011-09-07 06:56:57 -03001011static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
1012 .s_ctrl = mt9m111_s_ctrl,
1013};
1014
Julia Lawall39229622017-08-08 06:58:30 -04001015static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
Guennadi Liakhovetski14c5ea92011-06-05 08:27:39 -03001016 .s_power = mt9m111_s_power,
Akinobu Mita329d9e352018-11-12 11:00:48 -05001017 .log_status = v4l2_ctrl_subdev_log_status,
1018 .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1019 .unsubscribe_event = v4l2_event_subdev_unsubscribe,
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001020#ifdef CONFIG_VIDEO_ADV_DEBUG
1021 .g_register = mt9m111_g_register,
1022 .s_register = mt9m111_s_register,
1023#endif
1024};
1025
Michael Grzeschik937bb422018-11-27 05:02:50 -05001026static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
1027 struct v4l2_subdev_frame_interval *fi)
1028{
1029 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1030
1031 fi->interval = mt9m111->frame_interval;
1032
1033 return 0;
1034}
1035
1036static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
1037 struct v4l2_subdev_frame_interval *fi)
1038{
1039 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1040 const struct mt9m111_mode_info *mode;
1041 struct v4l2_fract *fract = &fi->interval;
1042 int fps;
1043
1044 if (mt9m111->is_streaming)
1045 return -EBUSY;
1046
1047 if (fi->pad != 0)
1048 return -EINVAL;
1049
1050 if (fract->numerator == 0) {
1051 fract->denominator = 30;
1052 fract->numerator = 1;
1053 }
1054
1055 fps = DIV_ROUND_CLOSEST(fract->denominator, fract->numerator);
1056
1057 /* Find best fitting mode. Do not update the mode if no one was found. */
1058 mode = mt9m111_find_mode(mt9m111, fps, mt9m111->width, mt9m111->height);
1059 if (!mode)
1060 return 0;
1061
1062 if (mode->max_fps != fps) {
1063 fract->denominator = mode->max_fps;
1064 fract->numerator = 1;
1065 }
1066
1067 mt9m111->current_mode = mode;
1068 mt9m111->frame_interval = fi->interval;
1069
1070 return 0;
1071}
1072
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001073static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
1074 struct v4l2_subdev_pad_config *cfg,
1075 struct v4l2_subdev_mbus_code_enum *code)
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001076{
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001077 if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts))
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001078 return -EINVAL;
1079
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001080 code->code = mt9m111_colour_fmts[code->index].code;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001081 return 0;
1082}
1083
Marco Felsch7784b1d2018-11-27 05:02:48 -05001084static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
1085{
1086 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1087
1088 mt9m111->is_streaming = !!enable;
1089 return 0;
1090}
1091
Guennadi Liakhovetski0c0b4462011-07-26 11:48:29 -03001092static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
1093 struct v4l2_mbus_config *cfg)
1094{
Enrico Scholz98480d62018-11-27 05:02:53 -05001095 struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
1096
1097 cfg->flags = V4L2_MBUS_MASTER |
Guennadi Liakhovetski0c0b4462011-07-26 11:48:29 -03001098 V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
1099 V4L2_MBUS_DATA_ACTIVE_HIGH;
Enrico Scholz98480d62018-11-27 05:02:53 -05001100
1101 cfg->flags |= mt9m111->pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING :
1102 V4L2_MBUS_PCLK_SAMPLE_FALLING;
1103
Guennadi Liakhovetski0c0b4462011-07-26 11:48:29 -03001104 cfg->type = V4L2_MBUS_PARALLEL;
Guennadi Liakhovetski0c0b4462011-07-26 11:48:29 -03001105
1106 return 0;
1107}
1108
Julia Lawall39229622017-08-08 06:58:30 -04001109static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
Guennadi Liakhovetski0c0b4462011-07-26 11:48:29 -03001110 .g_mbus_config = mt9m111_g_mbus_config,
Marco Felsch7784b1d2018-11-27 05:02:48 -05001111 .s_stream = mt9m111_s_stream,
Michael Grzeschik937bb422018-11-27 05:02:50 -05001112 .g_frame_interval = mt9m111_g_frame_interval,
1113 .s_frame_interval = mt9m111_s_frame_interval,
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001114};
1115
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001116static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
1117 .enum_mbus_code = mt9m111_enum_mbus_code,
Hans Verkuil10d5509c2015-12-14 08:25:32 -02001118 .get_selection = mt9m111_get_selection,
1119 .set_selection = mt9m111_set_selection,
Hans Verkuilda298c62015-04-09 04:02:34 -03001120 .get_fmt = mt9m111_get_fmt,
Hans Verkuil717fd5b2015-04-09 06:24:36 -03001121 .set_fmt = mt9m111_set_fmt,
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001122};
1123
Julia Lawall39229622017-08-08 06:58:30 -04001124static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001125 .core = &mt9m111_subdev_core_ops,
1126 .video = &mt9m111_subdev_video_ops,
Hans Verkuilebcff5f2015-04-09 04:01:33 -03001127 .pad = &mt9m111_subdev_pad_ops,
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001128};
1129
Laurent Pinchart4bbc6d52012-07-18 10:54:04 -03001130/*
1131 * Interface active, can use i2c. If it fails, it can indeed mean, that
1132 * this wasn't our capture interface, so, we wait for the right one
1133 */
1134static int mt9m111_video_probe(struct i2c_client *client)
1135{
1136 struct mt9m111 *mt9m111 = to_mt9m111(client);
1137 s32 data;
1138 int ret;
1139
1140 ret = mt9m111_s_power(&mt9m111->subdev, 1);
1141 if (ret < 0)
1142 return ret;
1143
1144 data = reg_read(CHIP_VERSION);
1145
1146 switch (data) {
1147 case 0x143a: /* MT9M111 or MT9M131 */
Laurent Pinchart4bbc6d52012-07-18 10:54:04 -03001148 dev_info(&client->dev,
1149 "Detected a MT9M111/MT9M131 chip ID %x\n", data);
1150 break;
1151 case 0x148c: /* MT9M112 */
Laurent Pinchart4bbc6d52012-07-18 10:54:04 -03001152 dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
1153 break;
1154 default:
1155 dev_err(&client->dev,
1156 "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
1157 data);
1158 ret = -ENODEV;
1159 goto done;
1160 }
1161
1162 ret = mt9m111_init(mt9m111);
1163 if (ret)
1164 goto done;
1165
1166 ret = v4l2_ctrl_handler_setup(&mt9m111->hdl);
1167
1168done:
1169 mt9m111_s_power(&mt9m111->subdev, 0);
1170 return ret;
1171}
1172
Enrico Scholz98480d62018-11-27 05:02:53 -05001173static int mt9m111_probe_fw(struct i2c_client *client, struct mt9m111 *mt9m111)
1174{
1175 struct v4l2_fwnode_endpoint bus_cfg = {
1176 .bus_type = V4L2_MBUS_PARALLEL
1177 };
1178 struct fwnode_handle *np;
1179 int ret;
1180
1181 np = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
1182 if (!np)
1183 return -EINVAL;
1184
1185 ret = v4l2_fwnode_endpoint_parse(np, &bus_cfg);
1186 if (ret)
1187 goto out_put_fw;
1188
1189 mt9m111->pclk_sample = !!(bus_cfg.bus.parallel.flags &
1190 V4L2_MBUS_PCLK_SAMPLE_RISING);
1191
1192out_put_fw:
1193 fwnode_handle_put(np);
1194 return ret;
1195}
1196
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001197static int mt9m111_probe(struct i2c_client *client,
1198 const struct i2c_device_id *did)
1199{
1200 struct mt9m111 *mt9m111;
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001201 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001202 int ret;
1203
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001204 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
1205 dev_warn(&adapter->dev,
1206 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
1207 return -EIO;
1208 }
1209
Guennadi Liakhovetski70e176a2012-12-21 10:28:43 -03001210 mt9m111 = devm_kzalloc(&client->dev, sizeof(struct mt9m111), GFP_KERNEL);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001211 if (!mt9m111)
1212 return -ENOMEM;
1213
Enrico Scholz98480d62018-11-27 05:02:53 -05001214 ret = mt9m111_probe_fw(client, mt9m111);
1215 if (ret)
1216 return ret;
1217
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001218 mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
1219 if (IS_ERR(mt9m111->clk))
Fabio Estevambddb4b52017-08-27 13:30:36 -03001220 return PTR_ERR(mt9m111->clk);
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001221
Guennadi Liakhovetski4a1313c2013-03-12 08:40:37 -03001222 /* Default HIGHPOWER context */
1223 mt9m111->ctx = &context_b;
1224
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001225 v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
Akinobu Mita329d9e352018-11-12 11:00:48 -05001226 mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
1227 V4L2_SUBDEV_FL_HAS_EVENTS;
Akinobu Mita5ed8c222018-01-03 13:22:44 -05001228
Akinobu Mitadde64f72018-11-12 11:00:49 -05001229 v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
Hans Verkuilaf8425c2011-09-07 06:56:57 -03001230 v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1231 V4L2_CID_VFLIP, 0, 1, 1, 0);
1232 v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1233 V4L2_CID_HFLIP, 0, 1, 1, 0);
1234 v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1235 V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
1236 mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
1237 V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
1238 v4l2_ctrl_new_std_menu(&mt9m111->hdl,
1239 &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
1240 V4L2_EXPOSURE_AUTO);
Akinobu Mita74e08732018-01-03 13:22:47 -05001241 v4l2_ctrl_new_std_menu_items(&mt9m111->hdl,
1242 &mt9m111_ctrl_ops, V4L2_CID_TEST_PATTERN,
1243 ARRAY_SIZE(mt9m111_test_pattern_menu) - 1, 0, 0,
1244 mt9m111_test_pattern_menu);
Akinobu Mitadde64f72018-11-12 11:00:49 -05001245 v4l2_ctrl_new_std_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
1246 V4L2_CID_COLORFX, V4L2_COLORFX_SOLARIZATION,
1247 ~(BIT(V4L2_COLORFX_NONE) |
1248 BIT(V4L2_COLORFX_BW) |
1249 BIT(V4L2_COLORFX_SEPIA) |
1250 BIT(V4L2_COLORFX_NEGATIVE) |
1251 BIT(V4L2_COLORFX_SOLARIZATION)),
1252 V4L2_COLORFX_NONE);
Hans Verkuilaf8425c2011-09-07 06:56:57 -03001253 mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001254 if (mt9m111->hdl.error) {
1255 ret = mt9m111->hdl.error;
1256 goto out_clkput;
1257 }
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001258
Akinobu Mita90411ce2018-01-03 13:22:45 -05001259#ifdef CONFIG_MEDIA_CONTROLLER
1260 mt9m111->pad.flags = MEDIA_PAD_FL_SOURCE;
1261 mt9m111->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1262 ret = media_entity_pads_init(&mt9m111->subdev.entity, 1, &mt9m111->pad);
1263 if (ret < 0)
1264 goto out_hdlfree;
1265#endif
1266
Michael Grzeschik937bb422018-11-27 05:02:50 -05001267 mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS];
1268 mt9m111->frame_interval.numerator = 1;
1269 mt9m111->frame_interval.denominator = mt9m111->current_mode->max_fps;
1270
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001271 /* Second stage probe - when a capture adapter is there */
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001272 mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
1273 mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
1274 mt9m111->rect.width = MT9M111_MAX_WIDTH;
1275 mt9m111->rect.height = MT9M111_MAX_HEIGHT;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001276 mt9m111->fmt = &mt9m111_colour_fmts[0];
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -03001277 mt9m111->lastpage = -1;
Guennadi Liakhovetski6b806e32011-11-03 08:12:00 -03001278 mutex_init(&mt9m111->power_lock);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001279
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -03001280 ret = mt9m111_video_probe(client);
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001281 if (ret < 0)
Akinobu Mita90411ce2018-01-03 13:22:45 -05001282 goto out_entityclean;
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001283
1284 mt9m111->subdev.dev = &client->dev;
1285 ret = v4l2_async_register_subdev(&mt9m111->subdev);
1286 if (ret < 0)
Akinobu Mita90411ce2018-01-03 13:22:45 -05001287 goto out_entityclean;
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001288
1289 return 0;
1290
Akinobu Mita90411ce2018-01-03 13:22:45 -05001291out_entityclean:
1292#ifdef CONFIG_MEDIA_CONTROLLER
1293 media_entity_cleanup(&mt9m111->subdev.entity);
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001294out_hdlfree:
Akinobu Mita90411ce2018-01-03 13:22:45 -05001295#endif
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001296 v4l2_ctrl_handler_free(&mt9m111->hdl);
1297out_clkput:
1298 v4l2_clk_put(mt9m111->clk);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001299
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001300 return ret;
1301}
1302
1303static int mt9m111_remove(struct i2c_client *client)
1304{
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001305 struct mt9m111 *mt9m111 = to_mt9m111(client);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001306
Guennadi Liakhovetskief6672e2013-07-30 04:35:18 -03001307 v4l2_async_unregister_subdev(&mt9m111->subdev);
Akinobu Mita90411ce2018-01-03 13:22:45 -05001308 media_entity_cleanup(&mt9m111->subdev.entity);
Guennadi Liakhovetski9aea4702012-12-21 13:01:55 -03001309 v4l2_clk_put(mt9m111->clk);
Hans Verkuilaf8425c2011-09-07 06:56:57 -03001310 v4l2_ctrl_handler_free(&mt9m111->hdl);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001311
1312 return 0;
1313}
Robert Jarzmikc5f176d2014-06-21 19:19:54 -03001314static const struct of_device_id mt9m111_of_match[] = {
1315 { .compatible = "micron,mt9m111", },
1316 {},
1317};
1318MODULE_DEVICE_TABLE(of, mt9m111_of_match);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001319
1320static const struct i2c_device_id mt9m111_id[] = {
1321 { "mt9m111", 0 },
1322 { }
1323};
1324MODULE_DEVICE_TABLE(i2c, mt9m111_id);
1325
1326static struct i2c_driver mt9m111_i2c_driver = {
1327 .driver = {
1328 .name = "mt9m111",
Robert Jarzmikc5f176d2014-06-21 19:19:54 -03001329 .of_match_table = of_match_ptr(mt9m111_of_match),
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001330 },
1331 .probe = mt9m111_probe,
1332 .remove = mt9m111_remove,
1333 .id_table = mt9m111_id,
1334};
1335
Axel Linc6e8d862012-02-12 06:56:32 -03001336module_i2c_driver(mt9m111_i2c_driver);
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001337
Philipp Wiesnerc8cf0782010-08-03 07:57:39 -03001338MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
Robert Jarzmik77110ab2008-08-14 12:02:51 -03001339MODULE_AUTHOR("Robert Jarzmik");
1340MODULE_LICENSE("GPL");