diff options
-rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-tc3589x.c | 114 |
2 files changed, 24 insertions, 91 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a86c49a605c6..5ad9e927baba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -579,6 +579,7 @@ config GPIO_STP_XWAY | |||
579 | config GPIO_TC3589X | 579 | config GPIO_TC3589X |
580 | bool "TC3589X GPIOs" | 580 | bool "TC3589X GPIOs" |
581 | depends on MFD_TC3589X | 581 | depends on MFD_TC3589X |
582 | select GPIOLIB_IRQCHIP | ||
582 | help | 583 | help |
583 | This enables support for the GPIOs found on the TC3589X | 584 | This enables support for the GPIOs found on the TC3589X |
584 | I/O Expander. | 585 | I/O Expander. |
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 4b0d8ccbe561..51f7cbd9ff71 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c | |||
@@ -12,8 +12,6 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/irq.h> | ||
16 | #include <linux/irqdomain.h> | ||
17 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
18 | #include <linux/mfd/tc3589x.h> | 16 | #include <linux/mfd/tc3589x.h> |
19 | 17 | ||
@@ -31,7 +29,6 @@ struct tc3589x_gpio { | |||
31 | struct tc3589x *tc3589x; | 29 | struct tc3589x *tc3589x; |
32 | struct device *dev; | 30 | struct device *dev; |
33 | struct mutex irq_lock; | 31 | struct mutex irq_lock; |
34 | struct irq_domain *domain; | ||
35 | /* Caches of interrupt control registers for bus_lock */ | 32 | /* Caches of interrupt control registers for bus_lock */ |
36 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; | 33 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; |
37 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; | 34 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; |
@@ -92,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, | |||
92 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); | 89 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); |
93 | } | 90 | } |
94 | 91 | ||
95 | /** | ||
96 | * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ | ||
97 | * | ||
98 | * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. | ||
99 | * @irq: index of the hardware interrupt requested in the chip IRQs | ||
100 | * | ||
101 | * Useful for drivers to request their own IRQs. | ||
102 | */ | ||
103 | static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, | ||
104 | int hwirq) | ||
105 | { | ||
106 | if (!tc3589x_gpio) | ||
107 | return -EINVAL; | ||
108 | |||
109 | return irq_create_mapping(tc3589x_gpio->domain, hwirq); | ||
110 | } | ||
111 | |||
112 | static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
113 | { | ||
114 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
115 | |||
116 | return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); | ||
117 | } | ||
118 | |||
119 | static struct gpio_chip template_chip = { | 92 | static struct gpio_chip template_chip = { |
120 | .label = "tc3589x", | 93 | .label = "tc3589x", |
121 | .owner = THIS_MODULE, | 94 | .owner = THIS_MODULE, |
@@ -123,13 +96,13 @@ static struct gpio_chip template_chip = { | |||
123 | .get = tc3589x_gpio_get, | 96 | .get = tc3589x_gpio_get, |
124 | .direction_output = tc3589x_gpio_direction_output, | 97 | .direction_output = tc3589x_gpio_direction_output, |
125 | .set = tc3589x_gpio_set, | 98 | .set = tc3589x_gpio_set, |
126 | .to_irq = tc3589x_gpio_to_irq, | ||
127 | .can_sleep = true, | 99 | .can_sleep = true, |
128 | }; | 100 | }; |
129 | 101 | ||
130 | static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) | 102 | static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) |
131 | { | 103 | { |
132 | struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); | 104 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
105 | struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); | ||
133 | int offset = d->hwirq; | 106 | int offset = d->hwirq; |
134 | int regoffset = offset / 8; | 107 | int regoffset = offset / 8; |
135 | int mask = 1 << (offset % 8); | 108 | int mask = 1 << (offset % 8); |
@@ -156,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) | |||
156 | 129 | ||
157 | static void tc3589x_gpio_irq_lock(struct irq_data *d) | 130 | static void tc3589x_gpio_irq_lock(struct irq_data *d) |
158 | { | 131 | { |
159 | struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); | 132 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
133 | struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); | ||
160 | 134 | ||
161 | mutex_lock(&tc3589x_gpio->irq_lock); | 135 | mutex_lock(&tc3589x_gpio->irq_lock); |
162 | } | 136 | } |
163 | 137 | ||
164 | static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) | 138 | static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) |
165 | { | 139 | { |
166 | struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); | 140 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
141 | struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); | ||
167 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | 142 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; |
168 | static const u8 regmap[] = { | 143 | static const u8 regmap[] = { |
169 | [REG_IBE] = TC3589x_GPIOIBE0, | 144 | [REG_IBE] = TC3589x_GPIOIBE0, |
@@ -191,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) | |||
191 | 166 | ||
192 | static void tc3589x_gpio_irq_mask(struct irq_data *d) | 167 | static void tc3589x_gpio_irq_mask(struct irq_data *d) |
193 | { | 168 | { |
194 | struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); | 169 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
170 | struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); | ||
195 | int offset = d->hwirq; | 171 | int offset = d->hwirq; |
196 | int regoffset = offset / 8; | 172 | int regoffset = offset / 8; |
197 | int mask = 1 << (offset % 8); | 173 | int mask = 1 << (offset % 8); |
@@ -201,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) | |||
201 | 177 | ||
202 | static void tc3589x_gpio_irq_unmask(struct irq_data *d) | 178 | static void tc3589x_gpio_irq_unmask(struct irq_data *d) |
203 | { | 179 | { |
204 | struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); | 180 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
181 | struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); | ||
205 | int offset = d->hwirq; | 182 | int offset = d->hwirq; |
206 | int regoffset = offset / 8; | 183 | int regoffset = offset / 8; |
207 | int mask = 1 << (offset % 8); | 184 | int mask = 1 << (offset % 8); |
@@ -239,7 +216,8 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) | |||
239 | while (stat) { | 216 | while (stat) { |
240 | int bit = __ffs(stat); | 217 | int bit = __ffs(stat); |
241 | int line = i * 8 + bit; | 218 | int line = i * 8 + bit; |
242 | int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); | 219 | int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain, |
220 | line); | ||
243 | 221 | ||
244 | handle_nested_irq(irq); | 222 | handle_nested_irq(irq); |
245 | stat &= ~(1 << bit); | 223 | stat &= ~(1 << bit); |
@@ -251,59 +229,6 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) | |||
251 | return IRQ_HANDLED; | 229 | return IRQ_HANDLED; |
252 | } | 230 | } |
253 | 231 | ||
254 | static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, | ||
255 | irq_hw_number_t hwirq) | ||
256 | { | ||
257 | struct tc3589x *tc3589x_gpio = d->host_data; | ||
258 | |||
259 | irq_set_chip_data(irq, tc3589x_gpio); | ||
260 | irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, | ||
261 | handle_simple_irq); | ||
262 | irq_set_nested_thread(irq, 1); | ||
263 | #ifdef CONFIG_ARM | ||
264 | set_irq_flags(irq, IRQF_VALID); | ||
265 | #else | ||
266 | irq_set_noprobe(irq); | ||
267 | #endif | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) | ||
273 | { | ||
274 | #ifdef CONFIG_ARM | ||
275 | set_irq_flags(irq, 0); | ||
276 | #endif | ||
277 | irq_set_chip_and_handler(irq, NULL, NULL); | ||
278 | irq_set_chip_data(irq, NULL); | ||
279 | } | ||
280 | |||
281 | static struct irq_domain_ops tc3589x_irq_ops = { | ||
282 | .map = tc3589x_gpio_irq_map, | ||
283 | .unmap = tc3589x_gpio_irq_unmap, | ||
284 | .xlate = irq_domain_xlate_twocell, | ||
285 | }; | ||
286 | |||
287 | static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, | ||
288 | struct device_node *np) | ||
289 | { | ||
290 | /* | ||
291 | * If this results in a linear domain, irq_create_mapping() will | ||
292 | * take care of allocating IRQ descriptors at runtime. When a base | ||
293 | * is provided, the IRQ descriptors will be allocated when the | ||
294 | * domain is instantiated. | ||
295 | */ | ||
296 | tc3589x_gpio->domain = irq_domain_add_simple(np, | ||
297 | tc3589x_gpio->chip.ngpio, 0, &tc3589x_irq_ops, | ||
298 | tc3589x_gpio); | ||
299 | if (!tc3589x_gpio->domain) { | ||
300 | dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); | ||
301 | return -ENOSYS; | ||
302 | } | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int tc3589x_gpio_probe(struct platform_device *pdev) | 232 | static int tc3589x_gpio_probe(struct platform_device *pdev) |
308 | { | 233 | { |
309 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | 234 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); |
@@ -349,10 +274,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) | |||
349 | if (ret < 0) | 274 | if (ret < 0) |
350 | return ret; | 275 | return ret; |
351 | 276 | ||
352 | ret = tc3589x_gpio_irq_init(tc3589x_gpio, np); | ||
353 | if (ret) | ||
354 | return ret; | ||
355 | |||
356 | ret = devm_request_threaded_irq(&pdev->dev, | 277 | ret = devm_request_threaded_irq(&pdev->dev, |
357 | irq, NULL, tc3589x_gpio_irq, | 278 | irq, NULL, tc3589x_gpio_irq, |
358 | IRQF_ONESHOT, "tc3589x-gpio", | 279 | IRQF_ONESHOT, "tc3589x-gpio", |
@@ -368,6 +289,17 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) | |||
368 | return ret; | 289 | return ret; |
369 | } | 290 | } |
370 | 291 | ||
292 | ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, | ||
293 | &tc3589x_gpio_irq_chip, | ||
294 | 0, | ||
295 | handle_simple_irq, | ||
296 | IRQ_TYPE_NONE); | ||
297 | if (ret) { | ||
298 | dev_err(&pdev->dev, | ||
299 | "could not connect irqchip to gpiochip\n"); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
371 | if (pdata && pdata->setup) | 303 | if (pdata && pdata->setup) |
372 | pdata->setup(tc3589x, tc3589x_gpio->chip.base); | 304 | pdata->setup(tc3589x, tc3589x_gpio->chip.base); |
373 | 305 | ||