blob: c5c67ec8fd78fa1d1199435f3ed634c3e389965a [file] [log] [blame]
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -03001/*
2 * Driver for MT9V022 CMOS Image Sensor from Micron
3 *
4 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
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
11#include <linux/videodev2.h>
12#include <linux/slab.h>
13#include <linux/i2c.h>
14#include <linux/delay.h>
15#include <linux/log2.h>
16
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -030017#include <media/soc_camera.h>
18#include <media/soc_mediabus.h>
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -030019#include <media/v4l2-subdev.h>
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -030020#include <media/v4l2-chip-ident.h>
Hans Verkuilab7b50a2011-09-07 05:22:39 -030021#include <media/v4l2-ctrls.h>
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -030022
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -030023/*
24 * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -030025 * The platform has to define ctruct i2c_board_info objects and link to them
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -030026 * from struct soc_camera_link
27 */
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -030028
29static char *sensor_type;
30module_param(sensor_type, charp, S_IRUGO);
Niels de Vos61a2d072008-07-31 00:07:23 -070031MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -030032
33/* mt9v022 selected register addresses */
34#define MT9V022_CHIP_VERSION 0x00
35#define MT9V022_COLUMN_START 0x01
36#define MT9V022_ROW_START 0x02
37#define MT9V022_WINDOW_HEIGHT 0x03
38#define MT9V022_WINDOW_WIDTH 0x04
39#define MT9V022_HORIZONTAL_BLANKING 0x05
40#define MT9V022_VERTICAL_BLANKING 0x06
41#define MT9V022_CHIP_CONTROL 0x07
42#define MT9V022_SHUTTER_WIDTH1 0x08
43#define MT9V022_SHUTTER_WIDTH2 0x09
44#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a
45#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b
46#define MT9V022_RESET 0x0c
47#define MT9V022_READ_MODE 0x0d
48#define MT9V022_MONITOR_MODE 0x0e
49#define MT9V022_PIXEL_OPERATION_MODE 0x0f
50#define MT9V022_LED_OUT_CONTROL 0x1b
51#define MT9V022_ADC_MODE_CONTROL 0x1c
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -030052#define MT9V022_ANALOG_GAIN 0x35
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -030053#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
54#define MT9V022_PIXCLK_FV_LV 0x74
55#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
56#define MT9V022_AEC_AGC_ENABLE 0xAF
57#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
58
59/* Progressive scan, master, defaults */
60#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
61
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -030062#define MT9V022_MAX_WIDTH 752
63#define MT9V022_MAX_HEIGHT 480
64#define MT9V022_MIN_WIDTH 48
65#define MT9V022_MIN_HEIGHT 32
66#define MT9V022_COLUMN_SKIP 1
67#define MT9V022_ROW_SKIP 4
68
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -030069/* MT9V022 has only one fixed colorspace per pixelcode */
70struct mt9v022_datafmt {
71 enum v4l2_mbus_pixelcode code;
72 enum v4l2_colorspace colorspace;
73};
74
75/* Find a data format by a pixel code in an array */
76static const struct mt9v022_datafmt *mt9v022_find_datafmt(
77 enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt,
78 int n)
79{
80 int i;
81 for (i = 0; i < n; i++)
82 if (fmt[i].code == code)
83 return fmt + i;
84
85 return NULL;
86}
87
88static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -030089 /*
90 * Order important: first natively supported,
91 * second supported with a GPIO extender
92 */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -030093 {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
94 {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
Guennadi Liakhovetskibb55de32008-04-22 14:45:13 -030095};
96
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -030097static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
Guennadi Liakhovetskibb55de32008-04-22 14:45:13 -030098 /* Order important - see above */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -030099 {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
Laurent Pinchart076704332010-09-28 07:01:44 -0300100 {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300101};
102
103struct mt9v022 {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300104 struct v4l2_subdev subdev;
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300105 struct v4l2_ctrl_handler hdl;
106 struct {
107 /* exposure/auto-exposure cluster */
108 struct v4l2_ctrl *autoexposure;
109 struct v4l2_ctrl *exposure;
110 };
111 struct {
112 /* gain/auto-gain cluster */
113 struct v4l2_ctrl *autogain;
114 struct v4l2_ctrl *gain;
115 };
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300116 struct v4l2_rect rect; /* Sensor window */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300117 const struct mt9v022_datafmt *fmt;
118 const struct mt9v022_datafmt *fmts;
119 int num_fmts;
Guennadi Liakhovetski7fb0fd02008-05-05 14:12:30 -0300120 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300121 u16 chip_control;
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300122 unsigned short y_skip_top; /* Lines to skip at the top */
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300123};
124
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300125static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
126{
127 return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
128}
129
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300130static int reg_read(struct i2c_client *client, const u8 reg)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300131{
Jonathan Cameron3f877042011-10-21 09:30:25 -0300132 return i2c_smbus_read_word_swapped(client, reg);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300133}
134
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300135static int reg_write(struct i2c_client *client, const u8 reg,
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300136 const u16 data)
137{
Jonathan Cameron3f877042011-10-21 09:30:25 -0300138 return i2c_smbus_write_word_swapped(client, reg, data);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300139}
140
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300141static int reg_set(struct i2c_client *client, const u8 reg,
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300142 const u16 data)
143{
144 int ret;
145
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300146 ret = reg_read(client, reg);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300147 if (ret < 0)
148 return ret;
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300149 return reg_write(client, reg, ret | data);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300150}
151
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300152static int reg_clear(struct i2c_client *client, const u8 reg,
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300153 const u16 data)
154{
155 int ret;
156
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300157 ret = reg_read(client, reg);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300158 if (ret < 0)
159 return ret;
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300160 return reg_write(client, reg, ret & ~data);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300161}
162
Guennadi Liakhovetskia4c56fd2009-08-25 11:53:23 -0300163static int mt9v022_init(struct i2c_client *client)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300164{
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300165 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300166 int ret;
167
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300168 /*
169 * Almost the default mode: master, parallel, simultaneous, and an
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300170 * undocumented bit 0x200, which is present in table 7, but not in 8,
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300171 * plus snapshot mode to disable scan for now
172 */
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300173 mt9v022->chip_control |= 0x10;
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300174 ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300175 if (!ret)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300176 ret = reg_write(client, MT9V022_READ_MODE, 0x300);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300177
178 /* All defaults */
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300179 if (!ret)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300180 /* AEC, AGC on */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300181 ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300182 if (!ret)
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300183 ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
184 if (!ret)
185 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
186 if (!ret)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300187 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300188 if (!ret)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300189 /* default - auto */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300190 ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300191 if (!ret)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300192 ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300193 if (!ret)
194 return v4l2_ctrl_handler_setup(&mt9v022->hdl);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300195
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300196 return ret;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300197}
198
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300199static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300200{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300201 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300202 struct mt9v022 *mt9v022 = to_mt9v022(client);
Stefan Herbrechtsmeier81034662008-08-14 12:04:11 -0300203
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300204 if (enable)
205 /* Switch to master "normal" mode */
206 mt9v022->chip_control &= ~0x10;
207 else
208 /* Switch to snapshot mode */
209 mt9v022->chip_control |= 0x10;
Stefan Herbrechtsmeier81034662008-08-14 12:04:11 -0300210
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300211 if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300212 return -EIO;
213 return 0;
214}
215
Guennadi Liakhovetski08590b92009-08-25 11:46:54 -0300216static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300217{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300218 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300219 struct mt9v022 *mt9v022 = to_mt9v022(client);
220 struct v4l2_rect rect = a->c;
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300221 int ret;
222
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300223 /* Bayer format - even size lengths */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300224 if (mt9v022->fmts == mt9v022_colour_fmts) {
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300225 rect.width = ALIGN(rect.width, 2);
226 rect.height = ALIGN(rect.height, 2);
227 /* Let the user play with the starting pixel */
228 }
229
230 soc_camera_limit_side(&rect.left, &rect.width,
231 MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
232
233 soc_camera_limit_side(&rect.top, &rect.height,
234 MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
235
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300236 /* Like in example app. Contradicts the datasheet though */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300237 ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300238 if (ret >= 0) {
239 if (ret & 1) /* Autoexposure */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300240 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300241 rect.height + mt9v022->y_skip_top + 43);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300242 else
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300243 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300244 rect.height + mt9v022->y_skip_top + 43);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300245 }
246 /* Setup frame format: defaults apart from width and height */
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300247 if (!ret)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300248 ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300249 if (!ret)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300250 ret = reg_write(client, MT9V022_ROW_START, rect.top);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300251 if (!ret)
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300252 /*
253 * Default 94, Phytec driver says:
254 * "width + horizontal blank >= 660"
255 */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300256 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300257 rect.width > 660 - 43 ? 43 :
258 660 - rect.width);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300259 if (!ret)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300260 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300261 if (!ret)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300262 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
Guennadi Liakhovetski11211642008-08-14 12:03:18 -0300263 if (!ret)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300264 ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300265 rect.height + mt9v022->y_skip_top);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300266
267 if (ret < 0)
268 return ret;
269
Márton Némethe26b3142010-02-24 17:13:29 -0300270 dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300271
272 mt9v022->rect = rect;
273
274 return 0;
275}
276
277static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
278{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300279 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300280 struct mt9v022 *mt9v022 = to_mt9v022(client);
281
282 a->c = mt9v022->rect;
283 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
284
285 return 0;
286}
287
288static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
289{
290 a->bounds.left = MT9V022_COLUMN_SKIP;
291 a->bounds.top = MT9V022_ROW_SKIP;
292 a->bounds.width = MT9V022_MAX_WIDTH;
293 a->bounds.height = MT9V022_MAX_HEIGHT;
294 a->defrect = a->bounds;
295 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
296 a->pixelaspect.numerator = 1;
297 a->pixelaspect.denominator = 1;
298
299 return 0;
300}
301
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300302static int mt9v022_g_fmt(struct v4l2_subdev *sd,
303 struct v4l2_mbus_framefmt *mf)
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300304{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300305 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300306 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300307
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300308 mf->width = mt9v022->rect.width;
309 mf->height = mt9v022->rect.height;
310 mf->code = mt9v022->fmt->code;
311 mf->colorspace = mt9v022->fmt->colorspace;
312 mf->field = V4L2_FIELD_NONE;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300313
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300314 return 0;
315}
316
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300317static int mt9v022_s_fmt(struct v4l2_subdev *sd,
318 struct v4l2_mbus_framefmt *mf)
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300319{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300320 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300321 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski08590b92009-08-25 11:46:54 -0300322 struct v4l2_crop a = {
323 .c = {
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300324 .left = mt9v022->rect.left,
325 .top = mt9v022->rect.top,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300326 .width = mf->width,
327 .height = mf->height,
Guennadi Liakhovetski08590b92009-08-25 11:46:54 -0300328 },
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300329 };
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300330 int ret;
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300331
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300332 /*
333 * The caller provides a supported format, as verified per call to
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300334 * .try_mbus_fmt(), datawidth is from our supported format list
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300335 */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300336 switch (mf->code) {
Laurent Pinchart076704332010-09-28 07:01:44 -0300337 case V4L2_MBUS_FMT_Y8_1X8:
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300338 case V4L2_MBUS_FMT_Y10_1X10:
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300339 if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
340 return -EINVAL;
341 break;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300342 case V4L2_MBUS_FMT_SBGGR8_1X8:
343 case V4L2_MBUS_FMT_SBGGR10_1X10:
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300344 if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
345 return -EINVAL;
346 break;
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300347 default:
348 return -EINVAL;
349 }
350
351 /* No support for scaling on this camera, just crop. */
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300352 ret = mt9v022_s_crop(sd, &a);
353 if (!ret) {
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300354 mf->width = mt9v022->rect.width;
355 mf->height = mt9v022->rect.height;
356 mt9v022->fmt = mt9v022_find_datafmt(mf->code,
357 mt9v022->fmts, mt9v022->num_fmts);
358 mf->colorspace = mt9v022->fmt->colorspace;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300359 }
360
361 return ret;
Guennadi Liakhovetski09e231b2009-03-13 06:08:20 -0300362}
363
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300364static int mt9v022_try_fmt(struct v4l2_subdev *sd,
365 struct v4l2_mbus_framefmt *mf)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300366{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300367 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300368 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300369 const struct mt9v022_datafmt *fmt;
370 int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
371 mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300372
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300373 v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300374 MT9V022_MAX_WIDTH, align,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300375 &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300376 MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300377
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300378 fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
379 mt9v022->num_fmts);
380 if (!fmt) {
381 fmt = mt9v022->fmt;
382 mf->code = fmt->code;
383 }
384
385 mf->colorspace = fmt->colorspace;
386
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300387 return 0;
388}
389
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300390static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
391 struct v4l2_dbg_chip_ident *id)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300392{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300393 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300394 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300395
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300396 if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300397 return -EINVAL;
398
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300399 if (id->match.addr != client->addr)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300400 return -ENODEV;
401
402 id->ident = mt9v022->model;
403 id->revision = 0;
404
405 return 0;
406}
407
408#ifdef CONFIG_VIDEO_ADV_DEBUG
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300409static int mt9v022_g_register(struct v4l2_subdev *sd,
410 struct v4l2_dbg_register *reg)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300411{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300412 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300413
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300414 if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300415 return -EINVAL;
416
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300417 if (reg->match.addr != client->addr)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300418 return -ENODEV;
419
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300420 reg->size = 2;
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300421 reg->val = reg_read(client, reg->reg);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300422
423 if (reg->val > 0xffff)
424 return -EIO;
425
426 return 0;
427}
428
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300429static int mt9v022_s_register(struct v4l2_subdev *sd,
430 struct v4l2_dbg_register *reg)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300431{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300432 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300433
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300434 if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300435 return -EINVAL;
436
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300437 if (reg->match.addr != client->addr)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300438 return -ENODEV;
439
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300440 if (reg_write(client, reg->reg, reg->val) < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300441 return -EIO;
442
443 return 0;
444}
445#endif
446
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300447static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300448{
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300449 struct mt9v022 *mt9v022 = container_of(ctrl->handler,
450 struct mt9v022, hdl);
451 struct v4l2_subdev *sd = &mt9v022->subdev;
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300452 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300453 struct v4l2_ctrl *gain = mt9v022->gain;
454 struct v4l2_ctrl *exp = mt9v022->exposure;
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300455 unsigned long range;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300456 int data;
457
458 switch (ctrl->id) {
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300459 case V4L2_CID_AUTOGAIN:
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300460 data = reg_read(client, MT9V022_ANALOG_GAIN);
461 if (data < 0)
462 return -EIO;
463
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300464 range = gain->maximum - gain->minimum;
465 gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
466 return 0;
467 case V4L2_CID_EXPOSURE_AUTO:
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300468 data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
469 if (data < 0)
470 return -EIO;
471
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300472 range = exp->maximum - exp->minimum;
473 exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
474 return 0;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300475 }
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300476 return -EINVAL;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300477}
478
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300479static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300480{
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300481 struct mt9v022 *mt9v022 = container_of(ctrl->handler,
482 struct mt9v022, hdl);
483 struct v4l2_subdev *sd = &mt9v022->subdev;
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300484 struct i2c_client *client = v4l2_get_subdevdata(sd);
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300485 int data;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300486
487 switch (ctrl->id) {
488 case V4L2_CID_VFLIP:
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300489 if (ctrl->val)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300490 data = reg_set(client, MT9V022_READ_MODE, 0x10);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300491 else
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300492 data = reg_clear(client, MT9V022_READ_MODE, 0x10);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300493 if (data < 0)
494 return -EIO;
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300495 return 0;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300496 case V4L2_CID_HFLIP:
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300497 if (ctrl->val)
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300498 data = reg_set(client, MT9V022_READ_MODE, 0x20);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300499 else
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300500 data = reg_clear(client, MT9V022_READ_MODE, 0x20);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300501 if (data < 0)
502 return -EIO;
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300503 return 0;
504 case V4L2_CID_AUTOGAIN:
505 if (ctrl->val) {
506 if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
507 return -EIO;
508 } else {
509 struct v4l2_ctrl *gain = mt9v022->gain;
510 /* mt9v022 has minimum == default */
511 unsigned long range = gain->maximum - gain->minimum;
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300512 /* Valid values 16 to 64, 32 to 64 must be even. */
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300513 unsigned long gain_val = ((gain->val - gain->minimum) *
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300514 48 + range / 2) / range + 16;
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300515
516 if (gain_val >= 32)
517 gain_val &= ~1;
518
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300519 /*
520 * The user wants to set gain manually, hope, she
521 * knows, what she's doing... Switch AGC off.
522 */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300523 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300524 return -EIO;
525
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300526 dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300527 reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
528 if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300529 return -EIO;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300530 }
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300531 return 0;
532 case V4L2_CID_EXPOSURE_AUTO:
533 if (ctrl->val == V4L2_EXPOSURE_AUTO) {
534 data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
535 } else {
536 struct v4l2_ctrl *exp = mt9v022->exposure;
537 unsigned long range = exp->maximum - exp->minimum;
538 unsigned long shutter = ((exp->val - exp->minimum) *
539 479 + range / 2) / range + 1;
540
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300541 /*
542 * The user wants to set shutter width manually, hope,
543 * she knows, what she's doing... Switch AEC off.
544 */
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300545 data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
546 if (data < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300547 return -EIO;
Guennadi Liakhovetski85f8be62009-08-25 11:47:00 -0300548 dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300549 reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
550 shutter);
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300551 if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300552 shutter) < 0)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300553 return -EIO;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300554 }
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300555 return 0;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300556 }
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300557 return -EINVAL;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300558}
559
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300560/*
561 * Interface active, can use i2c. If it fails, it can indeed mean, that
562 * this wasn't our capture interface, so, we wait for the right one
563 */
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300564static int mt9v022_video_probe(struct i2c_client *client)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300565{
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300566 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300567 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300568 s32 data;
569 int ret;
Sascha Hauere958e272009-03-13 06:08:20 -0300570 unsigned long flags;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300571
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300572 /* Read out the chip version register */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300573 data = reg_read(client, MT9V022_CHIP_VERSION);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300574
575 /* must be 0x1311 or 0x1313 */
576 if (data != 0x1311 && data != 0x1313) {
577 ret = -ENODEV;
Guennadi Liakhovetski85f8be62009-08-25 11:47:00 -0300578 dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300579 data);
580 goto ei2c;
581 }
582
583 /* Soft reset */
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300584 ret = reg_write(client, MT9V022_RESET, 1);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300585 if (ret < 0)
586 goto ei2c;
587 /* 15 clock cycles */
588 udelay(200);
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300589 if (reg_read(client, MT9V022_RESET)) {
Guennadi Liakhovetski85f8be62009-08-25 11:47:00 -0300590 dev_err(&client->dev, "Resetting MT9V022 failed!\n");
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300591 if (ret > 0)
592 ret = -EIO;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300593 goto ei2c;
594 }
595
596 /* Set monochrome or colour sensor type */
597 if (sensor_type && (!strcmp("colour", sensor_type) ||
598 !strcmp("color", sensor_type))) {
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300599 ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300600 mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300601 mt9v022->fmts = mt9v022_colour_fmts;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300602 } else {
Guennadi Liakhovetski9538e1c2009-04-24 12:57:01 -0300603 ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300604 mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300605 mt9v022->fmts = mt9v022_monochrome_fmts;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300606 }
607
Sascha Hauere958e272009-03-13 06:08:20 -0300608 if (ret < 0)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300609 goto ei2c;
Sascha Hauere958e272009-03-13 06:08:20 -0300610
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300611 mt9v022->num_fmts = 0;
Sascha Hauere958e272009-03-13 06:08:20 -0300612
613 /*
614 * This is a 10bit sensor, so by default we only allow 10bit.
615 * The platform may support different bus widths due to
616 * different routing of the data lines.
617 */
618 if (icl->query_bus_param)
619 flags = icl->query_bus_param(icl);
620 else
621 flags = SOCAM_DATAWIDTH_10;
622
623 if (flags & SOCAM_DATAWIDTH_10)
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300624 mt9v022->num_fmts++;
Sascha Hauere958e272009-03-13 06:08:20 -0300625 else
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300626 mt9v022->fmts++;
Sascha Hauere958e272009-03-13 06:08:20 -0300627
628 if (flags & SOCAM_DATAWIDTH_8)
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300629 mt9v022->num_fmts++;
Sascha Hauere958e272009-03-13 06:08:20 -0300630
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300631 mt9v022->fmt = &mt9v022->fmts[0];
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300632
Guennadi Liakhovetski85f8be62009-08-25 11:47:00 -0300633 dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300634 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
635 "monochrome" : "colour");
636
Guennadi Liakhovetskia4c56fd2009-08-25 11:53:23 -0300637 ret = mt9v022_init(client);
638 if (ret < 0)
639 dev_err(&client->dev, "Failed to initialise the camera\n");
640
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300641ei2c:
642 return ret;
643}
644
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300645static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
646{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300647 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300648 struct mt9v022 *mt9v022 = to_mt9v022(client);
649
650 *lines = mt9v022->y_skip_top;
651
652 return 0;
653}
654
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300655static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
656 .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
657 .s_ctrl = mt9v022_s_ctrl,
658};
659
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300660static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300661 .g_chip_ident = mt9v022_g_chip_ident,
662#ifdef CONFIG_VIDEO_ADV_DEBUG
663 .g_register = mt9v022_g_register,
664 .s_register = mt9v022_s_register,
665#endif
666};
667
Hans Verkuil3805f202010-05-08 17:55:00 -0300668static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300669 enum v4l2_mbus_pixelcode *code)
670{
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300671 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300672 struct mt9v022 *mt9v022 = to_mt9v022(client);
673
Hans Verkuil3805f202010-05-08 17:55:00 -0300674 if (index >= mt9v022->num_fmts)
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300675 return -EINVAL;
676
677 *code = mt9v022->fmts[index].code;
678 return 0;
679}
680
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300681static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
682 struct v4l2_mbus_config *cfg)
683{
684 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300685 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300686
687 cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
688 V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
689 V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
690 V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
691 V4L2_MBUS_DATA_ACTIVE_HIGH;
692 cfg->type = V4L2_MBUS_PARALLEL;
693 cfg->flags = soc_camera_apply_board_flags(icl, cfg);
694
695 return 0;
696}
697
698static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
699 const struct v4l2_mbus_config *cfg)
700{
701 struct i2c_client *client = v4l2_get_subdevdata(sd);
Guennadi Liakhovetski443f4832011-09-09 07:06:50 -0300702 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300703 struct mt9v022 *mt9v022 = to_mt9v022(client);
704 unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
Guennadi Liakhovetski443f4832011-09-09 07:06:50 -0300705 unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300706 int ret;
707 u16 pixclk = 0;
708
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300709 if (icl->set_bus_param) {
710 ret = icl->set_bus_param(icl, 1 << (bps - 1));
711 if (ret)
712 return ret;
713 } else if (bps != 10) {
714 /*
715 * Without board specific bus width settings we only support the
716 * sensors native bus width
717 */
718 return -EINVAL;
719 }
720
721 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
722 pixclk |= 0x10;
723
724 if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
725 pixclk |= 0x1;
726
727 if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
728 pixclk |= 0x2;
729
730 ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
731 if (ret < 0)
732 return ret;
733
734 if (!(flags & V4L2_MBUS_MASTER))
735 mt9v022->chip_control &= ~0x8;
736
737 ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
738 if (ret < 0)
739 return ret;
740
741 dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
742 pixclk, mt9v022->chip_control);
743
744 return 0;
745}
746
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300747static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
748 .s_stream = mt9v022_s_stream,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300749 .s_mbus_fmt = mt9v022_s_fmt,
750 .g_mbus_fmt = mt9v022_g_fmt,
751 .try_mbus_fmt = mt9v022_try_fmt,
Guennadi Liakhovetski08590b92009-08-25 11:46:54 -0300752 .s_crop = mt9v022_s_crop,
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300753 .g_crop = mt9v022_g_crop,
754 .cropcap = mt9v022_cropcap,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300755 .enum_mbus_fmt = mt9v022_enum_fmt,
Guennadi Liakhovetskie8e2c702011-07-27 05:53:33 -0300756 .g_mbus_config = mt9v022_g_mbus_config,
757 .s_mbus_config = mt9v022_s_mbus_config,
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300758};
759
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300760static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
761 .g_skip_top_lines = mt9v022_g_skip_top_lines,
762};
763
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300764static struct v4l2_subdev_ops mt9v022_subdev_ops = {
765 .core = &mt9v022_subdev_core_ops,
766 .video = &mt9v022_subdev_video_ops,
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300767 .sensor = &mt9v022_subdev_sensor_ops,
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300768};
769
Jean Delvared2653e92008-04-29 23:11:39 +0200770static int mt9v022_probe(struct i2c_client *client,
771 const struct i2c_device_id *did)
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300772{
773 struct mt9v022 *mt9v022;
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300774 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300775 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300776 int ret;
777
778 if (!icl) {
779 dev_err(&client->dev, "MT9V022 driver needs platform data\n");
780 return -EINVAL;
781 }
782
783 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
784 dev_warn(&adapter->dev,
785 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
786 return -EIO;
787 }
788
789 mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
790 if (!mt9v022)
791 return -ENOMEM;
792
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300793 v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300794 v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
795 v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
796 V4L2_CID_VFLIP, 0, 1, 1, 0);
797 v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
798 V4L2_CID_HFLIP, 0, 1, 1, 0);
799 mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
800 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
801 mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
802 V4L2_CID_GAIN, 0, 127, 1, 64);
803
804 /*
805 * Simulated autoexposure. If enabled, we calculate shutter width
806 * ourselves in the driver based on vertical blanking and frame width
807 */
808 mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
809 &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
810 V4L2_EXPOSURE_AUTO);
811 mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
812 V4L2_CID_EXPOSURE, 1, 255, 1, 255);
813
814 mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
815 if (mt9v022->hdl.error) {
816 int err = mt9v022->hdl.error;
817
818 kfree(mt9v022);
819 return err;
820 }
821 v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
822 V4L2_EXPOSURE_MANUAL, true);
823 v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300824
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300825 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300826
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300827 /*
828 * MT9V022 _really_ corrupts the first read out line.
829 * TODO: verify on i.MX31
830 */
Guennadi Liakhovetski32536102009-12-11 11:14:46 -0300831 mt9v022->y_skip_top = 1;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300832 mt9v022->rect.left = MT9V022_COLUMN_SKIP;
833 mt9v022->rect.top = MT9V022_ROW_SKIP;
834 mt9v022->rect.width = MT9V022_MAX_WIDTH;
835 mt9v022->rect.height = MT9V022_MAX_HEIGHT;
836
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300837 ret = mt9v022_video_probe(client);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300838 if (ret) {
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300839 v4l2_ctrl_handler_free(&mt9v022->hdl);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300840 kfree(mt9v022);
841 }
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300842
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300843 return ret;
844}
845
846static int mt9v022_remove(struct i2c_client *client)
847{
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300848 struct mt9v022 *mt9v022 = to_mt9v022(client);
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300849 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300850
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300851 v4l2_device_unregister_subdev(&mt9v022->subdev);
Guennadi Liakhovetski14178aa2011-09-21 15:16:30 -0300852 if (icl->free_bus)
853 icl->free_bus(icl);
Hans Verkuilab7b50a2011-09-07 05:22:39 -0300854 v4l2_ctrl_handler_free(&mt9v022->hdl);
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300855 kfree(mt9v022);
856
857 return 0;
858}
Jean Delvare3760f732008-04-29 23:11:40 +0200859static const struct i2c_device_id mt9v022_id[] = {
860 { "mt9v022", 0 },
861 { }
862};
863MODULE_DEVICE_TABLE(i2c, mt9v022_id);
864
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300865static struct i2c_driver mt9v022_i2c_driver = {
866 .driver = {
867 .name = "mt9v022",
868 },
869 .probe = mt9v022_probe,
870 .remove = mt9v022_remove,
Jean Delvare3760f732008-04-29 23:11:40 +0200871 .id_table = mt9v022_id,
Guennadi Liakhovetski7397bfbe2008-04-22 14:42:04 -0300872};
873
874static int __init mt9v022_mod_init(void)
875{
876 return i2c_add_driver(&mt9v022_i2c_driver);
877}
878
879static void __exit mt9v022_mod_exit(void)
880{
881 i2c_del_driver(&mt9v022_i2c_driver);
882}
883
884module_init(mt9v022_mod_init);
885module_exit(mt9v022_mod_exit);
886
887MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
888MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
889MODULE_LICENSE("GPL");