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 : 207 : static int bcm2835_pm_probe(struct platform_device *pdev)
29 : : {
30 : : struct resource *res;
31 : 207 : struct device *dev = &pdev->dev;
32 : : struct bcm2835_pm *pm;
33 : : int ret;
34 : :
35 : : pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
36 [ + - ]: 207 : if (!pm)
37 : : return -ENOMEM;
38 : : platform_set_drvdata(pdev, pm);
39 : :
40 : 207 : pm->dev = dev;
41 : :
42 : 207 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
43 : 207 : pm->base = devm_ioremap_resource(dev, res);
44 [ - + ]: 207 : if (IS_ERR(pm->base))
45 : 0 : return PTR_ERR(pm->base);
46 : :
47 : 207 : ret = devm_mfd_add_devices(dev, -1,
48 : : bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
49 : : NULL, 0, NULL);
50 [ + - ]: 207 : if (ret)
51 : : return ret;
52 : :
53 : : /* Map the RPiVid ASB regs if present. */
54 : 207 : res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
55 [ - + ]: 207 : 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 : 207 : res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
69 [ + - ]: 207 : if (res) {
70 : 207 : pm->asb = devm_ioremap_resource(dev, res);
71 [ - + ]: 207 : if (IS_ERR(pm->asb))
72 : 0 : return PTR_ERR(pm->asb);
73 : :
74 : 207 : ret = devm_mfd_add_devices(dev, -1,
75 : : bcm2835_power_devs,
76 : : ARRAY_SIZE(bcm2835_power_devs),
77 : : NULL, 0, NULL);
78 [ - + ]: 207 : 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 : 207 : 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");
|