diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-08-25 10:43:33 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-18 23:18:35 -0400 |
commit | 979ea1ddf80ac7383acdea03471355ca62702539 (patch) | |
tree | 2ee4c73eb672c1ee8167ed7e0906bac6f3b00e69 /drivers/media/video/mt9m001.c | |
parent | 0bab829de1ab60d8c3cbf7e402192bb9446840b7 (diff) |
V4L/DVB (12510): soc-camera: (partially) convert to v4l2-(sub)dev API
Convert the soc-camera framework to use the v4l2-(sub)dev API. Start using
v4l2-subdev operations. Only a part of the interface between the
soc_camera core, soc_camera host drivers on one side and soc_camera device
drivers on the other side is replaced so far. The rest of the interface
will be replaced in incremental steps, and will require extensions and,
possibly, modifications to the v4l2-subdev code.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
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; |