diff options
author | Lee Jones <lee.jones@linaro.org> | 2012-11-05 10:10:31 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-11-11 17:35:03 -0500 |
commit | 76f93992e4c44f30be797d5c99d6f369ed001747 (patch) | |
tree | f4ece6f5b6cf7bcd06f3460640b01807fae6fc0a | |
parent | 7da0cbfc54c82eec793ff3d1b23b7a25406c6dba (diff) |
mfd: Provide the STMPE driver with its own IRQ domain
The STMPE driver is yet another IRQ controller which requires its
own IRQ domain. So, we provide it with one.
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/mfd/stmpe.c | 82 | ||||
-rw-r--r-- | include/linux/mfd/stmpe.h | 2 |
2 files changed, 52 insertions, 32 deletions
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index ad13cb00a749..5c8d8f260df2 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/irqdomain.h> | ||
15 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
@@ -757,7 +758,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
757 | int i; | 758 | int i; |
758 | 759 | ||
759 | if (variant->id_val == STMPE801_ID) { | 760 | if (variant->id_val == STMPE801_ID) { |
760 | handle_nested_irq(stmpe->irq_base); | 761 | int base = irq_create_mapping(stmpe->domain, 0); |
762 | |||
763 | handle_nested_irq(base); | ||
761 | return IRQ_HANDLED; | 764 | return IRQ_HANDLED; |
762 | } | 765 | } |
763 | 766 | ||
@@ -778,8 +781,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
778 | while (status) { | 781 | while (status) { |
779 | int bit = __ffs(status); | 782 | int bit = __ffs(status); |
780 | int line = bank * 8 + bit; | 783 | int line = bank * 8 + bit; |
784 | int nestedirq = irq_create_mapping(stmpe->domain, line); | ||
781 | 785 | ||
782 | handle_nested_irq(stmpe->irq_base + line); | 786 | handle_nested_irq(nestedirq); |
783 | status &= ~(1 << bit); | 787 | status &= ~(1 << bit); |
784 | } | 788 | } |
785 | 789 | ||
@@ -820,7 +824,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data) | |||
820 | static void stmpe_irq_mask(struct irq_data *data) | 824 | static void stmpe_irq_mask(struct irq_data *data) |
821 | { | 825 | { |
822 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); | 826 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
823 | int offset = data->irq - stmpe->irq_base; | 827 | int offset = data->hwirq; |
824 | int regoffset = offset / 8; | 828 | int regoffset = offset / 8; |
825 | int mask = 1 << (offset % 8); | 829 | int mask = 1 << (offset % 8); |
826 | 830 | ||
@@ -830,7 +834,7 @@ static void stmpe_irq_mask(struct irq_data *data) | |||
830 | static void stmpe_irq_unmask(struct irq_data *data) | 834 | static void stmpe_irq_unmask(struct irq_data *data) |
831 | { | 835 | { |
832 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); | 836 | struct stmpe *stmpe = irq_data_get_irq_chip_data(data); |
833 | int offset = data->irq - stmpe->irq_base; | 837 | int offset = data->hwirq; |
834 | int regoffset = offset / 8; | 838 | int regoffset = offset / 8; |
835 | int mask = 1 << (offset % 8); | 839 | int mask = 1 << (offset % 8); |
836 | 840 | ||
@@ -845,43 +849,62 @@ static struct irq_chip stmpe_irq_chip = { | |||
845 | .irq_unmask = stmpe_irq_unmask, | 849 | .irq_unmask = stmpe_irq_unmask, |
846 | }; | 850 | }; |
847 | 851 | ||
848 | static int __devinit stmpe_irq_init(struct stmpe *stmpe) | 852 | static int stmpe_irq_map(struct irq_domain *d, unsigned int virq, |
853 | irq_hw_number_t hwirq) | ||
849 | { | 854 | { |
855 | struct stmpe *stmpe = d->host_data; | ||
850 | struct irq_chip *chip = NULL; | 856 | struct irq_chip *chip = NULL; |
851 | int num_irqs = stmpe->variant->num_irqs; | ||
852 | int base = stmpe->irq_base; | ||
853 | int irq; | ||
854 | 857 | ||
855 | if (stmpe->variant->id_val != STMPE801_ID) | 858 | if (stmpe->variant->id_val != STMPE801_ID) |
856 | chip = &stmpe_irq_chip; | 859 | chip = &stmpe_irq_chip; |
857 | 860 | ||
858 | for (irq = base; irq < base + num_irqs; irq++) { | 861 | irq_set_chip_data(virq, stmpe); |
859 | irq_set_chip_data(irq, stmpe); | 862 | irq_set_chip_and_handler(virq, chip, handle_edge_irq); |
860 | irq_set_chip_and_handler(irq, chip, handle_edge_irq); | 863 | irq_set_nested_thread(virq, 1); |
861 | irq_set_nested_thread(irq, 1); | ||
862 | #ifdef CONFIG_ARM | 864 | #ifdef CONFIG_ARM |
863 | set_irq_flags(irq, IRQF_VALID); | 865 | set_irq_flags(virq, IRQF_VALID); |
864 | #else | 866 | #else |
865 | irq_set_noprobe(irq); | 867 | irq_set_noprobe(virq); |
866 | #endif | 868 | #endif |
867 | } | ||
868 | 869 | ||
869 | return 0; | 870 | return 0; |
870 | } | 871 | } |
871 | 872 | ||
872 | static void stmpe_irq_remove(struct stmpe *stmpe) | 873 | static void stmpe_irq_unmap(struct irq_domain *d, unsigned int virq) |
873 | { | 874 | { |
874 | int num_irqs = stmpe->variant->num_irqs; | ||
875 | int base = stmpe->irq_base; | ||
876 | int irq; | ||
877 | |||
878 | for (irq = base; irq < base + num_irqs; irq++) { | ||
879 | #ifdef CONFIG_ARM | 875 | #ifdef CONFIG_ARM |
880 | set_irq_flags(irq, 0); | 876 | set_irq_flags(virq, 0); |
881 | #endif | 877 | #endif |
882 | irq_set_chip_and_handler(irq, NULL, NULL); | 878 | irq_set_chip_and_handler(virq, NULL, NULL); |
883 | irq_set_chip_data(irq, NULL); | 879 | irq_set_chip_data(virq, NULL); |
880 | } | ||
881 | |||
882 | static struct irq_domain_ops stmpe_irq_ops = { | ||
883 | .map = stmpe_irq_map, | ||
884 | .unmap = stmpe_irq_unmap, | ||
885 | .xlate = irq_domain_xlate_twocell, | ||
886 | }; | ||
887 | |||
888 | static int __devinit stmpe_irq_init(struct stmpe *stmpe) | ||
889 | { | ||
890 | int base = stmpe->irq_base; | ||
891 | int num_irqs = stmpe->variant->num_irqs; | ||
892 | |||
893 | if (base) { | ||
894 | stmpe->domain = irq_domain_add_legacy( | ||
895 | NULL, num_irqs, base, 0, &stmpe_irq_ops, stmpe); | ||
896 | } | ||
897 | else { | ||
898 | stmpe->domain = irq_domain_add_linear( | ||
899 | NULL, num_irqs, &stmpe_irq_ops, stmpe); | ||
900 | } | ||
901 | |||
902 | if (!stmpe->domain) { | ||
903 | dev_err(stmpe->dev, "Failed to create irqdomain\n"); | ||
904 | return -ENOSYS; | ||
884 | } | 905 | } |
906 | |||
907 | return 0; | ||
885 | } | 908 | } |
886 | 909 | ||
887 | static int __devinit stmpe_chip_init(struct stmpe *stmpe) | 910 | static int __devinit stmpe_chip_init(struct stmpe *stmpe) |
@@ -954,7 +977,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe, | |||
954 | struct mfd_cell *cell) | 977 | struct mfd_cell *cell) |
955 | { | 978 | { |
956 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, | 979 | return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, |
957 | NULL, stmpe->irq_base, NULL); | 980 | NULL, stmpe->irq_base, stmpe->domain); |
958 | } | 981 | } |
959 | 982 | ||
960 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) | 983 | static int __devinit stmpe_devices_init(struct stmpe *stmpe) |
@@ -1067,7 +1090,7 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) | |||
1067 | if (ret) { | 1090 | if (ret) { |
1068 | dev_err(stmpe->dev, "failed to request IRQ: %d\n", | 1091 | dev_err(stmpe->dev, "failed to request IRQ: %d\n", |
1069 | ret); | 1092 | ret); |
1070 | goto out_removeirq; | 1093 | goto free_gpio; |
1071 | } | 1094 | } |
1072 | } | 1095 | } |
1073 | 1096 | ||
@@ -1083,9 +1106,6 @@ out_removedevs: | |||
1083 | mfd_remove_devices(stmpe->dev); | 1106 | mfd_remove_devices(stmpe->dev); |
1084 | if (stmpe->irq >= 0) | 1107 | if (stmpe->irq >= 0) |
1085 | free_irq(stmpe->irq, stmpe); | 1108 | free_irq(stmpe->irq, stmpe); |
1086 | out_removeirq: | ||
1087 | if (stmpe->irq >= 0) | ||
1088 | stmpe_irq_remove(stmpe); | ||
1089 | free_gpio: | 1109 | free_gpio: |
1090 | if (pdata->irq_over_gpio) | 1110 | if (pdata->irq_over_gpio) |
1091 | gpio_free(pdata->irq_gpio); | 1111 | gpio_free(pdata->irq_gpio); |
@@ -1098,10 +1118,8 @@ int stmpe_remove(struct stmpe *stmpe) | |||
1098 | { | 1118 | { |
1099 | mfd_remove_devices(stmpe->dev); | 1119 | mfd_remove_devices(stmpe->dev); |
1100 | 1120 | ||
1101 | if (stmpe->irq >= 0) { | 1121 | if (stmpe->irq >= 0) |
1102 | free_irq(stmpe->irq, stmpe); | 1122 | free_irq(stmpe->irq, stmpe); |
1103 | stmpe_irq_remove(stmpe); | ||
1104 | } | ||
1105 | 1123 | ||
1106 | if (stmpe->pdata->irq_over_gpio) | 1124 | if (stmpe->pdata->irq_over_gpio) |
1107 | gpio_free(stmpe->pdata->irq_gpio); | 1125 | gpio_free(stmpe->pdata->irq_gpio); |
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index f8d5b4d5843f..15dac790365f 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h | |||
@@ -62,6 +62,7 @@ struct stmpe_client_info; | |||
62 | * @lock: lock protecting I/O operations | 62 | * @lock: lock protecting I/O operations |
63 | * @irq_lock: IRQ bus lock | 63 | * @irq_lock: IRQ bus lock |
64 | * @dev: device, mostly for dev_dbg() | 64 | * @dev: device, mostly for dev_dbg() |
65 | * @irq_domain: IRQ domain | ||
65 | * @client: client - i2c or spi | 66 | * @client: client - i2c or spi |
66 | * @ci: client specific information | 67 | * @ci: client specific information |
67 | * @partnum: part number | 68 | * @partnum: part number |
@@ -79,6 +80,7 @@ struct stmpe { | |||
79 | struct mutex lock; | 80 | struct mutex lock; |
80 | struct mutex irq_lock; | 81 | struct mutex irq_lock; |
81 | struct device *dev; | 82 | struct device *dev; |
83 | struct irq_domain *domain; | ||
82 | void *client; | 84 | void *client; |
83 | struct stmpe_client_info *ci; | 85 | struct stmpe_client_info *ci; |
84 | enum stmpe_partnum partnum; | 86 | enum stmpe_partnum partnum; |