Skip to content

Commit 0ea6839

Browse files
fancerLinus Walleij
authored andcommitted
gpio: dwapb: Convert driver to using the GPIO-lib-based IRQ-chip
GPIO-lib provides a ready-to-use interface to initialize an IRQ-chip on top of a GPIO chip. It's better from maintainability and readability point of view to use one instead of supporting a hand-written Generic IRQ-chip-based implementation. Moreover the new implementation won't cause much functional overhead but will provide a cleaner driver code. All of that makes the DW APB GPIO driver conversion pretty much justified especially seeing a tendency of the other GPIO drivers getting converted too. Here is what we do in the framework of this commit to convert the driver to using the GPIO-lib-based IRQ-chip interface: 1) IRQ ack, mask and unmask callbacks are locally defined instead of using the Generic IRQ-chip ones. 2) An irq_chip structure instance is embedded into the dwapb_gpio private data. Note we can't have a static instance of that structure since GPIO-lib will add some hooks into it by calling gpiochip_set_irq_hooks(). A warning about that would have been printed by the GPIO-lib code if we used a single irq_chip structure instance for multiple DW APB GPIO controllers. 3) Initialize the gpio_irq_chip structure embedded into the gpio_chip descriptor. By default there is no IRQ enabled so any event raised will be handled by the handle_bad_irq() IRQ flow handler. If DW APB GPIO IP-core is synthesized to have non-shared reference IRQ-lines, then as before the hierarchical and cascaded cases are distinguished by checking how many parental IRQs are defined. (Note irq_set_chained_handler_and_data() won't initialize IRQs, which descriptors couldn't be found.) If DW APB GPIO IP is used on a platform with shared IRQ line, then we simply won't let the GPIO-lib to initialize the parental IRQs, but will handle them locally in the driver. 4) Discard linear IRQ-domain and Generic IRQ-chip initialization, since GPIO-lib IRQ-chip interface will create a new domain and accept a standard IRQ-chip structure pointer based on the setting we provided in the gpio_irq_chip structure. 5) Manually select a proper IRQ flow handler directly in the irq_set_type() callback by calling irq_set_handler_locked() method, since an ordinary (not Generic) irq_chip descriptor is now utilized. Note this shalln't give any regression 6) Alter CONFIG_GPIO_DWAPB kernel config to select CONFIG_GPIOLIB_IRQCHIP instead of CONFIG_GENERIC_IRQ_CHIP. Note neither 4) nor 5) shall cause a regression of commit 6a2f4b7 ("gpio: dwapb: use a second irq chip"), since the later isn't properly used here anyway. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Link: https://lore.kernel.org/r/20200730152808.2955-6-Sergey.Semin@baikalelectronics.ru Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent f9f890b commit 0ea6839

File tree

2 files changed

+111
-94
lines changed

2 files changed

+111
-94
lines changed

drivers/gpio/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ config GPIO_DAVINCI
202202
config GPIO_DWAPB
203203
tristate "Synopsys DesignWare APB GPIO driver"
204204
select GPIO_GENERIC
205-
select GENERIC_IRQ_CHIP
205+
select GPIOLIB_IRQCHIP
206206
help
207207
Say Y or M here to build support for the Synopsys DesignWare APB
208208
GPIO block.

drivers/gpio/gpio-dwapb.c

Lines changed: 110 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <linux/io.h>
1414
#include <linux/ioport.h>
1515
#include <linux/irq.h>
16-
#include <linux/irqdomain.h>
1716
#include <linux/module.h>
1817
#include <linux/of.h>
1918
#include <linux/of_address.h>
@@ -83,22 +82,30 @@ struct dwapb_context {
8382
};
8483
#endif
8584

85+
struct dwapb_gpio_port_irqchip {
86+
struct irq_chip irqchip;
87+
unsigned int nr_irqs;
88+
unsigned int irq[DWAPB_MAX_GPIOS];
89+
};
90+
8691
struct dwapb_gpio_port {
8792
struct gpio_chip gc;
93+
struct dwapb_gpio_port_irqchip *pirq;
8894
bool is_registered;
8995
struct dwapb_gpio *gpio;
9096
#ifdef CONFIG_PM_SLEEP
9197
struct dwapb_context *ctx;
9298
#endif
9399
unsigned int idx;
94100
};
101+
#define to_dwapb_gpio(_gc) \
102+
(container_of(_gc, struct dwapb_gpio_port, gc)->gpio)
95103

96104
struct dwapb_gpio {
97105
struct device *dev;
98106
void __iomem *regs;
99107
struct dwapb_gpio_port *ports;
100108
unsigned int nr_ports;
101-
struct irq_domain *domain;
102109
unsigned int flags;
103110
struct reset_control *rst;
104111
struct clk_bulk_data clks[DWAPB_NR_CLOCKS];
@@ -193,12 +200,13 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
193200

194201
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
195202
{
203+
struct gpio_chip *gc = &gpio->ports[0].gc;
196204
unsigned long irq_status;
197205
irq_hw_number_t hwirq;
198206

199207
irq_status = dwapb_read(gpio, GPIO_INTSTATUS);
200208
for_each_set_bit(hwirq, &irq_status, DWAPB_MAX_GPIOS) {
201-
int gpio_irq = irq_find_mapping(gpio->domain, hwirq);
209+
int gpio_irq = irq_find_mapping(gc->irq.domain, hwirq);
202210
u32 irq_type = irq_get_trigger_type(gpio_irq);
203211

204212
generic_handle_irq(gpio_irq);
@@ -225,11 +233,48 @@ static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
225233
return IRQ_RETVAL(dwapb_do_irq(dev_id));
226234
}
227235

236+
static void dwapb_irq_ack(struct irq_data *d)
237+
{
238+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
239+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
240+
u32 val = BIT(irqd_to_hwirq(d));
241+
unsigned long flags;
242+
243+
spin_lock_irqsave(&gc->bgpio_lock, flags);
244+
dwapb_write(gpio, GPIO_PORTA_EOI, val);
245+
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
246+
}
247+
248+
static void dwapb_irq_mask(struct irq_data *d)
249+
{
250+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
251+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
252+
unsigned long flags;
253+
u32 val;
254+
255+
spin_lock_irqsave(&gc->bgpio_lock, flags);
256+
val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d));
257+
dwapb_write(gpio, GPIO_INTMASK, val);
258+
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
259+
}
260+
261+
static void dwapb_irq_unmask(struct irq_data *d)
262+
{
263+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
264+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
265+
unsigned long flags;
266+
u32 val;
267+
268+
spin_lock_irqsave(&gc->bgpio_lock, flags);
269+
val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d));
270+
dwapb_write(gpio, GPIO_INTMASK, val);
271+
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
272+
}
273+
228274
static void dwapb_irq_enable(struct irq_data *d)
229275
{
230-
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
231-
struct dwapb_gpio *gpio = igc->private;
232-
struct gpio_chip *gc = &gpio->ports[0].gc;
276+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
277+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
233278
unsigned long flags;
234279
u32 val;
235280

@@ -242,9 +287,8 @@ static void dwapb_irq_enable(struct irq_data *d)
242287

243288
static void dwapb_irq_disable(struct irq_data *d)
244289
{
245-
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
246-
struct dwapb_gpio *gpio = igc->private;
247-
struct gpio_chip *gc = &gpio->ports[0].gc;
290+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
291+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
248292
unsigned long flags;
249293
u32 val;
250294

@@ -257,9 +301,8 @@ static void dwapb_irq_disable(struct irq_data *d)
257301

258302
static int dwapb_irq_set_type(struct irq_data *d, u32 type)
259303
{
260-
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
261-
struct dwapb_gpio *gpio = igc->private;
262-
struct gpio_chip *gc = &gpio->ports[0].gc;
304+
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
305+
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
263306
irq_hw_number_t bit = irqd_to_hwirq(d);
264307
unsigned long level, polarity, flags;
265308

@@ -293,7 +336,10 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
293336
break;
294337
}
295338

296-
irq_setup_alt_chip(d, type);
339+
if (type & IRQ_TYPE_LEVEL_MASK)
340+
irq_set_handler_locked(d, handle_level_irq);
341+
else if (type & IRQ_TYPE_EDGE_BOTH)
342+
irq_set_handler_locked(d, handle_edge_irq);
297343

298344
dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
299345
if (type != IRQ_TYPE_EDGE_BOTH)
@@ -354,79 +400,67 @@ static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset,
354400
return dwapb_gpio_set_debounce(gc, offset, debounce);
355401
}
356402

403+
static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq,
404+
struct dwapb_port_property *pp)
405+
{
406+
int i;
407+
408+
/* Group all available IRQs into an array of parental IRQs. */
409+
for (i = 0; i < pp->ngpio; ++i) {
410+
if (!pp->irq[i])
411+
continue;
412+
413+
pirq->irq[pirq->nr_irqs++] = pp->irq[i];
414+
}
415+
416+
return pirq->nr_irqs ? 0 : -ENOENT;
417+
}
418+
357419
static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
358420
struct dwapb_gpio_port *port,
359421
struct dwapb_port_property *pp)
360422
{
423+
struct dwapb_gpio_port_irqchip *pirq;
361424
struct gpio_chip *gc = &port->gc;
362-
struct fwnode_handle *fwnode = pp->fwnode;
363-
struct irq_chip_generic *irq_gc = NULL;
364-
unsigned int ngpio = gc->ngpio;
365-
struct irq_chip_type *ct;
366-
irq_hw_number_t hwirq;
367-
int err, i;
368-
369-
if (memchr_inv(pp->irq, 0, sizeof(pp->irq)) == NULL) {
370-
dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx);
371-
return;
372-
}
373-
374-
gpio->domain = irq_domain_create_linear(fwnode, ngpio,
375-
&irq_generic_chip_ops, gpio);
376-
if (!gpio->domain)
377-
return;
425+
struct gpio_irq_chip *girq;
426+
int err;
378427

379-
err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
380-
DWAPB_DRIVER_NAME, handle_bad_irq,
381-
IRQ_NOREQUEST, 0,
382-
IRQ_GC_INIT_NESTED_LOCK);
383-
if (err) {
384-
dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n");
385-
irq_domain_remove(gpio->domain);
386-
gpio->domain = NULL;
428+
pirq = devm_kzalloc(gpio->dev, sizeof(*pirq), GFP_KERNEL);
429+
if (!pirq)
387430
return;
388-
}
389431

390-
irq_gc = irq_get_domain_generic_chip(gpio->domain, 0);
391-
if (!irq_gc) {
392-
irq_domain_remove(gpio->domain);
393-
gpio->domain = NULL;
394-
return;
432+
if (dwapb_convert_irqs(pirq, pp)) {
433+
dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx);
434+
goto err_kfree_pirq;
395435
}
396436

397-
irq_gc->reg_base = gpio->regs;
398-
irq_gc->private = gpio;
399-
400-
for (i = 0; i < 2; i++) {
401-
ct = &irq_gc->chip_types[i];
402-
ct->chip.irq_ack = irq_gc_ack_set_bit;
403-
ct->chip.irq_mask = irq_gc_mask_set_bit;
404-
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
405-
ct->chip.irq_set_type = dwapb_irq_set_type;
406-
ct->chip.irq_enable = dwapb_irq_enable;
407-
ct->chip.irq_disable = dwapb_irq_disable;
437+
girq = &gc->irq;
438+
girq->handler = handle_bad_irq;
439+
girq->default_type = IRQ_TYPE_NONE;
440+
441+
port->pirq = pirq;
442+
pirq->irqchip.name = DWAPB_DRIVER_NAME;
443+
pirq->irqchip.irq_ack = dwapb_irq_ack;
444+
pirq->irqchip.irq_mask = dwapb_irq_mask;
445+
pirq->irqchip.irq_unmask = dwapb_irq_unmask;
446+
pirq->irqchip.irq_set_type = dwapb_irq_set_type;
447+
pirq->irqchip.irq_enable = dwapb_irq_enable;
448+
pirq->irqchip.irq_disable = dwapb_irq_disable;
408449
#ifdef CONFIG_PM_SLEEP
409-
ct->chip.irq_set_wake = dwapb_irq_set_wake;
450+
pirq->irqchip.irq_set_wake = dwapb_irq_set_wake;
410451
#endif
411-
ct->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI);
412-
ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK);
413-
ct->type = IRQ_TYPE_LEVEL_MASK;
414-
}
415-
416-
irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
417-
irq_gc->chip_types[0].handler = handle_level_irq;
418-
irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
419-
irq_gc->chip_types[1].handler = handle_edge_irq;
420452

421453
if (!pp->irq_shared) {
422-
int i;
423-
424-
for (i = 0; i < pp->ngpio; i++) {
425-
if (pp->irq[i])
426-
irq_set_chained_handler_and_data(pp->irq[i],
427-
dwapb_irq_handler, gpio);
428-
}
454+
girq->num_parents = pirq->nr_irqs;
455+
girq->parents = pirq->irq;
456+
girq->parent_handler_data = gpio;
457+
girq->parent_handler = dwapb_irq_handler;
429458
} else {
459+
/* This will let us handle the parent IRQ in the driver */
460+
girq->num_parents = 0;
461+
girq->parents = NULL;
462+
girq->parent_handler = NULL;
463+
430464
/*
431465
* Request a shared IRQ since where MFD would have devices
432466
* using the same irq pin
@@ -436,33 +470,18 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
436470
IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
437471
if (err) {
438472
dev_err(gpio->dev, "error requesting IRQ\n");
439-
irq_domain_remove(gpio->domain);
440-
gpio->domain = NULL;
441-
return;
473+
goto err_kfree_pirq;
442474
}
443475
}
444476

445-
for (hwirq = 0; hwirq < ngpio; hwirq++)
446-
irq_create_mapping(gpio->domain, hwirq);
477+
girq->chip = &pirq->irqchip;
447478

448479
port->gc.to_irq = dwapb_gpio_to_irq;
449-
}
450-
451-
static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
452-
{
453-
struct dwapb_gpio_port *port = &gpio->ports[0];
454-
struct gpio_chip *gc = &port->gc;
455-
unsigned int ngpio = gc->ngpio;
456-
irq_hw_number_t hwirq;
457-
458-
if (!gpio->domain)
459-
return;
460480

461-
for (hwirq = 0; hwirq < ngpio; hwirq++)
462-
irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq));
481+
return;
463482

464-
irq_domain_remove(gpio->domain);
465-
gpio->domain = NULL;
483+
err_kfree_pirq:
484+
devm_kfree(gpio->dev, pirq);
466485
}
467486

468487
static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
@@ -699,7 +718,6 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
699718

700719
out_unregister:
701720
dwapb_gpio_unregister(gpio);
702-
dwapb_irq_teardown(gpio);
703721
clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
704722

705723
return err;
@@ -710,7 +728,6 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
710728
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
711729

712730
dwapb_gpio_unregister(gpio);
713-
dwapb_irq_teardown(gpio);
714731
reset_control_assert(gpio->rst);
715732
clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
716733

0 commit comments

Comments
 (0)