diff options
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 434 |
1 files changed, 255 insertions, 179 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index dbdcc86ae50d..995607f9d3ba 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -14,13 +14,13 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | 16 | ||
17 | #include <media/v4l2-common.h> | 17 | #include <media/v4l2-subdev.h> |
18 | #include <media/v4l2-chip-ident.h> | 18 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | 20 | ||
21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
22 | * The platform has to define i2c_board_info | 22 | * The platform has to define ctruct i2c_board_info objects and link to them |
23 | * and call i2c_register_board_info() */ | 23 | * from struct soc_camera_link */ |
24 | 24 | ||
25 | static char *sensor_type; | 25 | static char *sensor_type; |
26 | module_param(sensor_type, charp, S_IRUGO); | 26 | module_param(sensor_type, charp, S_IRUGO); |
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
45 | #define MT9V022_PIXEL_OPERATION_MODE 0x0f | 45 | #define MT9V022_PIXEL_OPERATION_MODE 0x0f |
46 | #define MT9V022_LED_OUT_CONTROL 0x1b | 46 | #define MT9V022_LED_OUT_CONTROL 0x1b |
47 | #define MT9V022_ADC_MODE_CONTROL 0x1c | 47 | #define MT9V022_ADC_MODE_CONTROL 0x1c |
48 | #define MT9V022_ANALOG_GAIN 0x34 | 48 | #define MT9V022_ANALOG_GAIN 0x35 |
49 | #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 | 49 | #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 |
50 | #define MT9V022_PIXCLK_FV_LV 0x74 | 50 | #define MT9V022_PIXCLK_FV_LV 0x74 |
51 | #define MT9V022_DIGITAL_TEST_PATTERN 0x7f | 51 | #define MT9V022_DIGITAL_TEST_PATTERN 0x7f |
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
55 | /* Progressive scan, master, defaults */ | 55 | /* Progressive scan, master, defaults */ |
56 | #define MT9V022_CHIP_CONTROL_DEFAULT 0x188 | 56 | #define MT9V022_CHIP_CONTROL_DEFAULT 0x188 |
57 | 57 | ||
58 | #define MT9V022_MAX_WIDTH 752 | ||
59 | #define MT9V022_MAX_HEIGHT 480 | ||
60 | #define MT9V022_MIN_WIDTH 48 | ||
61 | #define MT9V022_MIN_HEIGHT 32 | ||
62 | #define MT9V022_COLUMN_SKIP 1 | ||
63 | #define MT9V022_ROW_SKIP 4 | ||
64 | |||
58 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { | 65 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { |
59 | /* Order important: first natively supported, | 66 | /* Order important: first natively supported, |
60 | * second supported with a GPIO extender */ | 67 | * second supported with a GPIO extender */ |
@@ -85,12 +92,18 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { | |||
85 | }; | 92 | }; |
86 | 93 | ||
87 | struct mt9v022 { | 94 | struct mt9v022 { |
88 | struct i2c_client *client; | 95 | struct v4l2_subdev subdev; |
89 | struct soc_camera_device icd; | 96 | struct v4l2_rect rect; /* Sensor window */ |
97 | __u32 fourcc; | ||
90 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 98 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
91 | u16 chip_control; | 99 | u16 chip_control; |
92 | }; | 100 | }; |
93 | 101 | ||
102 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) | ||
103 | { | ||
104 | return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); | ||
105 | } | ||
106 | |||
94 | static int reg_read(struct i2c_client *client, const u8 reg) | 107 | static int reg_read(struct i2c_client *client, const u8 reg) |
95 | { | 108 | { |
96 | s32 data = i2c_smbus_read_word_data(client, reg); | 109 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -125,29 +138,11 @@ static int reg_clear(struct i2c_client *client, const u8 reg, | |||
125 | return reg_write(client, reg, ret & ~data); | 138 | return reg_write(client, reg, ret & ~data); |
126 | } | 139 | } |
127 | 140 | ||
128 | static int mt9v022_init(struct soc_camera_device *icd) | 141 | static int mt9v022_init(struct i2c_client *client) |
129 | { | 142 | { |
130 | struct i2c_client *client = to_i2c_client(icd->control); | 143 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
131 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
132 | struct soc_camera_link *icl = client->dev.platform_data; | ||
133 | int ret; | 144 | int ret; |
134 | 145 | ||
135 | if (icl->power) { | ||
136 | ret = icl->power(&client->dev, 1); | ||
137 | if (ret < 0) { | ||
138 | dev_err(icd->vdev->parent, | ||
139 | "Platform failed to power-on the camera.\n"); | ||
140 | return ret; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * The camera could have been already on, we hard-reset it additionally, | ||
146 | * if available. Soft reset is done in video_probe(). | ||
147 | */ | ||
148 | if (icl->reset) | ||
149 | icl->reset(&client->dev); | ||
150 | |||
151 | /* Almost the default mode: master, parallel, simultaneous, and an | 146 | /* Almost the default mode: master, parallel, simultaneous, and an |
152 | * undocumented bit 0x200, which is present in table 7, but not in 8, | 147 | * undocumented bit 0x200, which is present in table 7, but not in 8, |
153 | * plus snapshot mode to disable scan for now */ | 148 | * plus snapshot mode to disable scan for now */ |
@@ -161,6 +156,10 @@ static int mt9v022_init(struct soc_camera_device *icd) | |||
161 | /* AEC, AGC on */ | 156 | /* AEC, AGC on */ |
162 | ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); | 157 | ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); |
163 | if (!ret) | 158 | if (!ret) |
159 | ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); | ||
160 | if (!ret) | ||
161 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); | ||
162 | if (!ret) | ||
164 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); | 163 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); |
165 | if (!ret) | 164 | if (!ret) |
166 | /* default - auto */ | 165 | /* default - auto */ |
@@ -171,37 +170,19 @@ static int mt9v022_init(struct soc_camera_device *icd) | |||
171 | return ret; | 170 | return ret; |
172 | } | 171 | } |
173 | 172 | ||
174 | static int mt9v022_release(struct soc_camera_device *icd) | 173 | static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) |
175 | { | 174 | { |
176 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 175 | struct i2c_client *client = sd->priv; |
177 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | 176 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
178 | |||
179 | if (icl->power) | ||
180 | icl->power(&mt9v022->client->dev, 0); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | 177 | ||
185 | static int mt9v022_start_capture(struct soc_camera_device *icd) | 178 | if (enable) |
186 | { | 179 | /* Switch to master "normal" mode */ |
187 | struct i2c_client *client = to_i2c_client(icd->control); | 180 | mt9v022->chip_control &= ~0x10; |
188 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 181 | else |
189 | /* Switch to master "normal" mode */ | 182 | /* Switch to snapshot mode */ |
190 | mt9v022->chip_control &= ~0x10; | 183 | mt9v022->chip_control |= 0x10; |
191 | if (reg_write(client, MT9V022_CHIP_CONTROL, | ||
192 | mt9v022->chip_control) < 0) | ||
193 | return -EIO; | ||
194 | return 0; | ||
195 | } | ||
196 | 184 | ||
197 | static int mt9v022_stop_capture(struct soc_camera_device *icd) | 185 | if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) |
198 | { | ||
199 | struct i2c_client *client = to_i2c_client(icd->control); | ||
200 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
201 | /* Switch to snapshot mode */ | ||
202 | mt9v022->chip_control |= 0x10; | ||
203 | if (reg_write(client, MT9V022_CHIP_CONTROL, | ||
204 | mt9v022->chip_control) < 0) | ||
205 | return -EIO; | 186 | return -EIO; |
206 | return 0; | 187 | return 0; |
207 | } | 188 | } |
@@ -209,9 +190,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) | |||
209 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | 190 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, |
210 | unsigned long flags) | 191 | unsigned long flags) |
211 | { | 192 | { |
212 | struct i2c_client *client = to_i2c_client(icd->control); | 193 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
213 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 194 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
214 | struct soc_camera_link *icl = client->dev.platform_data; | 195 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
215 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | 196 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; |
216 | int ret; | 197 | int ret; |
217 | u16 pixclk = 0; | 198 | u16 pixclk = 0; |
@@ -255,7 +236,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
255 | if (ret < 0) | 236 | if (ret < 0) |
256 | return ret; | 237 | return ret; |
257 | 238 | ||
258 | dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | 239 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", |
259 | pixclk, mt9v022->chip_control); | 240 | pixclk, mt9v022->chip_control); |
260 | 241 | ||
261 | return 0; | 242 | return 0; |
@@ -263,8 +244,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
263 | 244 | ||
264 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | 245 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) |
265 | { | 246 | { |
266 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 247 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
267 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | ||
268 | unsigned int width_flag; | 248 | unsigned int width_flag; |
269 | 249 | ||
270 | if (icl->query_bus_param) | 250 | if (icl->query_bus_param) |
@@ -280,60 +260,121 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | |||
280 | width_flag; | 260 | width_flag; |
281 | } | 261 | } |
282 | 262 | ||
283 | static int mt9v022_set_crop(struct soc_camera_device *icd, | 263 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
284 | struct v4l2_rect *rect) | ||
285 | { | 264 | { |
286 | struct i2c_client *client = to_i2c_client(icd->control); | 265 | struct i2c_client *client = sd->priv; |
266 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
267 | struct v4l2_rect rect = a->c; | ||
268 | struct soc_camera_device *icd = client->dev.platform_data; | ||
287 | int ret; | 269 | int ret; |
288 | 270 | ||
271 | /* Bayer format - even size lengths */ | ||
272 | if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 || | ||
273 | mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) { | ||
274 | rect.width = ALIGN(rect.width, 2); | ||
275 | rect.height = ALIGN(rect.height, 2); | ||
276 | /* Let the user play with the starting pixel */ | ||
277 | } | ||
278 | |||
279 | soc_camera_limit_side(&rect.left, &rect.width, | ||
280 | MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); | ||
281 | |||
282 | soc_camera_limit_side(&rect.top, &rect.height, | ||
283 | MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); | ||
284 | |||
289 | /* Like in example app. Contradicts the datasheet though */ | 285 | /* Like in example app. Contradicts the datasheet though */ |
290 | ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); | 286 | ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); |
291 | if (ret >= 0) { | 287 | if (ret >= 0) { |
292 | if (ret & 1) /* Autoexposure */ | 288 | if (ret & 1) /* Autoexposure */ |
293 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, | 289 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, |
294 | rect->height + icd->y_skip_top + 43); | 290 | rect.height + icd->y_skip_top + 43); |
295 | else | 291 | else |
296 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 292 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
297 | rect->height + icd->y_skip_top + 43); | 293 | rect.height + icd->y_skip_top + 43); |
298 | } | 294 | } |
299 | /* Setup frame format: defaults apart from width and height */ | 295 | /* Setup frame format: defaults apart from width and height */ |
300 | if (!ret) | 296 | if (!ret) |
301 | ret = reg_write(client, MT9V022_COLUMN_START, rect->left); | 297 | ret = reg_write(client, MT9V022_COLUMN_START, rect.left); |
302 | if (!ret) | 298 | if (!ret) |
303 | ret = reg_write(client, MT9V022_ROW_START, rect->top); | 299 | ret = reg_write(client, MT9V022_ROW_START, rect.top); |
304 | if (!ret) | 300 | if (!ret) |
305 | /* Default 94, Phytec driver says: | 301 | /* Default 94, Phytec driver says: |
306 | * "width + horizontal blank >= 660" */ | 302 | * "width + horizontal blank >= 660" */ |
307 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, | 303 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, |
308 | rect->width > 660 - 43 ? 43 : | 304 | rect.width > 660 - 43 ? 43 : |
309 | 660 - rect->width); | 305 | 660 - rect.width); |
310 | if (!ret) | 306 | if (!ret) |
311 | ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); | 307 | ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); |
312 | if (!ret) | 308 | if (!ret) |
313 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); | 309 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); |
314 | if (!ret) | 310 | if (!ret) |
315 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, | 311 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, |
316 | rect->height + icd->y_skip_top); | 312 | rect.height + icd->y_skip_top); |
317 | 313 | ||
318 | if (ret < 0) | 314 | if (ret < 0) |
319 | return ret; | 315 | return ret; |
320 | 316 | ||
321 | dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height); | 317 | dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height); |
318 | |||
319 | mt9v022->rect = rect; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
325 | { | ||
326 | struct i2c_client *client = sd->priv; | ||
327 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
328 | |||
329 | a->c = mt9v022->rect; | ||
330 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
322 | 331 | ||
323 | return 0; | 332 | return 0; |
324 | } | 333 | } |
325 | 334 | ||
326 | static int mt9v022_set_fmt(struct soc_camera_device *icd, | 335 | static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
327 | struct v4l2_format *f) | ||
328 | { | 336 | { |
329 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 337 | a->bounds.left = MT9V022_COLUMN_SKIP; |
338 | a->bounds.top = MT9V022_ROW_SKIP; | ||
339 | a->bounds.width = MT9V022_MAX_WIDTH; | ||
340 | a->bounds.height = MT9V022_MAX_HEIGHT; | ||
341 | a->defrect = a->bounds; | ||
342 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
343 | a->pixelaspect.numerator = 1; | ||
344 | a->pixelaspect.denominator = 1; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
350 | { | ||
351 | struct i2c_client *client = sd->priv; | ||
352 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
330 | struct v4l2_pix_format *pix = &f->fmt.pix; | 353 | struct v4l2_pix_format *pix = &f->fmt.pix; |
331 | struct v4l2_rect rect = { | 354 | |
332 | .left = icd->x_current, | 355 | pix->width = mt9v022->rect.width; |
333 | .top = icd->y_current, | 356 | pix->height = mt9v022->rect.height; |
334 | .width = pix->width, | 357 | pix->pixelformat = mt9v022->fourcc; |
335 | .height = pix->height, | 358 | pix->field = V4L2_FIELD_NONE; |
359 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
365 | { | ||
366 | struct i2c_client *client = sd->priv; | ||
367 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
368 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
369 | struct v4l2_crop a = { | ||
370 | .c = { | ||
371 | .left = mt9v022->rect.left, | ||
372 | .top = mt9v022->rect.top, | ||
373 | .width = pix->width, | ||
374 | .height = pix->height, | ||
375 | }, | ||
336 | }; | 376 | }; |
377 | int ret; | ||
337 | 378 | ||
338 | /* The caller provides a supported format, as verified per call to | 379 | /* The caller provides a supported format, as verified per call to |
339 | * icd->try_fmt(), datawidth is from our supported format list */ | 380 | * icd->try_fmt(), datawidth is from our supported format list */ |
@@ -356,30 +397,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd, | |||
356 | } | 397 | } |
357 | 398 | ||
358 | /* No support for scaling on this camera, just crop. */ | 399 | /* No support for scaling on this camera, just crop. */ |
359 | return mt9v022_set_crop(icd, &rect); | 400 | ret = mt9v022_s_crop(sd, &a); |
401 | if (!ret) { | ||
402 | pix->width = mt9v022->rect.width; | ||
403 | pix->height = mt9v022->rect.height; | ||
404 | mt9v022->fourcc = pix->pixelformat; | ||
405 | } | ||
406 | |||
407 | return ret; | ||
360 | } | 408 | } |
361 | 409 | ||
362 | static int mt9v022_try_fmt(struct soc_camera_device *icd, | 410 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
363 | struct v4l2_format *f) | ||
364 | { | 411 | { |
412 | struct i2c_client *client = sd->priv; | ||
413 | struct soc_camera_device *icd = client->dev.platform_data; | ||
365 | struct v4l2_pix_format *pix = &f->fmt.pix; | 414 | struct v4l2_pix_format *pix = &f->fmt.pix; |
415 | int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | ||
416 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | ||
366 | 417 | ||
367 | v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */, | 418 | v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH, |
368 | &pix->height, 32 + icd->y_skip_top, | 419 | MT9V022_MAX_WIDTH, align, |
369 | 480 + icd->y_skip_top, 0, 0); | 420 | &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top, |
421 | MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0); | ||
370 | 422 | ||
371 | return 0; | 423 | return 0; |
372 | } | 424 | } |
373 | 425 | ||
374 | static int mt9v022_get_chip_id(struct soc_camera_device *icd, | 426 | static int mt9v022_g_chip_ident(struct v4l2_subdev *sd, |
375 | struct v4l2_dbg_chip_ident *id) | 427 | struct v4l2_dbg_chip_ident *id) |
376 | { | 428 | { |
377 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 429 | struct i2c_client *client = sd->priv; |
430 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
378 | 431 | ||
379 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 432 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
380 | return -EINVAL; | 433 | return -EINVAL; |
381 | 434 | ||
382 | if (id->match.addr != mt9v022->client->addr) | 435 | if (id->match.addr != client->addr) |
383 | return -ENODEV; | 436 | return -ENODEV; |
384 | 437 | ||
385 | id->ident = mt9v022->model; | 438 | id->ident = mt9v022->model; |
@@ -389,10 +442,10 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd, | |||
389 | } | 442 | } |
390 | 443 | ||
391 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 444 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
392 | static int mt9v022_get_register(struct soc_camera_device *icd, | 445 | static int mt9v022_g_register(struct v4l2_subdev *sd, |
393 | struct v4l2_dbg_register *reg) | 446 | struct v4l2_dbg_register *reg) |
394 | { | 447 | { |
395 | struct i2c_client *client = to_i2c_client(icd->control); | 448 | struct i2c_client *client = sd->priv; |
396 | 449 | ||
397 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 450 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
398 | return -EINVAL; | 451 | return -EINVAL; |
@@ -409,10 +462,10 @@ static int mt9v022_get_register(struct soc_camera_device *icd, | |||
409 | return 0; | 462 | return 0; |
410 | } | 463 | } |
411 | 464 | ||
412 | static int mt9v022_set_register(struct soc_camera_device *icd, | 465 | static int mt9v022_s_register(struct v4l2_subdev *sd, |
413 | struct v4l2_dbg_register *reg) | 466 | struct v4l2_dbg_register *reg) |
414 | { | 467 | { |
415 | struct i2c_client *client = to_i2c_client(icd->control); | 468 | struct i2c_client *client = sd->priv; |
416 | 469 | ||
417 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 470 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
418 | return -EINVAL; | 471 | return -EINVAL; |
@@ -481,41 +534,22 @@ static const struct v4l2_queryctrl mt9v022_controls[] = { | |||
481 | } | 534 | } |
482 | }; | 535 | }; |
483 | 536 | ||
484 | static int mt9v022_video_probe(struct soc_camera_device *); | ||
485 | static void mt9v022_video_remove(struct soc_camera_device *); | ||
486 | static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
487 | static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
488 | |||
489 | static struct soc_camera_ops mt9v022_ops = { | 537 | static struct soc_camera_ops mt9v022_ops = { |
490 | .owner = THIS_MODULE, | ||
491 | .probe = mt9v022_video_probe, | ||
492 | .remove = mt9v022_video_remove, | ||
493 | .init = mt9v022_init, | ||
494 | .release = mt9v022_release, | ||
495 | .start_capture = mt9v022_start_capture, | ||
496 | .stop_capture = mt9v022_stop_capture, | ||
497 | .set_crop = mt9v022_set_crop, | ||
498 | .set_fmt = mt9v022_set_fmt, | ||
499 | .try_fmt = mt9v022_try_fmt, | ||
500 | .set_bus_param = mt9v022_set_bus_param, | 538 | .set_bus_param = mt9v022_set_bus_param, |
501 | .query_bus_param = mt9v022_query_bus_param, | 539 | .query_bus_param = mt9v022_query_bus_param, |
502 | .controls = mt9v022_controls, | 540 | .controls = mt9v022_controls, |
503 | .num_controls = ARRAY_SIZE(mt9v022_controls), | 541 | .num_controls = ARRAY_SIZE(mt9v022_controls), |
504 | .get_control = mt9v022_get_control, | ||
505 | .set_control = mt9v022_set_control, | ||
506 | .get_chip_id = mt9v022_get_chip_id, | ||
507 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
508 | .get_register = mt9v022_get_register, | ||
509 | .set_register = mt9v022_set_register, | ||
510 | #endif | ||
511 | }; | 542 | }; |
512 | 543 | ||
513 | static int mt9v022_get_control(struct soc_camera_device *icd, | 544 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
514 | struct v4l2_control *ctrl) | ||
515 | { | 545 | { |
516 | struct i2c_client *client = to_i2c_client(icd->control); | 546 | struct i2c_client *client = sd->priv; |
547 | const struct v4l2_queryctrl *qctrl; | ||
548 | unsigned long range; | ||
517 | int data; | 549 | int data; |
518 | 550 | ||
551 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
552 | |||
519 | switch (ctrl->id) { | 553 | switch (ctrl->id) { |
520 | case V4L2_CID_VFLIP: | 554 | case V4L2_CID_VFLIP: |
521 | data = reg_read(client, MT9V022_READ_MODE); | 555 | data = reg_read(client, MT9V022_READ_MODE); |
@@ -541,19 +575,35 @@ static int mt9v022_get_control(struct soc_camera_device *icd, | |||
541 | return -EIO; | 575 | return -EIO; |
542 | ctrl->value = !!(data & 0x2); | 576 | ctrl->value = !!(data & 0x2); |
543 | break; | 577 | break; |
578 | case V4L2_CID_GAIN: | ||
579 | data = reg_read(client, MT9V022_ANALOG_GAIN); | ||
580 | if (data < 0) | ||
581 | return -EIO; | ||
582 | |||
583 | range = qctrl->maximum - qctrl->minimum; | ||
584 | ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; | ||
585 | |||
586 | break; | ||
587 | case V4L2_CID_EXPOSURE: | ||
588 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); | ||
589 | if (data < 0) | ||
590 | return -EIO; | ||
591 | |||
592 | range = qctrl->maximum - qctrl->minimum; | ||
593 | ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; | ||
594 | |||
595 | break; | ||
544 | } | 596 | } |
545 | return 0; | 597 | return 0; |
546 | } | 598 | } |
547 | 599 | ||
548 | static int mt9v022_set_control(struct soc_camera_device *icd, | 600 | static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
549 | struct v4l2_control *ctrl) | ||
550 | { | 601 | { |
551 | int data; | 602 | int data; |
552 | struct i2c_client *client = to_i2c_client(icd->control); | 603 | struct i2c_client *client = sd->priv; |
553 | const struct v4l2_queryctrl *qctrl; | 604 | const struct v4l2_queryctrl *qctrl; |
554 | 605 | ||
555 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | 606 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); |
556 | |||
557 | if (!qctrl) | 607 | if (!qctrl) |
558 | return -EINVAL; | 608 | return -EINVAL; |
559 | 609 | ||
@@ -580,12 +630,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
580 | return -EINVAL; | 630 | return -EINVAL; |
581 | else { | 631 | else { |
582 | unsigned long range = qctrl->maximum - qctrl->minimum; | 632 | unsigned long range = qctrl->maximum - qctrl->minimum; |
583 | /* Datasheet says 16 to 64. autogain only works properly | 633 | /* Valid values 16 to 64, 32 to 64 must be even. */ |
584 | * after setting gain to maximum 14. Larger values | ||
585 | * produce "white fly" noise effect. On the whole, | ||
586 | * manually setting analog gain does no good. */ | ||
587 | unsigned long gain = ((ctrl->value - qctrl->minimum) * | 634 | unsigned long gain = ((ctrl->value - qctrl->minimum) * |
588 | 10 + range / 2) / range + 4; | 635 | 48 + range / 2) / range + 16; |
589 | if (gain >= 32) | 636 | if (gain >= 32) |
590 | gain &= ~1; | 637 | gain &= ~1; |
591 | /* The user wants to set gain manually, hope, she | 638 | /* The user wants to set gain manually, hope, she |
@@ -594,11 +641,10 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
594 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 641 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
595 | return -EIO; | 642 | return -EIO; |
596 | 643 | ||
597 | dev_info(&icd->dev, "Setting gain from %d to %lu\n", | 644 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", |
598 | reg_read(client, MT9V022_ANALOG_GAIN), gain); | 645 | reg_read(client, MT9V022_ANALOG_GAIN), gain); |
599 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) | 646 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) |
600 | return -EIO; | 647 | return -EIO; |
601 | icd->gain = ctrl->value; | ||
602 | } | 648 | } |
603 | break; | 649 | break; |
604 | case V4L2_CID_EXPOSURE: | 650 | case V4L2_CID_EXPOSURE: |
@@ -615,13 +661,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
615 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 661 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) |
616 | return -EIO; | 662 | return -EIO; |
617 | 663 | ||
618 | dev_dbg(&icd->dev, "Shutter width from %d to %lu\n", | 664 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", |
619 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), | 665 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), |
620 | shutter); | 666 | shutter); |
621 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 667 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
622 | shutter) < 0) | 668 | shutter) < 0) |
623 | return -EIO; | 669 | return -EIO; |
624 | icd->exposure = ctrl->value; | ||
625 | } | 670 | } |
626 | break; | 671 | break; |
627 | case V4L2_CID_AUTOGAIN: | 672 | case V4L2_CID_AUTOGAIN: |
@@ -646,11 +691,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
646 | 691 | ||
647 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 692 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
648 | * this wasn't our capture interface, so, we wait for the right one */ | 693 | * this wasn't our capture interface, so, we wait for the right one */ |
649 | static int mt9v022_video_probe(struct soc_camera_device *icd) | 694 | static int mt9v022_video_probe(struct soc_camera_device *icd, |
695 | struct i2c_client *client) | ||
650 | { | 696 | { |
651 | struct i2c_client *client = to_i2c_client(icd->control); | 697 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
652 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 698 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
653 | struct soc_camera_link *icl = client->dev.platform_data; | ||
654 | s32 data; | 699 | s32 data; |
655 | int ret; | 700 | int ret; |
656 | unsigned long flags; | 701 | unsigned long flags; |
@@ -665,7 +710,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
665 | /* must be 0x1311 or 0x1313 */ | 710 | /* must be 0x1311 or 0x1313 */ |
666 | if (data != 0x1311 && data != 0x1313) { | 711 | if (data != 0x1311 && data != 0x1313) { |
667 | ret = -ENODEV; | 712 | ret = -ENODEV; |
668 | dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n", | 713 | dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", |
669 | data); | 714 | data); |
670 | goto ei2c; | 715 | goto ei2c; |
671 | } | 716 | } |
@@ -677,7 +722,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
677 | /* 15 clock cycles */ | 722 | /* 15 clock cycles */ |
678 | udelay(200); | 723 | udelay(200); |
679 | if (reg_read(client, MT9V022_RESET)) { | 724 | if (reg_read(client, MT9V022_RESET)) { |
680 | dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); | 725 | dev_err(&client->dev, "Resetting MT9V022 failed!\n"); |
726 | if (ret > 0) | ||
727 | ret = -EIO; | ||
681 | goto ei2c; | 728 | goto ei2c; |
682 | } | 729 | } |
683 | 730 | ||
@@ -694,7 +741,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
694 | } | 741 | } |
695 | 742 | ||
696 | if (ret < 0) | 743 | if (ret < 0) |
697 | goto eisis; | 744 | goto ei2c; |
698 | 745 | ||
699 | icd->num_formats = 0; | 746 | icd->num_formats = 0; |
700 | 747 | ||
@@ -716,42 +763,70 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
716 | if (flags & SOCAM_DATAWIDTH_8) | 763 | if (flags & SOCAM_DATAWIDTH_8) |
717 | icd->num_formats++; | 764 | icd->num_formats++; |
718 | 765 | ||
719 | ret = soc_camera_video_start(icd); | 766 | mt9v022->fourcc = icd->formats->fourcc; |
720 | if (ret < 0) | ||
721 | goto eisis; | ||
722 | 767 | ||
723 | dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", | 768 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", |
724 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? | 769 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? |
725 | "monochrome" : "colour"); | 770 | "monochrome" : "colour"); |
726 | 771 | ||
727 | return 0; | 772 | ret = mt9v022_init(client); |
773 | if (ret < 0) | ||
774 | dev_err(&client->dev, "Failed to initialise the camera\n"); | ||
728 | 775 | ||
729 | eisis: | ||
730 | ei2c: | 776 | ei2c: |
731 | return ret; | 777 | return ret; |
732 | } | 778 | } |
733 | 779 | ||
734 | static void mt9v022_video_remove(struct soc_camera_device *icd) | 780 | static void mt9v022_video_remove(struct soc_camera_device *icd) |
735 | { | 781 | { |
736 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 782 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
737 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | ||
738 | 783 | ||
739 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, | 784 | dev_dbg(&icd->dev, "Video removed: %p, %p\n", |
740 | icd->dev.parent, icd->vdev); | 785 | icd->dev.parent, icd->vdev); |
741 | soc_camera_video_stop(icd); | ||
742 | if (icl->free_bus) | 786 | if (icl->free_bus) |
743 | icl->free_bus(icl); | 787 | icl->free_bus(icl); |
744 | } | 788 | } |
745 | 789 | ||
790 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | ||
791 | .g_ctrl = mt9v022_g_ctrl, | ||
792 | .s_ctrl = mt9v022_s_ctrl, | ||
793 | .g_chip_ident = mt9v022_g_chip_ident, | ||
794 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
795 | .g_register = mt9v022_g_register, | ||
796 | .s_register = mt9v022_s_register, | ||
797 | #endif | ||
798 | }; | ||
799 | |||
800 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | ||
801 | .s_stream = mt9v022_s_stream, | ||
802 | .s_fmt = mt9v022_s_fmt, | ||
803 | .g_fmt = mt9v022_g_fmt, | ||
804 | .try_fmt = mt9v022_try_fmt, | ||
805 | .s_crop = mt9v022_s_crop, | ||
806 | .g_crop = mt9v022_g_crop, | ||
807 | .cropcap = mt9v022_cropcap, | ||
808 | }; | ||
809 | |||
810 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { | ||
811 | .core = &mt9v022_subdev_core_ops, | ||
812 | .video = &mt9v022_subdev_video_ops, | ||
813 | }; | ||
814 | |||
746 | static int mt9v022_probe(struct i2c_client *client, | 815 | static int mt9v022_probe(struct i2c_client *client, |
747 | const struct i2c_device_id *did) | 816 | const struct i2c_device_id *did) |
748 | { | 817 | { |
749 | struct mt9v022 *mt9v022; | 818 | struct mt9v022 *mt9v022; |
750 | struct soc_camera_device *icd; | 819 | struct soc_camera_device *icd = client->dev.platform_data; |
751 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 820 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
752 | struct soc_camera_link *icl = client->dev.platform_data; | 821 | struct soc_camera_link *icl; |
753 | int ret; | 822 | int ret; |
754 | 823 | ||
824 | if (!icd) { | ||
825 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
826 | return -EINVAL; | ||
827 | } | ||
828 | |||
829 | icl = to_soc_camera_link(icd); | ||
755 | if (!icl) { | 830 | if (!icl) { |
756 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 831 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
757 | return -EINVAL; | 832 | return -EINVAL; |
@@ -767,40 +842,41 @@ static int mt9v022_probe(struct i2c_client *client, | |||
767 | if (!mt9v022) | 842 | if (!mt9v022) |
768 | return -ENOMEM; | 843 | return -ENOMEM; |
769 | 844 | ||
845 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | ||
846 | |||
770 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 847 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
771 | mt9v022->client = client; | ||
772 | i2c_set_clientdata(client, mt9v022); | ||
773 | |||
774 | icd = &mt9v022->icd; | ||
775 | icd->ops = &mt9v022_ops; | ||
776 | icd->control = &client->dev; | ||
777 | icd->x_min = 1; | ||
778 | icd->y_min = 4; | ||
779 | icd->x_current = 1; | ||
780 | icd->y_current = 4; | ||
781 | icd->width_min = 48; | ||
782 | icd->width_max = 752; | ||
783 | icd->height_min = 32; | ||
784 | icd->height_max = 480; | ||
785 | icd->y_skip_top = 1; | ||
786 | icd->iface = icl->bus_id; | ||
787 | |||
788 | ret = soc_camera_device_register(icd); | ||
789 | if (ret) | ||
790 | goto eisdr; | ||
791 | 848 | ||
792 | return 0; | 849 | icd->ops = &mt9v022_ops; |
850 | /* | ||
851 | * MT9V022 _really_ corrupts the first read out line. | ||
852 | * TODO: verify on i.MX31 | ||
853 | */ | ||
854 | icd->y_skip_top = 1; | ||
855 | |||
856 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; | ||
857 | mt9v022->rect.top = MT9V022_ROW_SKIP; | ||
858 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | ||
859 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | ||
860 | |||
861 | ret = mt9v022_video_probe(icd, client); | ||
862 | if (ret) { | ||
863 | icd->ops = NULL; | ||
864 | i2c_set_clientdata(client, NULL); | ||
865 | kfree(mt9v022); | ||
866 | } | ||
793 | 867 | ||
794 | eisdr: | ||
795 | kfree(mt9v022); | ||
796 | return ret; | 868 | return ret; |
797 | } | 869 | } |
798 | 870 | ||
799 | static int mt9v022_remove(struct i2c_client *client) | 871 | static int mt9v022_remove(struct i2c_client *client) |
800 | { | 872 | { |
801 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | 873 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
874 | struct soc_camera_device *icd = client->dev.platform_data; | ||
802 | 875 | ||
803 | soc_camera_device_unregister(&mt9v022->icd); | 876 | icd->ops = NULL; |
877 | mt9v022_video_remove(icd); | ||
878 | i2c_set_clientdata(client, NULL); | ||
879 | client->driver = NULL; | ||
804 | kfree(mt9v022); | 880 | kfree(mt9v022); |
805 | 881 | ||
806 | return 0; | 882 | return 0; |