diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-28 10:23:16 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2009-09-17 03:47:10 -0400 |
commit | 1304850d4c5d2f915bdcb8d547f3ef26c60cc825 (patch) | |
tree | 35bcd4ca14363bde34ee2009fea5c40d346fc8c6 /drivers/regulator/wm831x-dcdc.c | |
parent | 8267a9ba8299e1e70d54c7666da6aada637de4fc (diff) |
regulator: Add WM831x DC-DC boost convertor support
The WM831x series of PMICs include a single DC-DC boost convertor.
This adds basic support for this convertor.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/regulator/wm831x-dcdc.c')
-rw-r--r-- | drivers/regulator/wm831x-dcdc.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 88a7dbac750..2eefc1a0cf0 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c | |||
@@ -614,6 +614,132 @@ static struct platform_driver wm831x_buckp_driver = { | |||
614 | }; | 614 | }; |
615 | 615 | ||
616 | /* | 616 | /* |
617 | * DCDC boost convertors | ||
618 | */ | ||
619 | |||
620 | static int wm831x_boostp_get_status(struct regulator_dev *rdev) | ||
621 | { | ||
622 | struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); | ||
623 | struct wm831x *wm831x = dcdc->wm831x; | ||
624 | int ret; | ||
625 | |||
626 | /* First, check for errors */ | ||
627 | ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS); | ||
628 | if (ret < 0) | ||
629 | return ret; | ||
630 | |||
631 | if (ret & (1 << rdev_get_id(rdev))) { | ||
632 | dev_dbg(wm831x->dev, "DCDC%d under voltage\n", | ||
633 | rdev_get_id(rdev) + 1); | ||
634 | return REGULATOR_STATUS_ERROR; | ||
635 | } | ||
636 | |||
637 | /* Is the regulator on? */ | ||
638 | ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS); | ||
639 | if (ret < 0) | ||
640 | return ret; | ||
641 | if (ret & (1 << rdev_get_id(rdev))) | ||
642 | return REGULATOR_STATUS_ON; | ||
643 | else | ||
644 | return REGULATOR_STATUS_OFF; | ||
645 | } | ||
646 | |||
647 | static struct regulator_ops wm831x_boostp_ops = { | ||
648 | .get_status = wm831x_boostp_get_status, | ||
649 | |||
650 | .is_enabled = wm831x_dcdc_is_enabled, | ||
651 | .enable = wm831x_dcdc_enable, | ||
652 | .disable = wm831x_dcdc_disable, | ||
653 | }; | ||
654 | |||
655 | static __devinit int wm831x_boostp_probe(struct platform_device *pdev) | ||
656 | { | ||
657 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | ||
658 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | ||
659 | int id = pdev->id % ARRAY_SIZE(pdata->dcdc); | ||
660 | struct wm831x_dcdc *dcdc; | ||
661 | struct resource *res; | ||
662 | int ret, irq; | ||
663 | |||
664 | dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); | ||
665 | |||
666 | if (pdata == NULL || pdata->dcdc[id] == NULL) | ||
667 | return -ENODEV; | ||
668 | |||
669 | dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL); | ||
670 | if (dcdc == NULL) { | ||
671 | dev_err(&pdev->dev, "Unable to allocate private data\n"); | ||
672 | return -ENOMEM; | ||
673 | } | ||
674 | |||
675 | dcdc->wm831x = wm831x; | ||
676 | |||
677 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
678 | if (res == NULL) { | ||
679 | dev_err(&pdev->dev, "No I/O resource\n"); | ||
680 | ret = -EINVAL; | ||
681 | goto err; | ||
682 | } | ||
683 | dcdc->base = res->start; | ||
684 | |||
685 | snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1); | ||
686 | dcdc->desc.name = dcdc->name; | ||
687 | dcdc->desc.id = id; | ||
688 | dcdc->desc.type = REGULATOR_VOLTAGE; | ||
689 | dcdc->desc.ops = &wm831x_boostp_ops; | ||
690 | dcdc->desc.owner = THIS_MODULE; | ||
691 | |||
692 | dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, | ||
693 | pdata->dcdc[id], dcdc); | ||
694 | if (IS_ERR(dcdc->regulator)) { | ||
695 | ret = PTR_ERR(dcdc->regulator); | ||
696 | dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", | ||
697 | id + 1, ret); | ||
698 | goto err; | ||
699 | } | ||
700 | |||
701 | irq = platform_get_irq_byname(pdev, "UV"); | ||
702 | ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, | ||
703 | IRQF_TRIGGER_RISING, dcdc->name, | ||
704 | dcdc); | ||
705 | if (ret != 0) { | ||
706 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | ||
707 | irq, ret); | ||
708 | goto err_regulator; | ||
709 | } | ||
710 | |||
711 | platform_set_drvdata(pdev, dcdc); | ||
712 | |||
713 | return 0; | ||
714 | |||
715 | err_regulator: | ||
716 | regulator_unregister(dcdc->regulator); | ||
717 | err: | ||
718 | kfree(dcdc); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static __devexit int wm831x_boostp_remove(struct platform_device *pdev) | ||
723 | { | ||
724 | struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); | ||
725 | struct wm831x *wm831x = dcdc->wm831x; | ||
726 | |||
727 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); | ||
728 | regulator_unregister(dcdc->regulator); | ||
729 | kfree(dcdc); | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static struct platform_driver wm831x_boostp_driver = { | ||
735 | .probe = wm831x_boostp_probe, | ||
736 | .remove = __devexit_p(wm831x_boostp_remove), | ||
737 | .driver = { | ||
738 | .name = "wm831x-boostp", | ||
739 | }, | ||
740 | }; | ||
741 | |||
742 | /* | ||
617 | * External Power Enable | 743 | * External Power Enable |
618 | * | 744 | * |
619 | * These aren't actually DCDCs but look like them in hardware so share | 745 | * These aren't actually DCDCs but look like them in hardware so share |
@@ -707,6 +833,10 @@ static int __init wm831x_dcdc_init(void) | |||
707 | if (ret != 0) | 833 | if (ret != 0) |
708 | pr_err("Failed to register WM831x BUCKP driver: %d\n", ret); | 834 | pr_err("Failed to register WM831x BUCKP driver: %d\n", ret); |
709 | 835 | ||
836 | ret = platform_driver_register(&wm831x_boostp_driver); | ||
837 | if (ret != 0) | ||
838 | pr_err("Failed to register WM831x BOOST driver: %d\n", ret); | ||
839 | |||
710 | ret = platform_driver_register(&wm831x_epe_driver); | 840 | ret = platform_driver_register(&wm831x_epe_driver); |
711 | if (ret != 0) | 841 | if (ret != 0) |
712 | pr_err("Failed to register WM831x EPE driver: %d\n", ret); | 842 | pr_err("Failed to register WM831x EPE driver: %d\n", ret); |
@@ -718,6 +848,7 @@ subsys_initcall(wm831x_dcdc_init); | |||
718 | static void __exit wm831x_dcdc_exit(void) | 848 | static void __exit wm831x_dcdc_exit(void) |
719 | { | 849 | { |
720 | platform_driver_unregister(&wm831x_epe_driver); | 850 | platform_driver_unregister(&wm831x_epe_driver); |
851 | platform_driver_unregister(&wm831x_boostp_driver); | ||
721 | platform_driver_unregister(&wm831x_buckp_driver); | 852 | platform_driver_unregister(&wm831x_buckp_driver); |
722 | platform_driver_unregister(&wm831x_buckv_driver); | 853 | platform_driver_unregister(&wm831x_buckv_driver); |
723 | } | 854 | } |