diff options
Diffstat (limited to 'drivers/media/video/mt9m001.c')
-rw-r--r-- | drivers/media/video/mt9m001.c | 157 |
1 files changed, 68 insertions, 89 deletions
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 1e4f269fc08b..2a73dac11d37 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -13,13 +13,13 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #include <media/v4l2-common.h> | 16 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9m001 i2c address 0x5d | 20 | /* mt9m001 i2c address 0x5d |
21 | * The platform has to define i2c_board_info | 21 | * The platform has to define ctruct i2c_board_info objects and link to them |
22 | * and call i2c_register_board_info() */ | 22 | * from struct soc_camera_link */ |
23 | 23 | ||
24 | /* mt9m001 selected register addresses */ | 24 | /* mt9m001 selected register addresses */ |
25 | #define MT9M001_CHIP_VERSION 0x00 | 25 | #define MT9M001_CHIP_VERSION 0x00 |
@@ -69,10 +69,16 @@ static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | struct mt9m001 { | 71 | struct mt9m001 { |
72 | struct v4l2_subdev subdev; | ||
72 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ | 73 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ |
73 | unsigned char autoexposure; | 74 | unsigned char autoexposure; |
74 | }; | 75 | }; |
75 | 76 | ||
77 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) | ||
78 | { | ||
79 | return container_of(i2c_get_clientdata(client), struct mt9m001, subdev); | ||
80 | } | ||
81 | |||
76 | static int reg_read(struct i2c_client *client, const u8 reg) | 82 | static int reg_read(struct i2c_client *client, const u8 reg) |
77 | { | 83 | { |
78 | s32 data = i2c_smbus_read_word_data(client, reg); | 84 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -110,32 +116,18 @@ static int reg_clear(struct i2c_client *client, const u8 reg, | |||
110 | static int mt9m001_init(struct soc_camera_device *icd) | 116 | static int mt9m001_init(struct soc_camera_device *icd) |
111 | { | 117 | { |
112 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 118 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
113 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
114 | int ret; | 119 | int ret; |
115 | 120 | ||
116 | dev_dbg(&icd->dev, "%s\n", __func__); | 121 | dev_dbg(&icd->dev, "%s\n", __func__); |
117 | 122 | ||
118 | if (icl->power) { | 123 | /* |
119 | ret = icl->power(&client->dev, 1); | 124 | * We don't know, whether platform provides reset, |
120 | if (ret < 0) { | 125 | * issue a soft reset too |
121 | dev_err(icd->vdev->parent, | 126 | */ |
122 | "Platform failed to power-on the camera.\n"); | 127 | ret = reg_write(client, MT9M001_RESET, 1); |
123 | return ret; | 128 | if (!ret) |
124 | } | 129 | ret = reg_write(client, MT9M001_RESET, 0); |
125 | } | ||
126 | |||
127 | /* The camera could have been already on, we reset it additionally */ | ||
128 | if (icl->reset) | ||
129 | ret = icl->reset(&client->dev); | ||
130 | else | ||
131 | ret = -ENODEV; | ||
132 | 130 | ||
133 | if (ret < 0) { | ||
134 | /* Either no platform reset, or platform reset failed */ | ||
135 | ret = reg_write(client, MT9M001_RESET, 1); | ||
136 | if (!ret) | ||
137 | ret = reg_write(client, MT9M001_RESET, 0); | ||
138 | } | ||
139 | /* Disable chip, synchronous option update */ | 131 | /* Disable chip, synchronous option update */ |
140 | if (!ret) | 132 | if (!ret) |
141 | ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); | 133 | ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); |
@@ -146,33 +138,19 @@ static int mt9m001_init(struct soc_camera_device *icd) | |||
146 | static int mt9m001_release(struct soc_camera_device *icd) | 138 | static int mt9m001_release(struct soc_camera_device *icd) |
147 | { | 139 | { |
148 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 140 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
149 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
150 | 141 | ||
151 | /* Disable the chip */ | 142 | /* Disable the chip */ |
152 | reg_write(client, MT9M001_OUTPUT_CONTROL, 0); | 143 | reg_write(client, MT9M001_OUTPUT_CONTROL, 0); |
153 | 144 | ||
154 | if (icl->power) | ||
155 | icl->power(&client->dev, 0); | ||
156 | |||
157 | return 0; | 145 | return 0; |
158 | } | 146 | } |
159 | 147 | ||
160 | static int mt9m001_start_capture(struct soc_camera_device *icd) | 148 | static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) |
161 | { | 149 | { |
162 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 150 | struct i2c_client *client = sd->priv; |
163 | 151 | ||
164 | /* Switch to master "normal" mode */ | 152 | /* Switch to master "normal" mode or stop sensor readout */ |
165 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) | 153 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) |
166 | return -EIO; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int mt9m001_stop_capture(struct soc_camera_device *icd) | ||
171 | { | ||
172 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
173 | |||
174 | /* Stop sensor readout */ | ||
175 | if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) | ||
176 | return -EIO; | 154 | return -EIO; |
177 | return 0; | 155 | return 0; |
178 | } | 156 | } |
@@ -220,7 +198,7 @@ static int mt9m001_set_crop(struct soc_camera_device *icd, | |||
220 | struct v4l2_rect *rect) | 198 | struct v4l2_rect *rect) |
221 | { | 199 | { |
222 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 200 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
223 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 201 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
224 | int ret; | 202 | int ret; |
225 | const u16 hblank = 9, vblank = 25; | 203 | const u16 hblank = 9, vblank = 25; |
226 | 204 | ||
@@ -257,9 +235,10 @@ static int mt9m001_set_crop(struct soc_camera_device *icd, | |||
257 | return ret; | 235 | return ret; |
258 | } | 236 | } |
259 | 237 | ||
260 | static int mt9m001_set_fmt(struct soc_camera_device *icd, | 238 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
261 | struct v4l2_format *f) | ||
262 | { | 239 | { |
240 | struct i2c_client *client = sd->priv; | ||
241 | struct soc_camera_device *icd = client->dev.platform_data; | ||
263 | struct v4l2_rect rect = { | 242 | struct v4l2_rect rect = { |
264 | .left = icd->x_current, | 243 | .left = icd->x_current, |
265 | .top = icd->y_current, | 244 | .top = icd->y_current, |
@@ -271,9 +250,10 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd, | |||
271 | return mt9m001_set_crop(icd, &rect); | 250 | return mt9m001_set_crop(icd, &rect); |
272 | } | 251 | } |
273 | 252 | ||
274 | static int mt9m001_try_fmt(struct soc_camera_device *icd, | 253 | static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
275 | struct v4l2_format *f) | ||
276 | { | 254 | { |
255 | struct i2c_client *client = sd->priv; | ||
256 | struct soc_camera_device *icd = client->dev.platform_data; | ||
277 | struct v4l2_pix_format *pix = &f->fmt.pix; | 257 | struct v4l2_pix_format *pix = &f->fmt.pix; |
278 | 258 | ||
279 | v4l_bound_align_image(&pix->width, 48, 1280, 1, | 259 | v4l_bound_align_image(&pix->width, 48, 1280, 1, |
@@ -283,11 +263,11 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd, | |||
283 | return 0; | 263 | return 0; |
284 | } | 264 | } |
285 | 265 | ||
286 | static int mt9m001_get_chip_id(struct soc_camera_device *icd, | 266 | static int mt9m001_g_chip_ident(struct v4l2_subdev *sd, |
287 | struct v4l2_dbg_chip_ident *id) | 267 | struct v4l2_dbg_chip_ident *id) |
288 | { | 268 | { |
289 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 269 | struct i2c_client *client = sd->priv; |
290 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 270 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
291 | 271 | ||
292 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 272 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
293 | return -EINVAL; | 273 | return -EINVAL; |
@@ -302,10 +282,10 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, | |||
302 | } | 282 | } |
303 | 283 | ||
304 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 284 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
305 | static int mt9m001_get_register(struct soc_camera_device *icd, | 285 | static int mt9m001_g_register(struct v4l2_subdev *sd, |
306 | struct v4l2_dbg_register *reg) | 286 | struct v4l2_dbg_register *reg) |
307 | { | 287 | { |
308 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 288 | struct i2c_client *client = sd->priv; |
309 | 289 | ||
310 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 290 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
311 | return -EINVAL; | 291 | return -EINVAL; |
@@ -322,10 +302,10 @@ static int mt9m001_get_register(struct soc_camera_device *icd, | |||
322 | return 0; | 302 | return 0; |
323 | } | 303 | } |
324 | 304 | ||
325 | static int mt9m001_set_register(struct soc_camera_device *icd, | 305 | static int mt9m001_s_register(struct v4l2_subdev *sd, |
326 | struct v4l2_dbg_register *reg) | 306 | struct v4l2_dbg_register *reg) |
327 | { | 307 | { |
328 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 308 | struct i2c_client *client = sd->priv; |
329 | 309 | ||
330 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 310 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
331 | return -EINVAL; | 311 | return -EINVAL; |
@@ -378,35 +358,20 @@ static const struct v4l2_queryctrl mt9m001_controls[] = { | |||
378 | } | 358 | } |
379 | }; | 359 | }; |
380 | 360 | ||
381 | static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
382 | static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
383 | |||
384 | static struct soc_camera_ops mt9m001_ops = { | 361 | static struct soc_camera_ops mt9m001_ops = { |
385 | .owner = THIS_MODULE, | ||
386 | .init = mt9m001_init, | 362 | .init = mt9m001_init, |
387 | .release = mt9m001_release, | 363 | .release = mt9m001_release, |
388 | .start_capture = mt9m001_start_capture, | ||
389 | .stop_capture = mt9m001_stop_capture, | ||
390 | .set_crop = mt9m001_set_crop, | 364 | .set_crop = mt9m001_set_crop, |
391 | .set_fmt = mt9m001_set_fmt, | ||
392 | .try_fmt = mt9m001_try_fmt, | ||
393 | .set_bus_param = mt9m001_set_bus_param, | 365 | .set_bus_param = mt9m001_set_bus_param, |
394 | .query_bus_param = mt9m001_query_bus_param, | 366 | .query_bus_param = mt9m001_query_bus_param, |
395 | .controls = mt9m001_controls, | 367 | .controls = mt9m001_controls, |
396 | .num_controls = ARRAY_SIZE(mt9m001_controls), | 368 | .num_controls = ARRAY_SIZE(mt9m001_controls), |
397 | .get_control = mt9m001_get_control, | ||
398 | .set_control = mt9m001_set_control, | ||
399 | .get_chip_id = mt9m001_get_chip_id, | ||
400 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
401 | .get_register = mt9m001_get_register, | ||
402 | .set_register = mt9m001_set_register, | ||
403 | #endif | ||
404 | }; | 369 | }; |
405 | 370 | ||
406 | static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 371 | static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
407 | { | 372 | { |
408 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 373 | struct i2c_client *client = sd->priv; |
409 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 374 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
410 | int data; | 375 | int data; |
411 | 376 | ||
412 | switch (ctrl->id) { | 377 | switch (ctrl->id) { |
@@ -423,10 +388,11 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro | |||
423 | return 0; | 388 | return 0; |
424 | } | 389 | } |
425 | 390 | ||
426 | static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 391 | static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
427 | { | 392 | { |
428 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 393 | struct i2c_client *client = sd->priv; |
429 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 394 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
395 | struct soc_camera_device *icd = client->dev.platform_data; | ||
430 | const struct v4l2_queryctrl *qctrl; | 396 | const struct v4l2_queryctrl *qctrl; |
431 | int data; | 397 | int data; |
432 | 398 | ||
@@ -521,10 +487,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
521 | static int mt9m001_video_probe(struct soc_camera_device *icd, | 487 | static int mt9m001_video_probe(struct soc_camera_device *icd, |
522 | struct i2c_client *client) | 488 | struct i2c_client *client) |
523 | { | 489 | { |
524 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 490 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
525 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 491 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
526 | s32 data; | 492 | s32 data; |
527 | int ret; | ||
528 | unsigned long flags; | 493 | unsigned long flags; |
529 | 494 | ||
530 | /* We must have a parent by now. And it cannot be a wrong one. | 495 | /* We must have a parent by now. And it cannot be a wrong one. |
@@ -533,11 +498,6 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
533 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 498 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
534 | return -ENODEV; | 499 | return -ENODEV; |
535 | 500 | ||
536 | /* Switch master clock on */ | ||
537 | ret = soc_camera_video_start(icd, &client->dev); | ||
538 | if (ret) | ||
539 | return ret; | ||
540 | |||
541 | /* Enable the chip */ | 501 | /* Enable the chip */ |
542 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); | 502 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); |
543 | dev_dbg(&icd->dev, "write: %d\n", data); | 503 | dev_dbg(&icd->dev, "write: %d\n", data); |
@@ -545,8 +505,6 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
545 | /* Read out the chip version register */ | 505 | /* Read out the chip version register */ |
546 | data = reg_read(client, MT9M001_CHIP_VERSION); | 506 | data = reg_read(client, MT9M001_CHIP_VERSION); |
547 | 507 | ||
548 | soc_camera_video_stop(icd); | ||
549 | |||
550 | /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ | 508 | /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ |
551 | switch (data) { | 509 | switch (data) { |
552 | case 0x8411: | 510 | case 0x8411: |
@@ -601,6 +559,27 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) | |||
601 | icl->free_bus(icl); | 559 | icl->free_bus(icl); |
602 | } | 560 | } |
603 | 561 | ||
562 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | ||
563 | .g_ctrl = mt9m001_g_ctrl, | ||
564 | .s_ctrl = mt9m001_s_ctrl, | ||
565 | .g_chip_ident = mt9m001_g_chip_ident, | ||
566 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
567 | .g_register = mt9m001_g_register, | ||
568 | .s_register = mt9m001_s_register, | ||
569 | #endif | ||
570 | }; | ||
571 | |||
572 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | ||
573 | .s_stream = mt9m001_s_stream, | ||
574 | .s_fmt = mt9m001_s_fmt, | ||
575 | .try_fmt = mt9m001_try_fmt, | ||
576 | }; | ||
577 | |||
578 | static struct v4l2_subdev_ops mt9m001_subdev_ops = { | ||
579 | .core = &mt9m001_subdev_core_ops, | ||
580 | .video = &mt9m001_subdev_video_ops, | ||
581 | }; | ||
582 | |||
604 | static int mt9m001_probe(struct i2c_client *client, | 583 | static int mt9m001_probe(struct i2c_client *client, |
605 | const struct i2c_device_id *did) | 584 | const struct i2c_device_id *did) |
606 | { | 585 | { |
@@ -631,7 +610,7 @@ static int mt9m001_probe(struct i2c_client *client, | |||
631 | if (!mt9m001) | 610 | if (!mt9m001) |
632 | return -ENOMEM; | 611 | return -ENOMEM; |
633 | 612 | ||
634 | i2c_set_clientdata(client, mt9m001); | 613 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); |
635 | 614 | ||
636 | /* Second stage probe - when a capture adapter is there */ | 615 | /* Second stage probe - when a capture adapter is there */ |
637 | icd->ops = &mt9m001_ops; | 616 | icd->ops = &mt9m001_ops; |
@@ -660,7 +639,7 @@ static int mt9m001_probe(struct i2c_client *client, | |||
660 | 639 | ||
661 | static int mt9m001_remove(struct i2c_client *client) | 640 | static int mt9m001_remove(struct i2c_client *client) |
662 | { | 641 | { |
663 | struct mt9m001 *mt9m001 = i2c_get_clientdata(client); | 642 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
664 | struct soc_camera_device *icd = client->dev.platform_data; | 643 | struct soc_camera_device *icd = client->dev.platform_data; |
665 | 644 | ||
666 | icd->ops = NULL; | 645 | icd->ops = NULL; |