From patchwork Mon Feb 10 15:22:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Simek X-Patchwork-Id: 3619221 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E1A38BF418 for ; Mon, 10 Feb 2014 15:28:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CF03F201CD for ; Mon, 10 Feb 2014 15:28:58 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9E74F2012D for ; Mon, 10 Feb 2014 15:28:57 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WCsmi-0004ad-3b; Mon, 10 Feb 2014 15:28:36 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WCshp-0007XQ-Jo; Mon, 10 Feb 2014 15:23:33 +0000 Received: from mail-ea0-f169.google.com ([209.85.215.169]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WCshl-0007Ux-Th for linux-arm-kernel@lists.infradead.org; Mon, 10 Feb 2014 15:23:31 +0000 Received: by mail-ea0-f169.google.com with SMTP id h10so3104361eak.14 for ; Mon, 10 Feb 2014 07:23:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:in-reply-to:references:content-type; bh=yrfS91kO2JzXYRNw8b4NBwW5ELyFojuKe7+m6BpwcDM=; b=A/BqWI7I4nWjZVYurskT1jxPa4XYB/kMbTtTvJLp+mukhksxpHfweYGRk5DguRu8Jb btrs0JDoDIMwI49XbCcuR0V7RQi6d6ykLAi5TCRDZgNmWWQbDJTlD/bUzXAFJMITqx7J q19DbfyJuocOHWZJDq4KI/8gVhIOrPWrYn14kqMvkIK5vEJqt2O15aKrQP2wE7fxixSk QzDuZV1MCDBYKnlJUAn6RqA2VtfBzGtXnmqzGMm70h9d4JyWeaQDVVYCQNoEmbAr1Gtk FI/IPHlYDt7Uni+kcJa0+HihMQ1UJEMoVIPKupcH7oH0NYYistmOG1pkJBNQj/idAseJ yzHg== X-Gm-Message-State: ALoCoQl6ZiNSsZtXu8jhrMchuf8Qga/wNk3ii7NcRiPeGZHHk3IOXdcTriJCTzqyHp2qnrBnyXxR X-Received: by 10.14.219.73 with SMTP id l49mr890210eep.112.1392045787943; Mon, 10 Feb 2014 07:23:07 -0800 (PST) Received: from localhost (nat-63.starnet.cz. [178.255.168.63]) by mx.google.com with ESMTPSA id f45sm55532119eeg.5.2014.02.10.07.23.05 for (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Mon, 10 Feb 2014 07:23:06 -0800 (PST) From: Michal Simek To: linux-arm-kernel@lists.infradead.org, Arnd Bergmann Subject: [RFC PATCH 2/3] mfd: syscon: Support early initialization Date: Mon, 10 Feb 2014 16:22:34 +0100 Message-Id: <1785585d090175da81b561b17eeef95d991ff0de.1392045742.git.michal.simek@xilinx.com> X-Mailer: git-send-email 1.8.2.3 In-Reply-To: References: In-Reply-To: References: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140210_102330_220496_1F90B47A X-CRM114-Status: GOOD ( 23.25 ) X-Spam-Score: -1.9 (-) Cc: Michal Simek , Lee Jones , Samuel Ortiz , linux-kernel@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some platforms need to get system controller ready as soon as possible. The patch provides early_syscon_initialization which create early mapping for all syscon compatible devices in early_syscon_probe. Regmap is get via syscon_early_regmap_lookup_by_phandle() Regular device probes attach device to regmap via regmap_attach_dev(). For early syscon initialization is necessary to extend struct syscon and provide remove function which unmap all early init structures. Signed-off-by: Michal Simek --- drivers/mfd/syscon.c | 126 +++++++++++++++++++++++++++++++++++++++------ include/linux/mfd/syscon.h | 11 ++++ 2 files changed, 120 insertions(+), 17 deletions(-) -- 1.8.2.3 diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 71841f9..5935f02 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -20,12 +20,15 @@ #include #include #include +#include #include static struct platform_driver syscon_driver; struct syscon { + void __iomem *base; struct regmap *regmap; + struct resource res; }; static int syscon_match_node(struct device *dev, void *data) @@ -95,6 +98,24 @@ struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); +struct regmap *syscon_early_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *syscon_np; + struct syscon *syscon; + + syscon_np = of_parse_phandle(np, property, 0); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + syscon = syscon_np->data; + + of_node_put(syscon_np); + + return syscon->regmap; +} +EXPORT_SYMBOL_GPL(syscon_early_regmap_lookup_by_phandle); + struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, const char *property) { @@ -128,40 +149,110 @@ static int syscon_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct syscon *syscon; struct resource *res; - void __iomem *base; - syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); + /* Early syscon init */ + if (pdev->dev.of_node && pdev->dev.of_node->data) { + syscon = pdev->dev.of_node->data; + res = &syscon->res; + regmap_attach_dev(dev, syscon->regmap, &syscon_regmap_config); + } else { + + syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); + if (!syscon) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + syscon->base = devm_ioremap(dev, res->start, + resource_size(res)); + if (!syscon->base) + return -ENOMEM; + + syscon_regmap_config.max_register = res->end - res->start - 3; + syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + &syscon_regmap_config); + if (IS_ERR(syscon->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(syscon->regmap); + } + } + + platform_set_drvdata(pdev, syscon); + + dev_info(dev, "regmap %pR registered\n", res); + + return 0; +} + +static const struct platform_device_id syscon_ids[] = { + { "syscon", }, + { } +}; + +static int syscon_remove(struct platform_device *pdev) +{ + struct syscon *syscon = platform_get_drvdata(pdev); + + if (pdev->dev.of_node && pdev->dev.of_node->data) { + iounmap(syscon->base); + kfree(syscon); + } + + return 0; +} + +static int early_syscon_probe(struct device_node *np) +{ + struct syscon *syscon; + + syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); if (!syscon) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; + if (of_address_to_resource(np, 0, &syscon->res)) + return -EINVAL; - base = devm_ioremap(dev, res->start, resource_size(res)); - if (!base) - return -ENOMEM; + syscon->base = ioremap(syscon->res.start, resource_size(&syscon->res)); + if (!syscon->base) { + pr_err("%s: Unable to map I/O memory\n", __func__); + return PTR_ERR(syscon->base); + } - syscon_regmap_config.max_register = res->end - res->start - 3; - syscon->regmap = devm_regmap_init_mmio(dev, base, - &syscon_regmap_config); + syscon_regmap_config.max_register = syscon->res.end - + syscon->res.start - 3; + syscon->regmap = regmap_init_mmio(NULL, syscon->base, + &syscon_regmap_config); if (IS_ERR(syscon->regmap)) { - dev_err(dev, "regmap init failed\n"); + pr_err("regmap init failed\n"); return PTR_ERR(syscon->regmap); } - platform_set_drvdata(pdev, syscon); + np->data = syscon; - dev_info(dev, "regmap %pR registered\n", res); + of_node_put(np); + + pr_info("%s: regmap %pR registered\n", np->full_name, &syscon->res); return 0; } -static const struct platform_device_id syscon_ids[] = { - { "syscon", }, - { } +static struct of_device_id of_syscon_ids[] = { + { .compatible = "syscon" }, + {}, }; +void __init early_syscon_init(void) +{ + struct device_node *np; + + for_each_matching_node_and_match(np, of_syscon_ids, NULL) { + if (!early_syscon_probe(np)) + BUG(); + } +} + static struct platform_driver syscon_driver = { .driver = { .name = "syscon", @@ -169,6 +260,7 @@ static struct platform_driver syscon_driver = { .of_match_table = of_syscon_match, }, .probe = syscon_probe, + .remove = syscon_remove, .id_table = syscon_ids, }; diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 8789fa3..465c092 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -24,6 +24,10 @@ extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s); extern struct regmap *syscon_regmap_lookup_by_phandle( struct device_node *np, const char *property); +extern struct regmap *syscon_early_regmap_lookup_by_phandle( + struct device_node *np, + const char *property); +extern void early_syscon_init(void); #else static inline struct regmap *syscon_node_to_regmap(struct device_node *np) { @@ -46,6 +50,13 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle( { return ERR_PTR(-ENOSYS); } + +static struct regmap *syscon_early_regmap_lookup_by_phandle( + struct device_node *np, + const char *property) +{ + return ERR_PTR(-ENOSYS); +} #endif #endif /* __LINUX_MFD_SYSCON_H__ */