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