ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 1) // SPDX-License-Identifier: GPL-2.0-only
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 2) /*
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 3) * ARM Integrator Logical Module bus driver
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 4) * Copyright (C) 2020 Linaro Ltd.
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 5) * Author: Linus Walleij <linus.walleij@linaro.org>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 6) *
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 7) * See the device tree bindings for this block for more details on the
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 8) * hardware.
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 9) */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 10)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 11) #include <linux/module.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 12) #include <linux/err.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 13) #include <linux/io.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 14) #include <linux/of.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 15) #include <linux/of_address.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 16) #include <linux/of_platform.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 17) #include <linux/init.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 18) #include <linux/slab.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 19) #include <linux/platform_device.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 20) #include <linux/bitops.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 21) #include <linux/mfd/syscon.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 22) #include <linux/regmap.h>
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 23)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 24) /* All information about the connected logic modules are in here */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 25) #define INTEGRATOR_SC_DEC_OFFSET 0x10
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 26)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 27) /* Base address for the expansion modules */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 28) #define INTEGRATOR_AP_EXP_BASE 0xc0000000
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 29) #define INTEGRATOR_AP_EXP_STRIDE 0x10000000
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 30)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 31) static int integrator_lm_populate(int num, struct device *dev)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 32) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 33) struct device_node *np = dev->of_node;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 34) struct device_node *child;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 35) u32 base;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 36) int ret;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 37)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 38) base = INTEGRATOR_AP_EXP_BASE + (num * INTEGRATOR_AP_EXP_STRIDE);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 39)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 40) /* Walk over the child nodes and see what chipselects we use */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 41) for_each_available_child_of_node(np, child) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 42) struct resource res;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 43)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 44) ret = of_address_to_resource(child, 0, &res);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 45) if (ret) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 46) dev_info(dev, "no valid address on child\n");
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 47) continue;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 48) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 49)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 50) /* First populate the syscon then any devices */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 51) if (res.start == base) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 52) dev_info(dev, "populate module @0x%08x from DT\n",
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 53) base);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 54) ret = of_platform_default_populate(child, NULL, dev);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 55) if (ret) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 56) dev_err(dev, "failed to populate module\n");
1740e6736922c (Sumera Priyadarsini 2021-01-12 10:25:49 +0100 57) of_node_put(child);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 58) return ret;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 59) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 60) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 61) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 62)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 63) return 0;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 64) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 65)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 66) static const struct of_device_id integrator_ap_syscon_match[] = {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 67) { .compatible = "arm,integrator-ap-syscon"},
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 68) { },
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 69) };
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 70)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 71) static int integrator_ap_lm_probe(struct platform_device *pdev)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 72) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 73) struct device *dev = &pdev->dev;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 74) struct device_node *syscon;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 75) static struct regmap *map;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 76) u32 val;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 77) int ret;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 78) int i;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 79)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 80) /* Look up the system controller */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 81) syscon = of_find_matching_node(NULL, integrator_ap_syscon_match);
97a2f40e38019 (Wei Yongjun 2020-05-25 11:16:34 +0200 82) if (!syscon) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 83) dev_err(dev,
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 84) "could not find Integrator/AP system controller\n");
97a2f40e38019 (Wei Yongjun 2020-05-25 11:16:34 +0200 85) return -ENODEV;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 86) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 87) map = syscon_node_to_regmap(syscon);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 88) if (IS_ERR(map)) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 89) dev_err(dev,
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 90) "could not find Integrator/AP system controller\n");
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 91) return PTR_ERR(map);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 92) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 93)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 94) ret = regmap_read(map, INTEGRATOR_SC_DEC_OFFSET, &val);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 95) if (ret) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 96) dev_err(dev, "could not read from Integrator/AP syscon\n");
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 97) return ret;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 98) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 99)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 100) /* Loop over the connected modules */
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 101) for (i = 0; i < 4; i++) {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 102) if (!(val & BIT(4 + i)))
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 103) continue;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 104)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 105) dev_info(dev, "detected module in slot %d\n", i);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 106) ret = integrator_lm_populate(i, dev);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 107) if (ret)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 108) return ret;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 109) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 110)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 111) return 0;
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 112) }
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 113)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 114) static const struct of_device_id integrator_ap_lm_match[] = {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 115) { .compatible = "arm,integrator-ap-lm"},
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 116) { },
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 117) };
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 118)
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 119) static struct platform_driver integrator_ap_lm_driver = {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 120) .probe = integrator_ap_lm_probe,
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 121) .driver = {
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 122) .name = "integratorap-lm",
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 123) .of_match_table = integrator_ap_lm_match,
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 124) },
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 125) };
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 126) module_platform_driver(integrator_ap_lm_driver);
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 127) MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 128) MODULE_DESCRIPTION("Integrator AP Logical Module driver");
ccea5e8a59181 (Linus Walleij 2020-02-13 13:41:23 +0100 129) MODULE_LICENSE("GPL v2");