Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0+ 2 : : /* 3 : : * PM MFD driver for Broadcom BCM2835 4 : : * 5 : : * This driver binds to the PM block and creates the MFD device for 6 : : * the WDT and power drivers. 7 : : */ 8 : : 9 : : #include <linux/delay.h> 10 : : #include <linux/io.h> 11 : : #include <linux/mfd/bcm2835-pm.h> 12 : : #include <linux/mfd/core.h> 13 : : #include <linux/module.h> 14 : : #include <linux/of_address.h> 15 : : #include <linux/of_platform.h> 16 : : #include <linux/platform_device.h> 17 : : #include <linux/types.h> 18 : : #include <linux/watchdog.h> 19 : : 20 : : static const struct mfd_cell bcm2835_pm_devs[] = { 21 : : { .name = "bcm2835-wdt" }, 22 : : }; 23 : : 24 : : static const struct mfd_cell bcm2835_power_devs[] = { 25 : : { .name = "bcm2835-power" }, 26 : : }; 27 : : 28 : 3 : static int bcm2835_pm_probe(struct platform_device *pdev) 29 : : { 30 : : struct resource *res; 31 : 3 : struct device *dev = &pdev->dev; 32 : : struct bcm2835_pm *pm; 33 : : int ret; 34 : : 35 : : pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL); 36 : 3 : if (!pm) 37 : : return -ENOMEM; 38 : : platform_set_drvdata(pdev, pm); 39 : : 40 : 3 : pm->dev = dev; 41 : : 42 : 3 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 43 : 3 : pm->base = devm_ioremap_resource(dev, res); 44 : 3 : if (IS_ERR(pm->base)) 45 : 0 : return PTR_ERR(pm->base); 46 : : 47 : 3 : ret = devm_mfd_add_devices(dev, -1, 48 : : bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), 49 : : NULL, 0, NULL); 50 : 3 : if (ret) 51 : : return ret; 52 : : 53 : : /* Map the RPiVid ASB regs if present. */ 54 : 3 : res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 55 : 3 : if (res) { 56 : 0 : pm->rpivid_asb = devm_ioremap_resource(dev, res); 57 : 0 : if (IS_ERR(pm->rpivid_asb)) { 58 : 0 : dev_err(dev, "Failed to map RPiVid ASB: %ld\n", 59 : : PTR_ERR(pm->rpivid_asb)); 60 : 0 : return PTR_ERR(pm->rpivid_asb); 61 : : } 62 : : } 63 : : 64 : : /* We'll use the presence of the AXI ASB regs in the 65 : : * bcm2835-pm binding as the key for whether we can reference 66 : : * the full PM register range and support power domains. 67 : : */ 68 : 3 : res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 69 : 3 : if (res) { 70 : 3 : pm->asb = devm_ioremap_resource(dev, res); 71 : 3 : if (IS_ERR(pm->asb)) 72 : 0 : return PTR_ERR(pm->asb); 73 : : 74 : 3 : ret = devm_mfd_add_devices(dev, -1, 75 : : bcm2835_power_devs, 76 : : ARRAY_SIZE(bcm2835_power_devs), 77 : : NULL, 0, NULL); 78 : 3 : if (ret) 79 : 0 : return ret; 80 : : } 81 : : 82 : : return 0; 83 : : } 84 : : 85 : : static const struct of_device_id bcm2835_pm_of_match[] = { 86 : : { .compatible = "brcm,bcm2835-pm-wdt", }, 87 : : { .compatible = "brcm,bcm2835-pm", }, 88 : : {}, 89 : : }; 90 : : MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); 91 : : 92 : : static struct platform_driver bcm2835_pm_driver = { 93 : : .probe = bcm2835_pm_probe, 94 : : .driver = { 95 : : .name = "bcm2835-pm", 96 : : .of_match_table = bcm2835_pm_of_match, 97 : : }, 98 : : }; 99 : 3 : module_platform_driver(bcm2835_pm_driver); 100 : : 101 : : MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); 102 : : MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD"); 103 : : MODULE_LICENSE("GPL");