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