aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2011-09-16 11:33:08 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-09-21 13:28:12 -0400
commit6426e14a7ebfaea831db8d95f55da334701f2c37 (patch)
treebcf4e247614cc4b0eb7b59e2c45824ef3dfb30cd /drivers
parentfbc09d3aa1510552e36d9bae05def25d039a98f2 (diff)
[media] noon010pc30: Conversion to the media controller API
Replace g/s_mbus_fmt ops with the pad level get/set_fmt operations. Add media entity initialization and set subdev flags so the host driver creates a subdev device node for the driver. A mutex was added for serializing the subdev operations. When setting format is attempted during streaming an (EBUSY) error will be returned. After the device is powered up it will now remain in "power sleep" mode until s_stream(1) is called. The "power sleep" mode is used to suspend/resume frame generation at the sensor's output through s_stream op. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/noon010pc30.c221
2 files changed, 154 insertions, 69 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9da6044b449..eb4fd6b44ca 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -762,7 +762,7 @@ config VIDEO_VIA_CAMERA
762 762
763config VIDEO_NOON010PC30 763config VIDEO_NOON010PC30
764 tristate "NOON010PC30 CIF camera sensor support" 764 tristate "NOON010PC30 CIF camera sensor support"
765 depends on I2C && VIDEO_V4L2 765 depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
766 ---help--- 766 ---help---
767 This driver supports NOON010PC30 CIF camera from Siliconfile 767 This driver supports NOON010PC30 CIF camera from Siliconfile
768 768
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c
index 35f722a88f7..1a874ec8f9e 100644
--- a/drivers/media/video/noon010pc30.c
+++ b/drivers/media/video/noon010pc30.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP 2 * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
3 * 3 *
4 * Copyright (C) 2010 Samsung Electronics 4 * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
5 * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> 5 * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
6 * 6 *
7 * Initial register configuration based on a driver authored by 7 * Initial register configuration based on a driver authored by
@@ -10,7 +10,7 @@
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later vergsion. 13 * (at your option) any later version.
14 */ 14 */
15 15
16#include <linux/delay.h> 16#include <linux/delay.h>
@@ -131,17 +131,24 @@ static const char * const noon010_supply_name[] = {
131 131
132struct noon010_info { 132struct noon010_info {
133 struct v4l2_subdev sd; 133 struct v4l2_subdev sd;
134 struct media_pad pad;
134 struct v4l2_ctrl_handler hdl; 135 struct v4l2_ctrl_handler hdl;
135 const struct noon010pc30_platform_data *pdata; 136 const struct noon010pc30_platform_data *pdata;
137 struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
138 u32 gpio_nreset;
139 u32 gpio_nstby;
140
141 /* Protects the struct members below */
142 struct mutex lock;
143
136 const struct noon010_format *curr_fmt; 144 const struct noon010_format *curr_fmt;
137 const struct noon010_frmsize *curr_win; 145 const struct noon010_frmsize *curr_win;
146 unsigned int apply_new_cfg:1;
147 unsigned int streaming:1;
138 unsigned int hflip:1; 148 unsigned int hflip:1;
139 unsigned int vflip:1; 149 unsigned int vflip:1;
140 unsigned int power:1; 150 unsigned int power:1;
141 u8 i2c_reg_page; 151 u8 i2c_reg_page;
142 struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
143 u32 gpio_nreset;
144 u32 gpio_nstby;
145}; 152};
146 153
147struct i2c_regval { 154struct i2c_regval {
@@ -313,6 +320,7 @@ static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
313 return ret; 320 return ret;
314} 321}
315 322
323/* Called with struct noon010_info.lock mutex held */
316static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) 324static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
317{ 325{
318 struct noon010_info *info = to_noon010(sd); 326 struct noon010_info *info = to_noon010(sd);
@@ -340,21 +348,18 @@ static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
340static int noon010_set_params(struct v4l2_subdev *sd) 348static int noon010_set_params(struct v4l2_subdev *sd)
341{ 349{
342 struct noon010_info *info = to_noon010(sd); 350 struct noon010_info *info = to_noon010(sd);
343 int ret;
344 351
345 if (!info->curr_win) 352 int ret = cam_i2c_write(sd, VDO_CTL_REG(0),
346 return -EINVAL; 353 info->curr_win->vid_ctl1);
347 354 if (ret)
348 ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1); 355 return ret;
349 356 return cam_i2c_write(sd, ISP_CTL_REG(0),
350 if (!ret && info->curr_fmt) 357 info->curr_fmt->ispctl1_reg);
351 ret = cam_i2c_write(sd, ISP_CTL_REG(0),
352 info->curr_fmt->ispctl1_reg);
353 return ret;
354} 358}
355 359
356/* Find nearest matching image pixel size. */ 360/* Find nearest matching image pixel size. */
357static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) 361static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf,
362 const struct noon010_frmsize **size)
358{ 363{
359 unsigned int min_err = ~0; 364 unsigned int min_err = ~0;
360 int i = ARRAY_SIZE(noon010_sizes); 365 int i = ARRAY_SIZE(noon010_sizes);
@@ -374,11 +379,14 @@ static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf)
374 if (match) { 379 if (match) {
375 mf->width = match->width; 380 mf->width = match->width;
376 mf->height = match->height; 381 mf->height = match->height;
382 if (size)
383 *size = match;
377 return 0; 384 return 0;
378 } 385 }
379 return -EINVAL; 386 return -EINVAL;
380} 387}
381 388
389/* Called with info.lock mutex held */
382static int power_enable(struct noon010_info *info) 390static int power_enable(struct noon010_info *info)
383{ 391{
384 int ret; 392 int ret;
@@ -419,6 +427,7 @@ static int power_enable(struct noon010_info *info)
419 return 0; 427 return 0;
420} 428}
421 429
430/* Called with info.lock mutex held */
422static int power_disable(struct noon010_info *info) 431static int power_disable(struct noon010_info *info)
423{ 432{
424 int ret; 433 int ret;
@@ -448,93 +457,120 @@ static int power_disable(struct noon010_info *info)
448static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) 457static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
449{ 458{
450 struct v4l2_subdev *sd = to_sd(ctrl); 459 struct v4l2_subdev *sd = to_sd(ctrl);
460 struct noon010_info *info = to_noon010(sd);
461 int ret = 0;
451 462
452 v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", 463 v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
453 __func__, ctrl->id, ctrl->val); 464 __func__, ctrl->id, ctrl->val);
454 465
466 mutex_lock(&info->lock);
467 /*
468 * If the device is not powered up by the host driver do
469 * not apply any controls to H/W at this time. Instead
470 * the controls will be restored right after power-up.
471 */
472 if (!info->power)
473 goto unlock;
474
455 switch (ctrl->id) { 475 switch (ctrl->id) {
456 case V4L2_CID_AUTO_WHITE_BALANCE: 476 case V4L2_CID_AUTO_WHITE_BALANCE:
457 return noon010_enable_autowhitebalance(sd, ctrl->val); 477 ret = noon010_enable_autowhitebalance(sd, ctrl->val);
478 break;
458 case V4L2_CID_BLUE_BALANCE: 479 case V4L2_CID_BLUE_BALANCE:
459 return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); 480 ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
481 break;
460 case V4L2_CID_RED_BALANCE: 482 case V4L2_CID_RED_BALANCE:
461 return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); 483 ret = cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
484 break;
462 default: 485 default:
463 return -EINVAL; 486 ret = -EINVAL;
464 } 487 }
488unlock:
489 mutex_unlock(&info->lock);
490 return ret;
465} 491}
466 492
467static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index, 493static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
468 enum v4l2_mbus_pixelcode *code) 494 struct v4l2_subdev_fh *fh,
495 struct v4l2_subdev_mbus_code_enum *code)
469{ 496{
470 if (!code || index >= ARRAY_SIZE(noon010_formats)) 497 if (code->index >= ARRAY_SIZE(noon010_formats))
471 return -EINVAL; 498 return -EINVAL;
472 499
473 *code = noon010_formats[index].code; 500 code->code = noon010_formats[code->index].code;
474 return 0; 501 return 0;
475} 502}
476 503
477static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) 504static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
505 struct v4l2_subdev_format *fmt)
478{ 506{
479 struct noon010_info *info = to_noon010(sd); 507 struct noon010_info *info = to_noon010(sd);
480 int ret; 508 struct v4l2_mbus_framefmt *mf;
481
482 if (!mf)
483 return -EINVAL;
484 509
485 if (!info->curr_win || !info->curr_fmt) { 510 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
486 ret = noon010_set_params(sd); 511 if (fh) {
487 if (ret) 512 mf = v4l2_subdev_get_try_format(fh, 0);
488 return ret; 513 fmt->format = *mf;
514 }
515 return 0;
489 } 516 }
517 mf = &fmt->format;
490 518
491 mf->width = info->curr_win->width; 519 mutex_lock(&info->lock);
492 mf->height = info->curr_win->height; 520 mf->width = info->curr_win->width;
493 mf->code = info->curr_fmt->code; 521 mf->height = info->curr_win->height;
494 mf->colorspace = info->curr_fmt->colorspace; 522 mf->code = info->curr_fmt->code;
495 mf->field = V4L2_FIELD_NONE; 523 mf->colorspace = info->curr_fmt->colorspace;
524 mf->field = V4L2_FIELD_NONE;
496 525
526 mutex_unlock(&info->lock);
497 return 0; 527 return 0;
498} 528}
499 529
500/* Return nearest media bus frame format. */ 530/* Return nearest media bus frame format. */
501static const struct noon010_format *try_fmt(struct v4l2_subdev *sd, 531static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
502 struct v4l2_mbus_framefmt *mf) 532 struct v4l2_mbus_framefmt *mf)
503{ 533{
504 int i = ARRAY_SIZE(noon010_formats); 534 int i = ARRAY_SIZE(noon010_formats);
505 535
506 noon010_try_frame_size(mf); 536 while (--i)
507
508 while (i--)
509 if (mf->code == noon010_formats[i].code) 537 if (mf->code == noon010_formats[i].code)
510 break; 538 break;
511
512 mf->code = noon010_formats[i].code; 539 mf->code = noon010_formats[i].code;
513 540
514 return &noon010_formats[i]; 541 return &noon010_formats[i];
515} 542}
516 543
517static int noon010_try_fmt(struct v4l2_subdev *sd, 544static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
518 struct v4l2_mbus_framefmt *mf) 545 struct v4l2_subdev_format *fmt)
519{
520 if (!sd || !mf)
521 return -EINVAL;
522
523 try_fmt(sd, mf);
524 return 0;
525}
526
527static int noon010_s_fmt(struct v4l2_subdev *sd,
528 struct v4l2_mbus_framefmt *mf)
529{ 546{
530 struct noon010_info *info = to_noon010(sd); 547 struct noon010_info *info = to_noon010(sd);
548 const struct noon010_frmsize *size = NULL;
549 const struct noon010_format *nf;
550 struct v4l2_mbus_framefmt *mf;
551 int ret = 0;
531 552
532 if (!sd || !mf) 553 nf = noon010_try_fmt(sd, &fmt->format);
533 return -EINVAL; 554 noon010_try_frame_size(&fmt->format, &size);
534 555 fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
535 info->curr_fmt = try_fmt(sd, mf);
536 556
537 return noon010_set_params(sd); 557 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
558 if (fh) {
559 mf = v4l2_subdev_get_try_format(fh, 0);
560 *mf = fmt->format;
561 }
562 return 0;
563 }
564 mutex_lock(&info->lock);
565 if (!info->streaming) {
566 info->apply_new_cfg = 1;
567 info->curr_fmt = nf;
568 info->curr_win = size;
569 } else {
570 ret = -EBUSY;
571 }
572 mutex_unlock(&info->lock);
573 return ret;
538} 574}
539 575
540static int noon010_base_config(struct v4l2_subdev *sd) 576static int noon010_base_config(struct v4l2_subdev *sd)
@@ -550,8 +586,6 @@ static int noon010_base_config(struct v4l2_subdev *sd)
550 } 586 }
551 if (!ret) 587 if (!ret)
552 ret = noon010_set_flip(sd, 1, 0); 588 ret = noon010_set_flip(sd, 1, 0);
553 if (!ret)
554 ret = noon010_power_ctrl(sd, false, false);
555 589
556 /* sync the handler and the registers state */ 590 /* sync the handler and the registers state */
557 v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); 591 v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl);
@@ -582,6 +616,26 @@ static int noon010_s_power(struct v4l2_subdev *sd, int on)
582 return ret; 616 return ret;
583} 617}
584 618
619static int noon010_s_stream(struct v4l2_subdev *sd, int on)
620{
621 struct noon010_info *info = to_noon010(sd);
622 int ret = 0;
623
624 mutex_lock(&info->lock);
625 if (!info->streaming != !on) {
626 ret = noon010_power_ctrl(sd, false, !on);
627 if (!ret)
628 info->streaming = on;
629 }
630 if (!ret && on && info->apply_new_cfg) {
631 ret = noon010_set_params(sd);
632 if (!ret)
633 info->apply_new_cfg = 0;
634 }
635 mutex_unlock(&info->lock);
636 return ret;
637}
638
585static int noon010_g_chip_ident(struct v4l2_subdev *sd, 639static int noon010_g_chip_ident(struct v4l2_subdev *sd,
586 struct v4l2_dbg_chip_ident *chip) 640 struct v4l2_dbg_chip_ident *chip)
587{ 641{
@@ -599,6 +653,22 @@ static int noon010_log_status(struct v4l2_subdev *sd)
599 return 0; 653 return 0;
600} 654}
601 655
656static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
657{
658 struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
659
660 mf->width = noon010_sizes[0].width;
661 mf->height = noon010_sizes[0].height;
662 mf->code = noon010_formats[0].code;
663 mf->colorspace = V4L2_COLORSPACE_JPEG;
664 mf->field = V4L2_FIELD_NONE;
665 return 0;
666}
667
668static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
669 .open = noon010_open,
670};
671
602static const struct v4l2_ctrl_ops noon010_ctrl_ops = { 672static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
603 .s_ctrl = noon010_s_ctrl, 673 .s_ctrl = noon010_s_ctrl,
604}; 674};
@@ -616,15 +686,19 @@ static const struct v4l2_subdev_core_ops noon010_core_ops = {
616 .log_status = noon010_log_status, 686 .log_status = noon010_log_status,
617}; 687};
618 688
619static const struct v4l2_subdev_video_ops noon010_video_ops = { 689static struct v4l2_subdev_pad_ops noon010_pad_ops = {
620 .g_mbus_fmt = noon010_g_fmt, 690 .enum_mbus_code = noon010_enum_mbus_code,
621 .s_mbus_fmt = noon010_s_fmt, 691 .get_fmt = noon010_get_fmt,
622 .try_mbus_fmt = noon010_try_fmt, 692 .set_fmt = noon010_set_fmt,
623 .enum_mbus_fmt = noon010_enum_fmt, 693};
694
695static struct v4l2_subdev_video_ops noon010_video_ops = {
696 .s_stream = noon010_s_stream,
624}; 697};
625 698
626static const struct v4l2_subdev_ops noon010_ops = { 699static const struct v4l2_subdev_ops noon010_ops = {
627 .core = &noon010_core_ops, 700 .core = &noon010_core_ops,
701 .pad = &noon010_pad_ops,
628 .video = &noon010_video_ops, 702 .video = &noon010_video_ops,
629}; 703};
630 704
@@ -665,10 +739,14 @@ static int noon010_probe(struct i2c_client *client,
665 if (!info) 739 if (!info)
666 return -ENOMEM; 740 return -ENOMEM;
667 741
742 mutex_init(&info->lock);
668 sd = &info->sd; 743 sd = &info->sd;
669 strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); 744 strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
670 v4l2_i2c_subdev_init(sd, client, &noon010_ops); 745 v4l2_i2c_subdev_init(sd, client, &noon010_ops);
671 746
747 sd->internal_ops = &noon010_subdev_internal_ops;
748 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
749
672 v4l2_ctrl_handler_init(&info->hdl, 3); 750 v4l2_ctrl_handler_init(&info->hdl, 3);
673 751
674 v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, 752 v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
@@ -719,11 +797,17 @@ static int noon010_probe(struct i2c_client *client,
719 if (ret) 797 if (ret)
720 goto np_reg_err; 798 goto np_reg_err;
721 799
800 info->pad.flags = MEDIA_PAD_FL_SOURCE;
801 sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
802 ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
803 if (ret < 0)
804 goto np_me_err;
805
722 ret = noon010_detect(client, info); 806 ret = noon010_detect(client, info);
723 if (!ret) 807 if (!ret)
724 return 0; 808 return 0;
725 809
726 /* the sensor detection failed */ 810np_me_err:
727 regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); 811 regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
728np_reg_err: 812np_reg_err:
729 if (gpio_is_valid(info->gpio_nstby)) 813 if (gpio_is_valid(info->gpio_nstby))
@@ -754,6 +838,7 @@ static int noon010_remove(struct i2c_client *client)
754 if (gpio_is_valid(info->gpio_nstby)) 838 if (gpio_is_valid(info->gpio_nstby))
755 gpio_free(info->gpio_nstby); 839 gpio_free(info->gpio_nstby);
756 840
841 media_entity_cleanup(&sd->entity);
757 kfree(info); 842 kfree(info);
758 return 0; 843 return 0;
759} 844}