From patchwork Fri Jun 7 20:50:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 2690111 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 55521DFB78 for ; Fri, 7 Jun 2013 21:23:02 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ul3fJ-0007af-6b; Fri, 07 Jun 2013 20:53:44 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ul3dR-00086H-QH; Fri, 07 Jun 2013 20:51:45 +0000 Received: from mho-02-ewr.mailhop.org ([204.13.248.72]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ul3cp-000824-78 for linux-arm-kernel@lists.infradead.org; Fri, 07 Jun 2013 20:51:15 +0000 Received: from c-50-131-214-131.hsd1.ca.comcast.net ([50.131.214.131] helo=[127.0.0.1]) by mho-02-ewr.mailhop.org with esmtpa (Exim 4.72) (envelope-from ) id 1Ul3cT-00062M-G9; Fri, 07 Jun 2013 20:50:45 +0000 X-Mail-Handler: Dyn Standard SMTP by Dyn X-Originating-IP: 50.131.214.131 X-Report-Abuse-To: abuse@dyndns.com (see http://www.dyndns.com/services/sendlabs/outbound_abuse.html for abuse reporting information) X-MHO-User: U2FsdGVkX188+f+i/YWQBNF9QbF67Mea Subject: [PATCH 3/4] pinctrl: single: omap: Add SoC specific module for wake-up events To: linus.walleij@linaro.org From: Tony Lindgren Date: Fri, 07 Jun 2013 13:50:44 -0700 Message-ID: <20130607205044.16513.27675.stgit@localhost> In-Reply-To: <20130607203936.16513.57494.stgit@localhost> References: <20130607203936.16513.57494.stgit@localhost> User-Agent: StGit/0.16-1-ga54b MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130607_165107_339879_B270F203 X-CRM114-Status: GOOD ( 20.72 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [204.13.248.72 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: devicetree-discuss@lists.ozlabs.org, Haojian Zhuang , Peter Ujfalusi , linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Roger Quadros 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: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org For wake-up events from deeper idle modes we need to check the configured padconf registers for the wake-up bit and then call the related interrupt handler. Done in collaboration with Roger Quadros . Cc: Haojian Zhuang Cc: Peter Ujfalusi Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: Roger Quadros Signed-off-by: Tony Lindgren Acked-by: Haojian Zhuang --- drivers/pinctrl/Makefile | 3 drivers/pinctrl/pinctrl-single-omap.c | 287 +++++++++++++++++++++ include/linux/platform_data/pinctrl-single-omap.h | 4 3 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 drivers/pinctrl/pinctrl-single-omap.c create mode 100644 include/linux/platform_data/pinctrl-single-omap.h diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 9bdaeb8..abf7f01 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -30,7 +30,8 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o -obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o +pcs-$(CONFIG_ARCH_OMAP2PLUS) += pinctrl-single-omap.o +obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o $(pcs-y) obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o diff --git a/drivers/pinctrl/pinctrl-single-omap.c b/drivers/pinctrl/pinctrl-single-omap.c new file mode 100644 index 0000000..680cf81 --- /dev/null +++ b/drivers/pinctrl/pinctrl-single-omap.c @@ -0,0 +1,287 @@ +/* + * pinctrl-single-omap - omap specific wake-up irq handler + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-single.h" + +#define OMAP_WAKEUP_EN (1 << 14) +#define OMAP_WAKEUP_EVENT (1 << 15) +#define OMAP_WAKEUP_EVENT_MASK (OMAP_WAKEUP_EN | OMAP_WAKEUP_EVENT) + +struct pcs_omap { + unsigned int irq; + struct device *dev; + struct list_head wakeirqs; + struct pcs_soc soc; + void (*reconfigure_io_chain)(void); + struct mutex mutex; +}; + +static int pcs_omap_reg_init(const struct pcs_soc *soc, struct pcs_reg *r) +{ + struct pcs_omap *pcso = container_of(soc, struct pcs_omap, soc); + struct list_head *pos; + struct pcs_reg *pcsoi; + int res = 0; + + if (!(r->val & OMAP_WAKEUP_EN)) + return 0; + + if (r->irq <= 0) + return 0; + + mutex_lock(&pcso->mutex); + list_for_each(pos, &pcso->wakeirqs) { + pcsoi = list_entry(pos, struct pcs_reg, node); + if (r->reg == pcsoi->reg) { + pcsoi->read = r->read; + pcsoi->write = r->write; + pcsoi->reg = r->reg; + pcsoi->val = r->val; + pcsoi->irq = r->irq; + pcsoi->gpio = r->gpio; + res++; + goto out; + } + } + pcsoi = devm_kzalloc(pcso->dev, sizeof(*r), GFP_KERNEL); + if (!pcsoi) { + mutex_unlock(&pcso->mutex); + res = -ENOMEM; + goto out; + } + *pcsoi = *r; + list_add_tail(&pcsoi->node, &pcso->wakeirqs); + +out: + mutex_unlock(&pcso->mutex); + + if (res && pcso->reconfigure_io_chain) + pcso->reconfigure_io_chain(); + + return res > 0 ? 0 : res; +} + +static int pcs_update_list(const struct pcs_soc *soc, struct pcs_reg *r) +{ + struct pcs_omap *pcso = container_of(soc, struct pcs_omap, soc); + struct list_head *pos; + int changed = 0; + + if (!r->irq) + return 0; + + mutex_lock(&pcso->mutex); + list_for_each(pos, &pcso->wakeirqs) { + struct pcs_reg *pcsoi; + + pcsoi = list_entry(pos, struct pcs_reg, node); + if ((r->reg == pcsoi->reg) && + (r->val != pcsoi->val)) { + pcsoi->val = r->val; + changed++; + } + } + mutex_unlock(&pcso->mutex); + + if (pcso->reconfigure_io_chain && changed) + pcso->reconfigure_io_chain(); + + return 0; +} + +static int pcs_omap_enable(const struct pcs_soc *soc, struct pcs_reg *r) +{ + return pcs_update_list(soc, r); +} + +static void pcs_omap_disable(const struct pcs_soc *soc, struct pcs_reg *r) +{ + pcs_update_list(soc, r); +} + +static irqreturn_t pcs_omap_handle_irq(int irq, void *data) +{ + struct pcs_omap *pcso = data; + struct list_head *pos; + unsigned int wakeirq; + + list_for_each(pos, &pcso->wakeirqs) { + struct pcs_reg *pcsoi; + u16 val; + + pcsoi = list_entry(pos, struct pcs_reg, node); + wakeirq = pcsoi->irq; + val = pcsoi->read(pcsoi->reg); + if ((val & OMAP_WAKEUP_EVENT_MASK) == OMAP_WAKEUP_EVENT_MASK) + generic_handle_irq(wakeirq); + } + + if (pcso->reconfigure_io_chain) + pcso->reconfigure_io_chain(); + + return IRQ_HANDLED; +} + +/* + * Note that omap2430 has 8-bit padconf registers and uses + * the plain pinctrl-single binding. + */ +static const struct of_device_id pcs_omap_of_match[] = { + { .compatible = "ti,omap3-padconf", }, + { .compatible = "ti,omap4-padconf", }, + { .compatible = "ti,omap5-padconf", }, + {} +}; +MODULE_DEVICE_TABLE(of, pcs_omap_of_match); + +/* SoC glue */ +static bool soc_found; +static unsigned int soc_irq; +static void (*soc_reconfigure_io_chain)(void); + +/* Fill in the SoC glue */ +static int pcs_omap_soc_probe(struct platform_device *pdev) +{ + struct pcs_omap_pdata *pdata = pdev->dev.platform_data; + + if (pdata) { + soc_irq = pdata->irq; + soc_reconfigure_io_chain = pdata->reconfigure_io_chain; + soc_found = true; + } + + return 0; +} + +static int pcs_omap_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct pcs_omap *pcso; + struct pcs_soc *soc; + int ret; + + match = of_match_device(pcs_omap_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "no match found\n"); + return -ENODEV; + } + + if (!soc_found) { + dev_dbg(&pdev->dev, + "%s deferring as SoC glue not yet registered\n", + __func__); + return -EPROBE_DEFER; + } + + pcso = devm_kzalloc(&pdev->dev, sizeof(*pcso), GFP_KERNEL); + if (!pcso) + return -ENOMEM; + + pcso->dev = &pdev->dev; + mutex_init(&pcso->mutex); + INIT_LIST_HEAD(&pcso->wakeirqs); + pcso->irq = soc_irq; + pcso->reconfigure_io_chain = soc_reconfigure_io_chain; + soc = &pcso->soc; + soc->reg_init = pcs_omap_reg_init; + soc->enable = pcs_omap_enable; + soc->disable = pcs_omap_disable; + soc->flags = PCS_HAS_FUNCTION_GPIO | PCS_HAS_FUNCTION_IRQ; + + ret = pinctrl_single_probe(pdev, soc); + if (ret) { + dev_err(&pdev->dev, "could not probe pictrl_single driver: %i\n", + ret); + return ret; + } + + ret = request_irq(soc_irq, pcs_omap_handle_irq, + IRQF_SHARED | IRQF_NO_SUSPEND, + "pinctrl-single-omap", pcso); + if (ret) { + dev_err(&pdev->dev, "could not get irq%i: %i\n", + soc_irq, ret); + return ret; + } + + platform_set_drvdata(pdev, pcso); + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int pcs_omap_remove(struct platform_device *pdev) +{ + struct pcs_omap *pcso = platform_get_drvdata(pdev); + + pinctrl_single_remove(pdev); + free_irq(pcso->irq, NULL); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver pcs_omap_driver = { + .probe = pcs_omap_probe, + .remove = pcs_omap_remove, + .driver = { + .name = "pinctrl-single-omap", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcs_omap_of_match), + }, +}; + +/* Dummy driver for registering SoC glue */ +static struct platform_driver pcs_omap_soc_driver = { + .probe = pcs_omap_soc_probe, + .driver = { + .name = "pinctrl-single-omap-soc", + .owner = THIS_MODULE, + }, +}; + +static int __init pcs_omap_init(void) +{ + platform_driver_register(&pcs_omap_soc_driver); + platform_driver_register(&pcs_omap_driver); + + return 0; +} +module_init(pcs_omap_init); + +static void __exit pcs_omap_exit(void) +{ + platform_driver_unregister(&pcs_omap_driver); + platform_driver_unregister(&pcs_omap_soc_driver); +} +module_exit(pcs_omap_exit); + +MODULE_ALIAS("platform: pinctrl-single-omap"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("pinctrl-single-omap driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/pinctrl-single-omap.h b/include/linux/platform_data/pinctrl-single-omap.h new file mode 100644 index 0000000..bd92efc --- /dev/null +++ b/include/linux/platform_data/pinctrl-single-omap.h @@ -0,0 +1,4 @@ +struct pcs_omap_pdata { + int irq; + void (*reconfigure_io_chain)(void); +};