0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/err.h>
0013 #include <linux/io.h>
0014 #include <linux/of.h>
0015 #include <linux/of_address.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/init.h>
0018 #include <linux/slab.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/bitops.h>
0021 #include <linux/mfd/syscon.h>
0022 #include <linux/regmap.h>
0023
0024
0025 #define INTEGRATOR_SC_DEC_OFFSET 0x10
0026
0027
0028 #define INTEGRATOR_AP_EXP_BASE 0xc0000000
0029 #define INTEGRATOR_AP_EXP_STRIDE 0x10000000
0030
0031 static int integrator_lm_populate(int num, struct device *dev)
0032 {
0033 struct device_node *np = dev->of_node;
0034 struct device_node *child;
0035 u32 base;
0036 int ret;
0037
0038 base = INTEGRATOR_AP_EXP_BASE + (num * INTEGRATOR_AP_EXP_STRIDE);
0039
0040
0041 for_each_available_child_of_node(np, child) {
0042 struct resource res;
0043
0044 ret = of_address_to_resource(child, 0, &res);
0045 if (ret) {
0046 dev_info(dev, "no valid address on child\n");
0047 continue;
0048 }
0049
0050
0051 if (res.start == base) {
0052 dev_info(dev, "populate module @0x%08x from DT\n",
0053 base);
0054 ret = of_platform_default_populate(child, NULL, dev);
0055 if (ret) {
0056 dev_err(dev, "failed to populate module\n");
0057 of_node_put(child);
0058 return ret;
0059 }
0060 }
0061 }
0062
0063 return 0;
0064 }
0065
0066 static const struct of_device_id integrator_ap_syscon_match[] = {
0067 { .compatible = "arm,integrator-ap-syscon"},
0068 { },
0069 };
0070
0071 static int integrator_ap_lm_probe(struct platform_device *pdev)
0072 {
0073 struct device *dev = &pdev->dev;
0074 struct device_node *syscon;
0075 static struct regmap *map;
0076 u32 val;
0077 int ret;
0078 int i;
0079
0080
0081 syscon = of_find_matching_node(NULL, integrator_ap_syscon_match);
0082 if (!syscon) {
0083 dev_err(dev,
0084 "could not find Integrator/AP system controller\n");
0085 return -ENODEV;
0086 }
0087 map = syscon_node_to_regmap(syscon);
0088 if (IS_ERR(map)) {
0089 dev_err(dev,
0090 "could not find Integrator/AP system controller\n");
0091 return PTR_ERR(map);
0092 }
0093
0094 ret = regmap_read(map, INTEGRATOR_SC_DEC_OFFSET, &val);
0095 if (ret) {
0096 dev_err(dev, "could not read from Integrator/AP syscon\n");
0097 return ret;
0098 }
0099
0100
0101 for (i = 0; i < 4; i++) {
0102 if (!(val & BIT(4 + i)))
0103 continue;
0104
0105 dev_info(dev, "detected module in slot %d\n", i);
0106 ret = integrator_lm_populate(i, dev);
0107 if (ret)
0108 return ret;
0109 }
0110
0111 return 0;
0112 }
0113
0114 static const struct of_device_id integrator_ap_lm_match[] = {
0115 { .compatible = "arm,integrator-ap-lm"},
0116 { },
0117 };
0118
0119 static struct platform_driver integrator_ap_lm_driver = {
0120 .probe = integrator_ap_lm_probe,
0121 .driver = {
0122 .name = "integratorap-lm",
0123 .of_match_table = integrator_ap_lm_match,
0124 },
0125 };
0126 module_platform_driver(integrator_ap_lm_driver);
0127 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0128 MODULE_DESCRIPTION("Integrator AP Logical Module driver");
0129 MODULE_LICENSE("GPL v2");