From b313346b1a92df8bd65bfa590e15b1b1bd48f86f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 18 Jul 2016 08:14:45 -0700 Subject: mfd: syscon: Decouple syscon interface from platform devices Follow Linux Kernel change introduced in bdb0066df96e74a4002125467ebe459feff1ebef and avoid device/driver model for DT-based platforms. See the original kernel commit for the rationale. Also make syscon_base_lookup_by_pdevname() behave the same way as its kernel counterpart in the case whern "property" argument is NULL. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/mfd/syscon.c | 79 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index ac46122c6b..cf1d2dfd58 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -17,15 +17,68 @@ #include #include #include - +#include #include #include +static LIST_HEAD(syscon_list); + struct syscon { + struct device_node *np; void __iomem *base; + struct list_head list; }; +static struct syscon *of_syscon_register(struct device_node *np) +{ + int ret; + struct syscon *syscon; + struct resource res; + + if (!of_device_is_compatible(np, "syscon")) + return ERR_PTR(-EINVAL); + + syscon = xzalloc(sizeof(*syscon)); + + if (of_address_to_resource(np, 0, &res)) { + ret = -ENOMEM; + goto err_map; + } + + syscon->base = IOMEM(res.start); + syscon->np = np; + + list_add_tail(&syscon->list, &syscon_list); + + return syscon; + +err_map: + kfree(syscon); + return ERR_PTR(ret); +} + +static void __iomem *syscon_node_to_base(struct device_node *np) +{ + struct syscon *entry, *syscon = NULL; + + list_for_each_entry(entry, &syscon_list, list) + if (entry->np == np) { + syscon = entry; + break; + } + + if (!syscon) + syscon = of_syscon_register(np); + + if (IS_ERR(syscon)) + return ERR_CAST(syscon); + + return syscon->base; +} +EXPORT_SYMBOL_GPL(syscon_node_to_regmap); + + void __iomem *syscon_base_lookup_by_pdevname(const char *s) { struct syscon *syscon; @@ -44,21 +97,17 @@ void __iomem *syscon_base_lookup_by_pdevname(const char *s) void __iomem *syscon_base_lookup_by_phandle(struct device_node *np, const char *property) { - struct device_node *node; - struct syscon *syscon; - struct device_d *dev; + struct device_node *syscon_np; - node = of_parse_phandle(np, property, 0); - if (!node) - return ERR_PTR(-ENODEV); + if (property) + syscon_np = of_parse_phandle(np, property, 0); + else + syscon_np = np; - dev = of_find_device_by_node(node); - if (!dev) + if (!syscon_np) return ERR_PTR(-ENODEV); - syscon = dev->priv; - - return syscon->base; + return syscon_node_to_base(syscon_np); } static int syscon_probe(struct device_d *dev) @@ -89,16 +138,10 @@ static struct platform_device_id syscon_ids[] = { { } }; -static struct of_device_id of_syscon_match[] = { - { .compatible = "syscon" }, - { }, -}; - static struct driver_d syscon_driver = { .name = "syscon", .probe = syscon_probe, .id_table = syscon_ids, - .of_compatible = DRV_OF_COMPAT(of_syscon_match), }; static int __init syscon_init(void) -- cgit v1.2.3