diff options
Diffstat (limited to 'drivers/media/video/s5p-fimc/mipi-csis.c')
-rw-r--r-- | drivers/media/video/s5p-fimc/mipi-csis.c | 90 |
1 files changed, 48 insertions, 42 deletions
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index ef056d6605c..59d79bc2f58 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c | |||
@@ -81,6 +81,12 @@ static char *csi_clock_name[] = { | |||
81 | }; | 81 | }; |
82 | #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) | 82 | #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) |
83 | 83 | ||
84 | static const char * const csis_supply_name[] = { | ||
85 | "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ | ||
86 | "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ | ||
87 | }; | ||
88 | #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) | ||
89 | |||
84 | enum { | 90 | enum { |
85 | ST_POWERED = 1, | 91 | ST_POWERED = 1, |
86 | ST_STREAMING = 2, | 92 | ST_STREAMING = 2, |
@@ -109,9 +115,9 @@ struct csis_state { | |||
109 | struct platform_device *pdev; | 115 | struct platform_device *pdev; |
110 | struct resource *regs_res; | 116 | struct resource *regs_res; |
111 | void __iomem *regs; | 117 | void __iomem *regs; |
118 | struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; | ||
112 | struct clk *clock[NUM_CSIS_CLOCKS]; | 119 | struct clk *clock[NUM_CSIS_CLOCKS]; |
113 | int irq; | 120 | int irq; |
114 | struct regulator *supply; | ||
115 | u32 flags; | 121 | u32 flags; |
116 | const struct csis_pix_format *csis_fmt; | 122 | const struct csis_pix_format *csis_fmt; |
117 | struct v4l2_mbus_framefmt format; | 123 | struct v4l2_mbus_framefmt format; |
@@ -460,6 +466,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
460 | struct resource *regs_res; | 466 | struct resource *regs_res; |
461 | struct csis_state *state; | 467 | struct csis_state *state; |
462 | int ret = -ENOMEM; | 468 | int ret = -ENOMEM; |
469 | int i; | ||
463 | 470 | ||
464 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 471 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
465 | if (!state) | 472 | if (!state) |
@@ -519,14 +526,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
519 | goto e_clkput; | 526 | goto e_clkput; |
520 | } | 527 | } |
521 | 528 | ||
522 | if (!pdata->fixed_phy_vdd) { | 529 | for (i = 0; i < CSIS_NUM_SUPPLIES; i++) |
523 | state->supply = regulator_get(&pdev->dev, "vdd"); | 530 | state->supplies[i].supply = csis_supply_name[i]; |
524 | if (IS_ERR(state->supply)) { | 531 | |
525 | ret = PTR_ERR(state->supply); | 532 | ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, |
526 | state->supply = NULL; | 533 | state->supplies); |
527 | goto e_clkput; | 534 | if (ret) |
528 | } | 535 | goto e_clkput; |
529 | } | ||
530 | 536 | ||
531 | ret = request_irq(state->irq, s5pcsis_irq_handler, 0, | 537 | ret = request_irq(state->irq, s5pcsis_irq_handler, 0, |
532 | dev_name(&pdev->dev), state); | 538 | dev_name(&pdev->dev), state); |
@@ -553,7 +559,6 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
553 | /* .. and a pointer to the subdev. */ | 559 | /* .. and a pointer to the subdev. */ |
554 | platform_set_drvdata(pdev, &state->sd); | 560 | platform_set_drvdata(pdev, &state->sd); |
555 | 561 | ||
556 | state->flags = ST_SUSPENDED; | ||
557 | pm_runtime_enable(&pdev->dev); | 562 | pm_runtime_enable(&pdev->dev); |
558 | 563 | ||
559 | return 0; | 564 | return 0; |
@@ -561,8 +566,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
561 | e_irqfree: | 566 | e_irqfree: |
562 | free_irq(state->irq, state); | 567 | free_irq(state->irq, state); |
563 | e_regput: | 568 | e_regput: |
564 | if (state->supply) | 569 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
565 | regulator_put(state->supply); | ||
566 | e_clkput: | 570 | e_clkput: |
567 | clk_disable(state->clock[CSIS_CLK_MUX]); | 571 | clk_disable(state->clock[CSIS_CLK_MUX]); |
568 | s5pcsis_clk_put(state); | 572 | s5pcsis_clk_put(state); |
@@ -575,7 +579,7 @@ e_free: | |||
575 | return ret; | 579 | return ret; |
576 | } | 580 | } |
577 | 581 | ||
578 | static int s5pcsis_suspend(struct device *dev) | 582 | static int s5pcsis_pm_suspend(struct device *dev, bool runtime) |
579 | { | 583 | { |
580 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; | 584 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; |
581 | struct platform_device *pdev = to_platform_device(dev); | 585 | struct platform_device *pdev = to_platform_device(dev); |
@@ -592,21 +596,21 @@ static int s5pcsis_suspend(struct device *dev) | |||
592 | ret = pdata->phy_enable(state->pdev, false); | 596 | ret = pdata->phy_enable(state->pdev, false); |
593 | if (ret) | 597 | if (ret) |
594 | goto unlock; | 598 | goto unlock; |
595 | if (state->supply) { | 599 | ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, |
596 | ret = regulator_disable(state->supply); | 600 | state->supplies); |
597 | if (ret) | 601 | if (ret) |
598 | goto unlock; | 602 | goto unlock; |
599 | } | ||
600 | clk_disable(state->clock[CSIS_CLK_GATE]); | 603 | clk_disable(state->clock[CSIS_CLK_GATE]); |
601 | state->flags &= ~ST_POWERED; | 604 | state->flags &= ~ST_POWERED; |
605 | if (!runtime) | ||
606 | state->flags |= ST_SUSPENDED; | ||
602 | } | 607 | } |
603 | state->flags |= ST_SUSPENDED; | ||
604 | unlock: | 608 | unlock: |
605 | mutex_unlock(&state->lock); | 609 | mutex_unlock(&state->lock); |
606 | return ret ? -EAGAIN : 0; | 610 | return ret ? -EAGAIN : 0; |
607 | } | 611 | } |
608 | 612 | ||
609 | static int s5pcsis_resume(struct device *dev) | 613 | static int s5pcsis_pm_resume(struct device *dev, bool runtime) |
610 | { | 614 | { |
611 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; | 615 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; |
612 | struct platform_device *pdev = to_platform_device(dev); | 616 | struct platform_device *pdev = to_platform_device(dev); |
@@ -618,20 +622,20 @@ static int s5pcsis_resume(struct device *dev) | |||
618 | __func__, state->flags); | 622 | __func__, state->flags); |
619 | 623 | ||
620 | mutex_lock(&state->lock); | 624 | mutex_lock(&state->lock); |
621 | if (!(state->flags & ST_SUSPENDED)) | 625 | if (!runtime && !(state->flags & ST_SUSPENDED)) |
622 | goto unlock; | 626 | goto unlock; |
623 | 627 | ||
624 | if (!(state->flags & ST_POWERED)) { | 628 | if (!(state->flags & ST_POWERED)) { |
625 | if (state->supply) | 629 | ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES, |
626 | ret = regulator_enable(state->supply); | 630 | state->supplies); |
627 | if (ret) | 631 | if (ret) |
628 | goto unlock; | 632 | goto unlock; |
629 | |||
630 | ret = pdata->phy_enable(state->pdev, true); | 633 | ret = pdata->phy_enable(state->pdev, true); |
631 | if (!ret) { | 634 | if (!ret) { |
632 | state->flags |= ST_POWERED; | 635 | state->flags |= ST_POWERED; |
633 | } else if (state->supply) { | 636 | } else { |
634 | regulator_disable(state->supply); | 637 | regulator_bulk_disable(CSIS_NUM_SUPPLIES, |
638 | state->supplies); | ||
635 | goto unlock; | 639 | goto unlock; |
636 | } | 640 | } |
637 | clk_enable(state->clock[CSIS_CLK_GATE]); | 641 | clk_enable(state->clock[CSIS_CLK_GATE]); |
@@ -646,24 +650,26 @@ static int s5pcsis_resume(struct device *dev) | |||
646 | } | 650 | } |
647 | 651 | ||
648 | #ifdef CONFIG_PM_SLEEP | 652 | #ifdef CONFIG_PM_SLEEP |
649 | static int s5pcsis_pm_suspend(struct device *dev) | 653 | static int s5pcsis_suspend(struct device *dev) |
650 | { | 654 | { |
651 | return s5pcsis_suspend(dev); | 655 | return s5pcsis_pm_suspend(dev, false); |
652 | } | 656 | } |
653 | 657 | ||
654 | static int s5pcsis_pm_resume(struct device *dev) | 658 | static int s5pcsis_resume(struct device *dev) |
655 | { | 659 | { |
656 | int ret; | 660 | return s5pcsis_pm_resume(dev, false); |
657 | 661 | } | |
658 | ret = s5pcsis_resume(dev); | 662 | #endif |
659 | 663 | ||
660 | if (!ret) { | 664 | #ifdef CONFIG_PM_RUNTIME |
661 | pm_runtime_disable(dev); | 665 | static int s5pcsis_runtime_suspend(struct device *dev) |
662 | ret = pm_runtime_set_active(dev); | 666 | { |
663 | pm_runtime_enable(dev); | 667 | return s5pcsis_pm_suspend(dev, true); |
664 | } | 668 | } |
665 | 669 | ||
666 | return ret; | 670 | static int s5pcsis_runtime_resume(struct device *dev) |
671 | { | ||
672 | return s5pcsis_pm_resume(dev, true); | ||
667 | } | 673 | } |
668 | #endif | 674 | #endif |
669 | 675 | ||
@@ -679,8 +685,7 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) | |||
679 | pm_runtime_set_suspended(&pdev->dev); | 685 | pm_runtime_set_suspended(&pdev->dev); |
680 | 686 | ||
681 | s5pcsis_clk_put(state); | 687 | s5pcsis_clk_put(state); |
682 | if (state->supply) | 688 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
683 | regulator_put(state->supply); | ||
684 | 689 | ||
685 | media_entity_cleanup(&state->sd.entity); | 690 | media_entity_cleanup(&state->sd.entity); |
686 | free_irq(state->irq, state); | 691 | free_irq(state->irq, state); |
@@ -692,8 +697,9 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) | |||
692 | } | 697 | } |
693 | 698 | ||
694 | static const struct dev_pm_ops s5pcsis_pm_ops = { | 699 | static const struct dev_pm_ops s5pcsis_pm_ops = { |
695 | SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL) | 700 | SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume, |
696 | SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume) | 701 | NULL) |
702 | SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) | ||
697 | }; | 703 | }; |
698 | 704 | ||
699 | static struct platform_driver s5pcsis_driver = { | 705 | static struct platform_driver s5pcsis_driver = { |