diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-12-11 04:26:26 +0100 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-12-12 22:07:28 +0100 |
commit | 70c8f01a357ac74d223a632659787396fef1e649 (patch) | |
tree | aff7db7fdcc8bdb3fe74f6313c2b8701cfdc9d0b /drivers/pinctrl/sh-pfc/core.c | |
parent | 5b46ac3a7723636082ec6234289517ca5b9c65af (diff) |
sh-pfc: Support GPIO to IRQ mapping specified IRQ resources
On non-DT platforms IRQ controllers associated with the GPIOs have a
fixed IRQ base value known at compile time. The sh-pfc driver translates
GPIO number to IRQ numbers using a hardcoded table. This mechanism
breaks on DT platforms, as the IRQ base values are dynamic in that case.
Fix this by specifying IRQs associated with GPIOs in IRQ resources,
populated automatically from the device tree. When IRQ resources are
specified the driver requires one IRQ resource per GPIO able to generate
an interrupt, and uses the translation table to compute the IRQ resource
offset instead of the IRQ number.
Cc: devicetree@vger.kernel.org
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sh-pfc/core.c')
-rw-r--r-- | drivers/pinctrl/sh-pfc/core.c | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 7831f078a5ef..b9b464d0578c 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -26,30 +26,67 @@ #include "core.h" -static int sh_pfc_ioremap(struct sh_pfc *pfc, struct platform_device *pdev) +static int sh_pfc_map_resources(struct sh_pfc *pfc, + struct platform_device *pdev) { + unsigned int num_windows = 0; + unsigned int num_irqs = 0; + struct sh_pfc_window *windows; + unsigned int *irqs = NULL; struct resource *res; - unsigned int k; + unsigned int i; + + /* Count the MEM and IRQ resources. */ + for (i = 0; i < pdev->num_resources; ++i) { + switch (resource_type(&pdev->resource[i])) { + case IORESOURCE_MEM: + num_windows++; + break; + + case IORESOURCE_IRQ: + num_irqs++; + break; + } + } - if (pdev->num_resources == 0) + if (num_windows == 0) return -EINVAL; - pfc->windows = devm_kzalloc(pfc->dev, pdev->num_resources * - sizeof(*pfc->windows), GFP_NOWAIT); - if (!pfc->windows) + /* Allocate memory windows and IRQs arrays. */ + windows = devm_kzalloc(pfc->dev, num_windows * sizeof(*windows), + GFP_KERNEL); + if (windows == NULL) return -ENOMEM; - pfc->num_windows = pdev->num_resources; + pfc->num_windows = num_windows; + pfc->windows = windows; - for (k = 0, res = pdev->resource; k < pdev->num_resources; k++, res++) { - WARN_ON(resource_type(res) != IORESOURCE_MEM); - pfc->windows[k].phys = res->start; - pfc->windows[k].size = resource_size(res); - pfc->windows[k].virt = - devm_ioremap_nocache(pfc->dev, res->start, - resource_size(res)); - if (!pfc->windows[k].virt) + if (num_irqs) { + irqs = devm_kzalloc(pfc->dev, num_irqs * sizeof(*irqs), + GFP_KERNEL); + if (irqs == NULL) return -ENOMEM; + + pfc->num_irqs = num_irqs; + pfc->irqs = irqs; + } + + /* Fill them. */ + for (i = 0, res = pdev->resource; i < pdev->num_resources; i++, res++) { + switch (resource_type(res)) { + case IORESOURCE_MEM: + windows->phys = res->start; + windows->size = resource_size(res); + windows->virt = devm_ioremap_resource(pfc->dev, res); + if (IS_ERR(windows->virt)) + return -ENOMEM; + windows++; + break; + + case IORESOURCE_IRQ: + *irqs++ = res->start; + break; + } } return 0; @@ -482,7 +519,7 @@ static int sh_pfc_probe(struct platform_device *pdev) pfc->info = info; pfc->dev = &pdev->dev; - ret = sh_pfc_ioremap(pfc, pdev); + ret = sh_pfc_map_resources(pfc, pdev); if (unlikely(ret < 0)) return ret; |