aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Abraham <thomas.ab@samsung.com>2013-03-26 11:12:33 -0400
committerLinus Walleij <linus.walleij@linaro.org>2013-04-09 04:16:53 -0400
commit8dc3568d5527bfdb61afadea9284814a705b64ff (patch)
tree16d5bbaa5acff47e0a8fba2d3ca9d1233856109e
parentf9819739427e6049d2d318743a4a25817018afd4 (diff)
pinctrl: exynos5440: add gpio interrupt support
Exynos5440 supports gpio interrupts on gpios 16 to 23. The eight interrupt lines originating from the pin-controller are connected to the gic. Add irq-chip support for these interrupts. Signed-off-by: Thomas Abraham <thomas.ab@samsung.com> Cc: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
index 7126b7db86c5..6038503ed929 100644
--- a/drivers/pinctrl/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/pinctrl-exynos5440.c
@@ -20,6 +20,9 @@
20#include <linux/pinctrl/pinctrl.h> 20#include <linux/pinctrl/pinctrl.h>
21#include <linux/pinctrl/pinmux.h> 21#include <linux/pinctrl/pinmux.h>
22#include <linux/pinctrl/pinconf.h> 22#include <linux/pinctrl/pinconf.h>
23#include <linux/interrupt.h>
24#include <linux/irqdomain.h>
25#include <linux/of_irq.h>
23#include "core.h" 26#include "core.h"
24 27
25/* EXYNOS5440 GPIO and Pinctrl register offsets */ 28/* EXYNOS5440 GPIO and Pinctrl register offsets */
@@ -37,6 +40,7 @@
37#define GPIO_DS1 0x2C 40#define GPIO_DS1 0x2C
38 41
39#define EXYNOS5440_MAX_PINS 23 42#define EXYNOS5440_MAX_PINS 23
43#define EXYNOS5440_MAX_GPIO_INT 8
40#define PIN_NAME_LENGTH 10 44#define PIN_NAME_LENGTH 10
41 45
42#define GROUP_SUFFIX "-grp" 46#define GROUP_SUFFIX "-grp"
@@ -109,6 +113,7 @@ struct exynos5440_pmx_func {
109struct exynos5440_pinctrl_priv_data { 113struct exynos5440_pinctrl_priv_data {
110 void __iomem *reg_base; 114 void __iomem *reg_base;
111 struct gpio_chip *gc; 115 struct gpio_chip *gc;
116 struct irq_domain *irq_domain;
112 117
113 const struct exynos5440_pin_group *pin_groups; 118 const struct exynos5440_pin_group *pin_groups;
114 unsigned int nr_groups; 119 unsigned int nr_groups;
@@ -116,6 +121,16 @@ struct exynos5440_pinctrl_priv_data {
116 unsigned int nr_functions; 121 unsigned int nr_functions;
117}; 122};
118 123
124/**
125 * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
126 * @priv: driver's private runtime data.
127 * @gpio_int: gpio interrupt number.
128 */
129struct exynos5440_gpio_intr_data {
130 struct exynos5440_pinctrl_priv_data *priv;
131 unsigned int gpio_int;
132};
133
119/* list of all possible config options supported */ 134/* list of all possible config options supported */
120static struct pin_config { 135static struct pin_config {
121 char *prop_cfg; 136 char *prop_cfg;
@@ -598,6 +613,22 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse
598 return 0; 613 return 0;
599} 614}
600 615
616/* gpiolib gpio_to_irq callback function */
617static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
618{
619 struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
620 unsigned int virq;
621
622 if (offset < 16 || offset > 23)
623 return -ENXIO;
624
625 if (!priv->irq_domain)
626 return -ENXIO;
627
628 virq = irq_create_mapping(priv->irq_domain, offset - 16);
629 return virq ? : -ENXIO;
630}
631
601/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ 632/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
602static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, 633static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
603 struct device_node *cfg_np, unsigned int **pin_list, 634 struct device_node *cfg_np, unsigned int **pin_list,
@@ -821,6 +852,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
821 gc->get = exynos5440_gpio_get; 852 gc->get = exynos5440_gpio_get;
822 gc->direction_input = exynos5440_gpio_direction_input; 853 gc->direction_input = exynos5440_gpio_direction_input;
823 gc->direction_output = exynos5440_gpio_direction_output; 854 gc->direction_output = exynos5440_gpio_direction_output;
855 gc->to_irq = exynos5440_gpio_to_irq;
824 gc->label = "gpiolib-exynos5440"; 856 gc->label = "gpiolib-exynos5440";
825 gc->owner = THIS_MODULE; 857 gc->owner = THIS_MODULE;
826 ret = gpiochip_add(gc); 858 ret = gpiochip_add(gc);
@@ -845,6 +877,110 @@ static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
845 return 0; 877 return 0;
846} 878}
847 879
880static void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
881{
882 struct exynos5440_pinctrl_priv_data *d;
883 unsigned long gpio_int;
884
885 d = irq_data_get_irq_chip_data(irqd);
886 gpio_int = readl(d->reg_base + GPIO_INT);
887 gpio_int |= 1 << irqd->hwirq;
888 writel(gpio_int, d->reg_base + GPIO_INT);
889}
890
891static void exynos5440_gpio_irq_mask(struct irq_data *irqd)
892{
893 struct exynos5440_pinctrl_priv_data *d;
894 unsigned long gpio_int;
895
896 d = irq_data_get_irq_chip_data(irqd);
897 gpio_int = readl(d->reg_base + GPIO_INT);
898 gpio_int &= ~(1 << irqd->hwirq);
899 writel(gpio_int, d->reg_base + GPIO_INT);
900}
901
902/* irq_chip for gpio interrupts */
903static struct irq_chip exynos5440_gpio_irq_chip = {
904 .name = "exynos5440_gpio_irq_chip",
905 .irq_unmask = exynos5440_gpio_irq_unmask,
906 .irq_mask = exynos5440_gpio_irq_mask,
907};
908
909/* interrupt handler for GPIO interrupts 0..7 */
910static irqreturn_t exynos5440_gpio_irq(int irq, void *data)
911{
912 struct exynos5440_gpio_intr_data *intd = data;
913 struct exynos5440_pinctrl_priv_data *d = intd->priv;
914 int virq;
915
916 virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
917 if (!virq)
918 return IRQ_NONE;
919 generic_handle_irq(virq);
920 return IRQ_HANDLED;
921}
922
923static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
924 irq_hw_number_t hw)
925{
926 struct exynos5440_pinctrl_priv_data *d = h->host_data;
927
928 irq_set_chip_data(virq, d);
929 irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
930 handle_level_irq);
931 set_irq_flags(virq, IRQF_VALID);
932 return 0;
933}
934
935/* irq domain callbacks for gpio interrupt controller */
936static const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
937 .map = exynos5440_gpio_irq_map,
938 .xlate = irq_domain_xlate_twocell,
939};
940
941/* setup handling of gpio interrupts */
942static int exynos5440_gpio_irq_init(struct platform_device *pdev,
943 struct exynos5440_pinctrl_priv_data *priv)
944{
945 struct device *dev = &pdev->dev;
946 struct exynos5440_gpio_intr_data *intd;
947 int i, irq, ret;
948
949 intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
950 GFP_KERNEL);
951 if (!intd) {
952 dev_err(dev, "failed to allocate memory for gpio intr data\n");
953 return -ENOMEM;
954 }
955
956 for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
957 irq = irq_of_parse_and_map(dev->of_node, i);
958 if (irq <= 0) {
959 dev_err(dev, "irq parsing failed\n");
960 return -EINVAL;
961 }
962
963 intd->gpio_int = i;
964 intd->priv = priv;
965 ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
966 0, dev_name(dev), intd++);
967 if (ret) {
968 dev_err(dev, "irq request failed\n");
969 return -ENXIO;
970 }
971 }
972
973 priv->irq_domain = irq_domain_add_linear(dev->of_node,
974 EXYNOS5440_MAX_GPIO_INT,
975 &exynos5440_gpio_irqd_ops, priv);
976 if (!priv->irq_domain) {
977 dev_err(dev, "failed to create irq domain\n");
978 return -ENXIO;
979 }
980
981 return 0;
982}
983
848static int exynos5440_pinctrl_probe(struct platform_device *pdev) 984static int exynos5440_pinctrl_probe(struct platform_device *pdev)
849{ 985{
850 struct device *dev = &pdev->dev; 986 struct device *dev = &pdev->dev;
@@ -883,6 +1019,12 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
883 return ret; 1019 return ret;
884 } 1020 }
885 1021
1022 ret = exynos5440_gpio_irq_init(pdev, priv);
1023 if (ret) {
1024 dev_err(dev, "failed to setup gpio interrupts\n");
1025 return ret;
1026 }
1027
886 platform_set_drvdata(pdev, priv); 1028 platform_set_drvdata(pdev, priv);
887 dev_info(dev, "EXYNOS5440 pinctrl driver registered\n"); 1029 dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
888 return 0; 1030 return 0;