Skip to content

Commit 2b72526

Browse files
Asmaa Mnebhibrgl
authored andcommitted
gpio: mlxbf2: Introduce IRQ support
Introduce standard IRQ handling in the gpio-mlxbf2.c driver. Signed-off-by: Asmaa Mnebhi <[email protected]> Acked-by: David S. Miller <[email protected]> Signed-off-by: Bartosz Golaszewski <[email protected]>
1 parent f4a20df commit 2b72526

File tree

1 file changed

+140
-2
lines changed

1 file changed

+140
-2
lines changed

drivers/gpio/gpio-mlxbf2.c

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
/*
4+
* Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
5+
*/
6+
37
#include <linux/bitfield.h>
48
#include <linux/bitops.h>
59
#include <linux/device.h>
610
#include <linux/gpio/driver.h>
11+
#include <linux/interrupt.h>
712
#include <linux/io.h>
813
#include <linux/ioport.h>
914
#include <linux/kernel.h>
@@ -43,9 +48,14 @@
4348
#define YU_GPIO_MODE0 0x0c
4449
#define YU_GPIO_DATASET 0x14
4550
#define YU_GPIO_DATACLEAR 0x18
51+
#define YU_GPIO_CAUSE_RISE_EN 0x44
52+
#define YU_GPIO_CAUSE_FALL_EN 0x48
4653
#define YU_GPIO_MODE1_CLEAR 0x50
4754
#define YU_GPIO_MODE0_SET 0x54
4855
#define YU_GPIO_MODE0_CLEAR 0x58
56+
#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80
57+
#define YU_GPIO_CAUSE_OR_EVTEN0 0x94
58+
#define YU_GPIO_CAUSE_OR_CLRCAUSE 0x98
4959

5060
struct mlxbf2_gpio_context_save_regs {
5161
u32 gpio_mode0;
@@ -55,6 +65,7 @@ struct mlxbf2_gpio_context_save_regs {
5565
/* BlueField-2 gpio block context structure. */
5666
struct mlxbf2_gpio_context {
5767
struct gpio_chip gc;
68+
struct irq_chip irq_chip;
5869

5970
/* YU GPIO blocks address */
6071
void __iomem *gpio_io;
@@ -218,15 +229,114 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip,
218229
return ret;
219230
}
220231

232+
static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
233+
{
234+
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
235+
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
236+
int offset = irqd_to_hwirq(irqd);
237+
unsigned long flags;
238+
u32 val;
239+
240+
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
241+
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
242+
val |= BIT(offset);
243+
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
244+
245+
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
246+
val |= BIT(offset);
247+
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
248+
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
249+
}
250+
251+
static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
252+
{
253+
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
254+
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
255+
int offset = irqd_to_hwirq(irqd);
256+
unsigned long flags;
257+
u32 val;
258+
259+
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
260+
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
261+
val &= ~BIT(offset);
262+
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
263+
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
264+
}
265+
266+
static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr)
267+
{
268+
struct mlxbf2_gpio_context *gs = ptr;
269+
struct gpio_chip *gc = &gs->gc;
270+
unsigned long pending;
271+
u32 level;
272+
273+
pending = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0);
274+
writel(pending, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
275+
276+
for_each_set_bit(level, &pending, gc->ngpio) {
277+
int gpio_irq = irq_find_mapping(gc->irq.domain, level);
278+
generic_handle_irq(gpio_irq);
279+
}
280+
281+
return IRQ_RETVAL(pending);
282+
}
283+
284+
static int
285+
mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
286+
{
287+
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
288+
struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
289+
int offset = irqd_to_hwirq(irqd);
290+
unsigned long flags;
291+
bool fall = false;
292+
bool rise = false;
293+
u32 val;
294+
295+
switch (type & IRQ_TYPE_SENSE_MASK) {
296+
case IRQ_TYPE_EDGE_BOTH:
297+
fall = true;
298+
rise = true;
299+
break;
300+
case IRQ_TYPE_EDGE_RISING:
301+
rise = true;
302+
break;
303+
case IRQ_TYPE_EDGE_FALLING:
304+
fall = true;
305+
break;
306+
default:
307+
return -EINVAL;
308+
}
309+
310+
spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
311+
if (fall) {
312+
val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN);
313+
val |= BIT(offset);
314+
writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN);
315+
}
316+
317+
if (rise) {
318+
val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN);
319+
val |= BIT(offset);
320+
writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN);
321+
}
322+
spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
323+
324+
return 0;
325+
}
326+
221327
/* BlueField-2 GPIO driver initialization routine. */
222328
static int
223329
mlxbf2_gpio_probe(struct platform_device *pdev)
224330
{
225331
struct mlxbf2_gpio_context *gs;
226332
struct device *dev = &pdev->dev;
333+
struct gpio_irq_chip *girq;
227334
struct gpio_chip *gc;
228335
unsigned int npins;
229-
int ret;
336+
const char *name;
337+
int ret, irq;
338+
339+
name = dev_name(dev);
230340

231341
gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
232342
if (!gs)
@@ -261,6 +371,34 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
261371
gc->ngpio = npins;
262372
gc->owner = THIS_MODULE;
263373

374+
irq = platform_get_irq(pdev, 0);
375+
if (irq >= 0) {
376+
gs->irq_chip.name = name;
377+
gs->irq_chip.irq_set_type = mlxbf2_gpio_irq_set_type;
378+
gs->irq_chip.irq_enable = mlxbf2_gpio_irq_enable;
379+
gs->irq_chip.irq_disable = mlxbf2_gpio_irq_disable;
380+
381+
girq = &gs->gc.irq;
382+
girq->chip = &gs->irq_chip;
383+
girq->handler = handle_simple_irq;
384+
girq->default_type = IRQ_TYPE_NONE;
385+
/* This will let us handle the parent IRQ in the driver */
386+
girq->num_parents = 0;
387+
girq->parents = NULL;
388+
girq->parent_handler = NULL;
389+
390+
/*
391+
* Directly request the irq here instead of passing
392+
* a flow-handler because the irq is shared.
393+
*/
394+
ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler,
395+
IRQF_SHARED, name, gs);
396+
if (ret) {
397+
dev_err(dev, "failed to request IRQ");
398+
return ret;
399+
}
400+
}
401+
264402
platform_set_drvdata(pdev, gs);
265403

266404
ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
@@ -315,5 +453,5 @@ static struct platform_driver mlxbf2_gpio_driver = {
315453
module_platform_driver(mlxbf2_gpio_driver);
316454

317455
MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver");
318-
MODULE_AUTHOR("Mellanox Technologies");
456+
MODULE_AUTHOR("Asmaa Mnebhi <[email protected]>");
319457
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)