irq linux,linux arm irq (3): gpio interrupt

linux arm irq (3)

3 gpio interrupt

Author: Yangkai Wang

wang_yangkai@163.com

Coding in 2021/05/16

转载请注明author,出处.

linux version 3.4.39

s5p6818 soc

Cortex-A53 Octa core CPU

Interrupt Controller,GIC400

GIC (Generic Interrupt Controllers), reference:Arm Generic Interrupt Controller Architecture version 2.0,Architecture Specification

GPIO controller,reference:S5P6818 Application Processor Datasheetgpio interrupt initasmlinkage void __init start_kernel(void)

|

init_IRQ();

|

machine_desc->init_irq(); /* call nxp_cpu_irq_init() *//* arch/arm/mach-s5p6818/irq.c */

/*----------------------------------------------------------------------------

*  cpu irq handler

*/

#define GIC_DIST_BASE(void __iomem *)(INTC_BASE + 0x00001000)// 0xC0009000

#define GIC_CPUI_BASE(void __iomem *)(INTC_BASE + 0x00002000)// 0xC000a000

#define GPIO_INT_BASE(void __iomem *)IO_ADDRESS(PHY_BASEADDR_GPIOA)

#define GPIO_BASE_OFFSET(0x1000)

#define GPIO_INT_MASK(0xFFFFFFFF)

#define ALIVE_INT_BASE(void __iomem *)IO_ADDRESS(PHY_BASEADDR_CLKPWR_MODULE + 0x800)

#define ALIVE_INT_MASK(0x000000FF)

/*

*  cpu irq handler

*/

void __init nxp_cpu_irq_init(void)

{

pr_debug("%s:%d\n", __func__, __LINE__);

printk("~~~ %s()\n", __func__);

__gic_init(GIC_DIST_BASE, (void __iomem *)GIC_CPUI_BASE);

gpio_init(GPIO_INT_BASE , IRQ_GPIO_START, GPIO_INT_MASK, 0);/* 64 ~ 223 (A,B,C,D,E) */

alive_init(ALIVE_INT_BASE, IRQ_ALIVE_START, ALIVE_INT_MASK, 0); /* 224 ~ 231 */

#ifdef CONFIG_FIQ

init_FIQ();

#endif

/* wake up source from idle */

irq_set_irq_wake(IRQ_PHY_CLKPWR_ALIVEIRQ + GIC_PHY_OFFSET, 1);

#if PM_RTC_WAKE

irq_set_irq_wake(IRQ_PHY_CLKPWR_RTCIRQ + GIC_PHY_OFFSET, 1);

#endif

}

nxp_cpu_irq_init(),中

gic 初始化:

__gic_init(GIC_DIST_BASE, (void __iomem *)GIC_CPUI_BASE);

gpio 中断相关初始化:

gpio_init(GPIO_INT_BASE , IRQ_GPIO_START, GPIO_INT_MASK, 0);C,D,E);

alive_init(ALIVE_INT_BASE, IRQ_ALIVE_START, ALIVE_INT_MASK, 0);gpio_interrupt_init(void __iomem *base, unsigned int irq_start,

u32 irq_sources, u32 resume_sources)/* arch/arm/mach-s5p6818/irq.c */

static void __init gpio_init(void __iomem *base, unsigned int irq_start,

u32 irq_sources, u32 resume_sources)

{

int irq_gpio = IRQ_PHY_GPIOA + GIC_PHY_OFFSET;

int num = 5;  /* A,B,C,D,E */

int ios = 32; /* GPIO 32 */

int n = 0,i = 0;

/* set gpio irq handler */

for (n = 0; num > n; n++) {

printk(KERN_INFO "GPIO  @%p: start %3d, mask 0x%08x (gpio %d)\n",

base, irq_start, irq_sources, irq_gpio);

for (i = 0; ios > i; i++) {

if (irq_sources & (1 <

int irq = irq_start + i; /* irq gpio ABCDE_i irq number */

irq_set_chip_data(irq, base);  /* desc->irq_data.chip_data:gpioABCDE controller base address; */

irq_set_chip_and_handler(irq, &gpio_chip, handle_level_irq); /* desc->irq_data.chip:gpio_chip; desc->handle_irq:handle_level_irq() */

set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);

}

}

/* init gpio irq register  */

writel(0xFFFFFFFF, base + GPIO_INT_STATUS);

writel(0x0, base + GPIO_INT_ENB);

writel(0x0, base + GPIO_INT_DET);

printk("~~~ %s() set GPIO* handler_data chained_handler\n", __func__);

/* register gpio irq handler data */

irq_set_handler_data(irq_gpio, base); /* irq_gpio:gpio ABCDE controller irq number */

/*

* call gpio_mask_irq

* chip and chip data is registerd at gic_init

*/

irq_set_chained_handler(irq_gpio, gpio_handler); /* set gpio ABCDE irq desc->handle_irq:gpio_handler() */

struct irq_desc *desc = irq_to_desc(irq_gpio);

struct irq_chip *chip = desc->irq_data.chip;

printk("~~~ %s() GPIO parent irq:%u, chip name:%s\n",\

__func__, irq_gpio, chip->name);

/* next */

irq_gpio++;

irq_start += ios; /* irq_start += 32, group gpioABCDE 32 io */

base += GPIO_BASE_OFFSET; /* add base address */

}

}

s5p6818有A B C D E ALIVE 6个gpio controller;(A B C D E(controller)组GPIO),每组gpio 下有32个io;

代码很简单:set gpio ABCDE_i io 的struct irq_desc desc;(one of struct irq_desc irq_desc[NR_IRQS]);

desc->irq_data.chip_data:gpioABCDE controller base address;

desc->irq_data.chip:gpio_chip;

desc->handle_irq:handle_level_irq();

set gpio ABCDE controller 的struct irq_desc desc;(one of struct irq_desc irq_desc[NR_IRQS]);

desc->irq_data.handler_data:gpioABCDE controller base address;

desc->handle_irq:gpio_handler;

and irq_startup(desc, true);/*

* Set a highlevel chained flow handler for a given IRQ.

* (a chained handler is automatically enabled and set to

*  IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD)

*/

static inline void

irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)

{

printk("~~~ %s() irq:%u, is_chained:%d\n", \

__func__, irq, 1);

__irq_set_handler(irq, handle, 1(is_chained)), NULL);

|

{

desc->handle_irq = handle;

if (handle != handle_bad_irq && is_chained) {

irq_settings_set_noprobe(desc);

irq_settings_set_norequest(desc);

irq_settings_set_nothread(desc);

irq_startup(desc, true);

}

}

}

如上,可知void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name);

is_chained的用意;

当发生gpio中断,会先call gpio ABCDE controller desc->handle_irq();gpio_handler();/* arch/arm/mach-s5p6818/irq.c */

static void gpio_handler(unsigned int irq, struct irq_desc *desc)

{

void __iomem *base = irq_desc_get_handler_data(desc);

u32 stat, mask;

int phy, bit;

mask = readl(base + GPIO_INT_ENB);

stat = readl(base + GPIO_INT_STATUS) & mask;

bit  = ffs(stat) - 1;

phy  = irq;

pr_debug("%s: gpio irq=%d [%s.%d], stat=0x%08x, mask=0x%08x\n",

__func__, phy, PIO_NAME(phy), bit, stat, mask);

printk("~~~ %s: gpio irq:%d [%s.%d], stat=0x%08x, mask=0x%08x\n",

__func__, phy, PIO_NAME(phy), bit, stat, mask);

if (-1 == bit) {

printk(KERN_ERR "Unknown gpio phy irq=%d, status=0x%08x, mask=0x%08x\r\n",

phy, stat, mask);

writel(-1, (base + GPIO_INT_STATUS));/* clear gpio status all */

writel_relaxed(phy, GIC_CPUI_BASE + GIC_CPU_EOI);

return;

}

/* gpio descriptor */

irq  = (VIO_IRQ_BASE + bit + (32 * (phy - PIO_IRQ_BASE)));// virtual irq

printk("~~~ %s() irq:%u, irq_desc->irq_data.irq:%u\n", \

__func__, irq, irq_desc->irq_data.irq);

/*desc = irq_desc + irq;*/ /*the global struct irq_desc irq_desc[NR_IRQS]*/

desc = irq_to_desc(irq);

if (desc && desc->action) {

/* disable irq reentrant */

desc->action->flags |= IRQF_DISABLED;

printk("~~~ %s() call generic_handle_irq_desc(), irq_desc->irq_data.irq:%u, atcion name:%s\n", \

__func__, desc->irq_data.irq, desc->action->name);

generic_handle_irq_desc(irq, desc);

} else {

printk(KERN_ERR "Error, not registered gpio interrupt=%d (%s.%d), disable !!!\n",

irq, PIO_NAME(phy), bit);

writel(readl(base + GPIO_INT_ENB) & ~(1<

writel(readl(base + GPIO_INT_STATUS) | (1<

readl(base + GPIO_INT_STATUS);/* Guarantee */

}

printk("~~~ %s() write CPUI end of INT reg, irq:%u\n", __func__, irq);

writel_relaxed(phy, GIC_CPUI_BASE + GIC_CPU_EOI);

return;

}

读寄存器,确认是具体哪个io,得到对应的struct irq_desc desc;

call generic_handle_irq_desc(irq, desc);

之后operate gic chip, end of gpio ABCDE controller irq:writel_relaxed(phy, GIC_CPUI_BASE + GIC_CPU_EOI);

inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)/* include/linux/irqdesc.h */

/*

* Architectures call this to let the generic IRQ layer

* handle an interrupt. If the descriptor is attached to an

* irqchip-style controller then we call the ->handle_irq() handler,

* and it calls __do_IRQ() if it's attached to an irqtype-style controller.

*/

static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)

{

if (irq >= IRQ_PHY_GPIOA)

printk("~~~ %s() irq:%u, irq_desc->irq_data.irq:%u\n", \

__func__, irq, irq_desc->irq_data.irq);

desc->handle_irq(irq, desc);

}

call desc->handle_irq(irq, desc);

也就是:void handle_level_irq(unsigned int irq, struct irq_desc *desc);/* kernel/irq/chip.c */

/**

*handle_level_irq - Level type irq handler

*@irq:the interrupt number

*@desc:the interrupt description structure for this irq

*

*Level type interrupts are active as long as the hardware line has

*the active level. This may require to mask the interrupt and unmask

*it after the associated handler has acknowledged the device, so the

*interrupt line is back to inactive.

*/

void

handle_level_irq(unsigned int irq, struct irq_desc *desc)

{

printk("~~~ %s() irq:%d\n", __func__, irq);

raw_spin_lock(&desc->lock);

mask_ack_irq(desc);

if (unlikely(irqd_irq_inprogress(&desc->irq_data)))

if (!irq_check_poll(desc))

goto out_unlock;

desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);

kstat_incr_irqs_this_cpu(irq, desc);

/*

* If its disabled or no action available

* keep it masked and get out of here

*/

if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data)))

goto out_unlock;

printk("~~~ %s() irq:%d, call handle_irq_event(), action name:%s\n", \

__func__, irq, desc->action->name);

handle_irq_event(desc);

cond_unmask_irq(desc);

out_unlock:

raw_spin_unlock(&desc->lock);

}

EXPORT_SYMBOL_GPL(handle_level_irq);

call:

...

mask_ack_irq(desc);

...

handle_irq_event(desc);

cond_unmask_irq(desc);

...mask_ack_irq(desc)

|

desc->irq_data.chip->irq_mask(&desc->irq_data);  / * gpio mask : irq disable  */

desc->irq_data.chip->irq_ack(&desc->irq_data);  / * gpio ack : irq pend clear */

/**/

cond_unmask_irq(desc)

|

desc->irq_data.chip->irq_unmask(&desc->irq_data); /* gpio unmask : irq enable */

irqreturn_t handle_irq_event(struct irq_desc *desc)/* kernel/irq/handle.c */

irqreturn_t handle_irq_event(struct irq_desc *desc)

{

struct irqaction *action = desc->action;

irqreturn_t ret;

if (desc->irq_data.irq >= IRQ_PHY_GPIOA)

printk("~~~ %s() irq:%d, name:%s, irq_chip:%s\n", \

__func__, desc->irq_data.irq, desc->name, \

(desc->irq_data.chip)->name);

desc->istate &= ~IRQS_PENDING;

irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);

raw_spin_unlock(&desc->lock);

ret = handle_irq_event_percpu(desc, action);

raw_spin_lock(&desc->lock);

irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);

return ret;

}

/* kernel/irq/handle.c */

irqreturn_t

handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)

{

irqreturn_t retval = IRQ_NONE;

unsigned int flags = 0, irq = desc->irq_data.irq;

if (irq >= IRQ_PHY_GPIOA)

printk("~~~ %s() irq:%d, name:%s\n", __func__, irq, desc->name);

do {

irqreturn_t res;

trace_irq_handler_entry(irq, action);

res = action->handler(irq, action->dev_id);

if (irq >= IRQ_PHY_GPIOA)

printk("~~~ %s() after call action->handler(), name:%s, res:%d\n", \

__func__, action->name, res);

trace_irq_handler_exit(irq, action, res);

if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",

irq, action->handler))

local_irq_disable();

switch (res) {

case IRQ_WAKE_THREAD:

/*

* Catch drivers which return WAKE_THREAD but

* did not set up a thread function

*/

if (unlikely(!action->thread_fn)) {

warn_no_thread(irq, action);

break;

}

if (irq >= IRQ_PHY_GPIOA)

printk("~~~ %s() irq_wake_thread\n", \

__func__);

irq_wake_thread(desc, action);

/* Fall through to add to randomness */

case IRQ_HANDLED:

flags |= action->flags;

break;

default:

break;

}

retval |= res;

action = action->next;

} while (action);

add_interrupt_randomness(irq, flags);

if (!noirqdebug)

note_interrupt(irq, desc, retval);

return retval;

}

终于到达:

res = action->handler(irq, action->dev_id);

gpio_interrupt_init/ alive_gpio_interrupt initialize, log[    0.000000] ~~~ gpio_init() set GPIO* handler_data chained_handler

[    0.000000] ~~~ irq_set_chained_handler() irq:85, is_chained:1

[    0.000000] ~~~ irq_startup() irq:85, call irq_enable()

[    0.000000] ~~~ gpio_init() GPIO parent irq:85, chip name:GIC

[    0.000000] GPIO  @f001b000: start 138, mask 0xffffffff (gpio 86)

[    0.000000] ~~~ gpio_init() set GPIO* handler_data chained_handler

[    0.000000] ~~~ irq_set_chained_handler() irq:86, is_chained:1

[    0.000000] ~~~ irq_startup() irq:86, call irq_enable()

[    0.000000] ~~~ gpio_init() GPIO parent irq:86, chip name:GIC

[    0.000000] GPIO  @f001c000: start 170, mask 0xffffffff (gpio 87)

[    0.000000] ~~~ gpio_init() set GPIO* handler_data chained_handler

[    0.000000] ~~~ irq_set_chained_handler() irq:87, is_chained:1

[    0.000000] ~~~ irq_startup() irq:87, call irq_enable()

[    0.000000] ~~~ gpio_init() GPIO parent irq:87, chip name:GIC

[    0.000000] GPIO  @f001d000: start 202, mask 0xffffffff (gpio 88)

[    0.000000] ~~~ gpio_init() set GPIO* handler_data chained_handler

[    0.000000] ~~~ irq_set_chained_handler() irq:88, is_chained:1

[    0.000000] ~~~ irq_startup() irq:88, call irq_enable()

[    0.000000] ~~~ gpio_init() GPIO parent irq:88, chip name:GIC

[    0.000000] GPIO  @f001e000: start 234, mask 0xffffffff (gpio 89)

[    0.000000] ~~~ gpio_init() set GPIO* handler_data chained_handler

[    0.000000] ~~~ irq_set_chained_handler() irq:89, is_chained:1

[    0.000000] ~~~ irq_startup() irq:89, call irq_enable()

[    0.000000] ~~~ gpio_init() GPIO parent irq:89, chip name:GIC

[    0.000000] ALIVE @f0010800: start 266, mask 0x000000ff (alive 36, num 6)

[    0.000000] ~~~ irq_set_chained_handler() irq:36, is_chained:1

[    0.000000] ~~~ irq_startup() irq:36, call irq_enable()

[    0.000000] ~~~ alive_init() ALIVE GPIO parent irq:36, chip name:GIC

press the button and release, trigger gpio interrupt handling, key driver code and log#define CFG_KEYPAD_KEY_OK{ PAD_GPIO_B + 31 }

#define CFG_KEYPAD_KEY_OK_CODE{ KEY_OK } /* 352 */

/* drivers/input/keyboard/nxp_io_key.c */

...

static int nxp_key_probe(struct platform_device *pdev)

{

...

ret = request_irq(gpio_to_irq(code->io), nxp_key_irqhnd,

(IRQF_SHARED | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING), pdev->name, code);

...

}

...

static irqreturn_t nxp_key_irqhnd(int irqno, void *dev_id)

{

struct key_code *code = dev_id;

printk("~~~ %s() irqno:%d\n", __func__, irqno);

queue_delayed_work(code->kcode_wq,

&code->kcode_work, DELAY_WORK_JIFFIES);

return IRQ_HANDLED;

}

...

static void nxp_key_event_wq(struct work_struct *work)

{

struct key_code *code = (struct key_code *)work;

struct key_info *key = code->info;

unsigned int keycode = code->keycode;

int press = 0;

u_long flags;

local_irq_save(flags);

press = gpio_get_value_cansleep(code->io);

if (code->detect_high)

press = !press;

local_irq_restore(flags);

if(press != code->keystat) {

code->keystat = press;

if (KEY_STAT_PRESS == press) {

input_report_key(key->input, keycode, 1);

input_sync(key->input);

} else {

input_report_key(key->input, keycode, 0);

input_sync(key->input);

}

pr_debug("key io:%d, code:%4d %s\n", code->io, keycode,

(KEY_STAT_PRESS==press?"DN":"UP"));

}

}

...[root@machine /]#

[root@machine /]#

[   41.944000] ~~~ gic_handle_irq() hwirq:86

[   41.944000] ~~~ irq_domain_legacy_revmap() hwirq:86

[   41.948000] ~~~ irq_find_mapping() hwirq:86, irq:86

[   41.952000] ~~~ gic_handle_irq() irqnr:86

[   41.956000] ~~~ generic_handle_irq() irq:86, irq_desc->irq_data.irq:0

[   41.964000] ~~~ generic_handle_irq_desc() irq:86, irq_desc->irq_data.irq:0

[   41.972000] gpio_handler: gpio irq=86 [GPIOB.31], stat=0x80000000, mask=0x88000000

[   41.976000] ~~~ gpio_handler: gpio irq:86 [GPIOB.31], stat=0x80000000, mask=0x88000000

[   41.984000] ~~~ gpio_handler() irq:169, irq_desc->irq_data.irq:0

[   41.992000] ~~~ gpio_handler() call generic_handle_irq_desc(), irq_desc->irq_data.irq:169, atcion name:nxp-keypad

[   42.004000] ~~~ generic_handle_irq_desc() irq:169, irq_desc->irq_data.irq:0

[   42.008000] ~~~ handle_level_irq() irq:169

[   42.012000] gpio_mask_irq: gpio irq = 169, GPIOB.31

[   42.016000] gpio_ack_irq: gpio irq = 169, GPIOB.31

[   42.024000] ~~~ handle_level_irq() irq:169, call handle_irq_event(), action name:nxp-keypad

[   42.032000] ~~~ handle_irq_event() irq:169, name:(null), irq_chip:GPIO

[   42.036000] ~~~ handle_irq_event_percpu() irq:169, name:(null)

[   42.044000] ~~~ nxp_key_irqhnd() irqno:169

[   42.048000] ~~~ handle_irq_event_percpu() after call action->handler(), name:nxp-keypad, res:1

[   42.056000] gpio_unmask_irq: gpio irq = 169, GPIOB.31

[   42.060000] ~~~ gpio_handler() write CPUI end of INT reg, irq:169

[   42.068000] key io:63, code: 352 DN

[root@machine /]#

[root@machine /]#

[root@machine /]#

[root@machine /]#

[root@machine /]#

[root@machine /]#

[root@machine /]#

[   46.620000] ~~~ gic_handle_irq() hwirq:86

[   46.620000] ~~~ irq_domain_legacy_revmap() hwirq:86

[   46.624000] ~~~ irq_find_mapping() hwirq:86, irq:86

[   46.628000] ~~~ gic_handle_irq() irqnr:86

[   46.632000] ~~~ generic_handle_irq() irq:86, irq_desc->irq_data.irq:0

[   46.640000] ~~~ generic_handle_irq_desc() irq:86, irq_desc->irq_data.irq:0

[   46.644000] gpio_handler: gpio irq=86 [GPIOB.31], stat=0x80000000, mask=0x88000000

[   46.652000] ~~~ gpio_handler: gpio irq:86 [GPIOB.31], stat=0x80000000, mask=0x88000000

[   46.660000] ~~~ gpio_handler() irq:169, irq_desc->irq_data.irq:0

[   46.668000] ~~~ gpio_handler() call generic_handle_irq_desc(), irq_desc->irq_data.irq:169, atcion name:nxp-keypad

[   46.676000] ~~~ generic_handle_irq_desc() irq:169, irq_desc->irq_data.irq:0

[   46.684000] ~~~ handle_level_irq() irq:169

[   46.688000] gpio_mask_irq: gpio irq = 169, GPIOB.31

[   46.692000] gpio_ack_irq: gpio irq = 169, GPIOB.31

[   46.696000] ~~~ handle_level_irq() irq:169, call handle_irq_event(), action name:nxp-keypad

[   46.704000] ~~~ handle_irq_event() irq:169, name:(null), irq_chip:GPIO

[   46.712000] ~~~ handle_irq_event_percpu() irq:169, name:(null)

[   46.716000] ~~~ nxp_key_irqhnd() irqno:169

[   46.724000] ~~~ handle_irq_event_percpu() after call action->handler(), name:nxp-keypad, res:1

[   46.732000] gpio_unmask_irq: gpio irq = 169, GPIOB.31

[   46.736000] ~~~ gpio_handler() write CPUI end of INT reg, irq:169

[   46.740000] key io:63, code: 352 UP

[root@machine /]#

s5p6818 gpio irq code:/* arch/arm/mach-s5p6818/irq.c */

/*

* (C) Copyright 2009

* jung hyun kim, Nexell Co,*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include#include#include#include#include#include#include#include#include#include#include#include#include/*

#define pr_debugprintk

*/

#defineINTC_BASE(void __iomem *)IO_ADDRESS(PHY_BASEADDR_INTC)

#defineGIC_PHY_OFFSET(0)

//----------------------------------------------------------------------------

static void __init __gic_init(void __iomem *dist_base, void __iomem *cpu_base);

static void __init gpio_init(void __iomem *base, unsigned int irq_start,

u32 irq_sources, u32 resume_sources);

static void __init alive_init(void __iomem *base, unsigned int irq_start,

u32 irq_sources, u32 resume_sources);

/*----------------------------------------------------------------------------

*  cpu irq handler

*/

#define GIC_DIST_BASE(void __iomem *)(INTC_BASE + 0x00001000)// 0xC0009000

#define GIC_CPUI_BASE(void __iomem *)(INTC_BASE + 0x00002000)// 0xC000a000

#define GPIO_INT_BASE(void __iomem *)IO_ADDRESS(PHY_BASEADDR_GPIOA)

#define GPIO_BASE_OFFSET(0x1000)

#define GPIO_INT_MASK(0xFFFFFFFF)

#define ALIVE_INT_BASE(void __iomem *)IO_ADDRESS(PHY_BASEADDR_CLKPWR_MODULE + 0x800)

#define ALIVE_INT_MASK(0x000000FF)

/*

*  cpu irq handler

*/

void __init nxp_cpu_irq_init(void)

{

pr_debug("%s:%d\n", __func__, __LINE__);

printk("~~~ %s()\n", __func__);

__gic_init(GIC_DIST_BASE, (void __iomem *)GIC_CPUI_BASE);

gpio_init(GPIO_INT_BASE , IRQ_GPIO_START, GPIO_INT_MASK, 0);/* 64 ~ 223 (A,B,C,D,E) */

alive_init(ALIVE_INT_BASE, IRQ_ALIVE_START, ALIVE_INT_MASK, 0); /* 224 ~ 231 */

#ifdef CONFIG_FIQ

init_FIQ();

#endif

/* wake up source from idle */

irq_set_irq_wake(IRQ_PHY_CLKPWR_ALIVEIRQ + GIC_PHY_OFFSET, 1);

#if PM_RTC_WAKE

irq_set_irq_wake(IRQ_PHY_CLKPWR_RTCIRQ + GIC_PHY_OFFSET, 1);

#endif

}

static void __init __gic_init(void __iomem *dist_base, void __iomem *cpu_base)

{

int irq = IRQ_GIC_PPI_VIC;

printk(KERN_INFO "GIC   @%p: start %3d (gic %d)\n",

dist_base, IRQ_GIC_START, (irq-IRQ_GIC_START));

printk("~~~ %s() call gic_init()\n", __func__);

gic_init(0, IRQ_GIC_PPI_START, dist_base, cpu_base);

}

/*----------------------------------------------------------------------------

*  ALIVE irq chain handler

*  start  -> request_irq -> alive irq_unmask

*  do IRQ -> alive handler -> alive irq_mask -> alive irq_ack -> driver handler -> alive irq_unmask ->

*  end    -> disable

----------------------------------------------------------------------------*/

#defineALIVE_MOD_REST(0x04)// detect mode reset

#defineALIVE_MOD_SET(0x08)// detect mode

#defineALIVE_MOD_READ(0x0C)// detect mode read

#defineALIVE_DET_RESET(0x4C)

#defineALIVE_DET_SET(0x50)

#defineALIVE_DET_READ(0x54)

#defineALIVE_INT_RESET(0x58)// interrupt reset : disable

#defineALIVE_INT_SET(0x5C)// interrupt set: enable

#defineALIVE_INT_SET_READ(0x60)// interrupt set read

#defineALIVE_INT_STATUS(0x64)// interrupt detect pending and clear

#defineALIVE_OUT_RESET(0x74)

#defineALIVE_OUT_SET(0x78)

#defineALIVE_OUT_READ(0x7C)

static void alive_ack_irq(struct irq_data *d)

{

void __iomem *base = irq_data_get_irq_chip_data(d);

int bit = (d->irq - IRQ_ALIVE_START) & 0x1F;

pr_debug("%s: alive irq = %d, io = %d\n", __func__, d->irq, bit);

/* alive ack : irq pend clear */

writel((1

pr_debug("%s: alive irq = %d, io = %d\n", __func__, d->irq, bit);

/* alive mask : irq reset (disable) */

writel((1

pr_debug("%s: alive irq = %d, io = %d\n", __func__, d->irq, bit);

/* alive unmask : irq set (enable) */

writel((1

int offs = 0, i = 0;

NX_ALIVE_DETECTMODE mode = 0;

pr_debug("%s: alive irq = %d, io = %d, type=0x%x\n",

__func__, d->irq, bit, type);

switch (type) {

case IRQ_TYPE_NONE:printk(KERN_WARNING "%s: No edge setting!\n", __func__);

break;

case IRQ_TYPE_EDGE_FALLING:mode = NX_ALIVE_DETECTMODE_SYNC_FALLINGEDGE; break;

case IRQ_TYPE_EDGE_RISING:mode = NX_ALIVE_DETECTMODE_SYNC_RISINGEDGE;break;

case IRQ_TYPE_EDGE_BOTH:mode = NX_ALIVE_DETECTMODE_SYNC_FALLINGEDGE; break;/* and Rising Edge */

case IRQ_TYPE_LEVEL_LOW:mode = NX_ALIVE_DETECTMODE_ASYNC_LOWLEVEL; break;

case IRQ_TYPE_LEVEL_HIGH:mode = NX_ALIVE_DETECTMODE_ASYNC_HIGHLEVEL; break;

default:

printk(KERN_ERR "%s: No such irq type %d", __func__, type);

return -1;

}

for ( ; 6 > i; i++, offs += 0x0C) {

reg = (i == mode ? ALIVE_MOD_SET : ALIVE_MOD_REST);

writel(1<

}

/*

* set risingedge mode for both edge

* 0x2C : Risingedge

*/

if (IRQ_TYPE_EDGE_BOTH == type)

writel(1<

writel(1<

writel(1<

writel(1

pr_info("%s: alive irq = %d, io = %d wake %s\n",

__func__, d->irq, bit, on?"on":"off");

#endif

return 0;

}

static void alive_irq_enable(struct irq_data *d)

{

void __iomem *base = irq_data_get_irq_chip_data(d);

int bit = (d->irq - IRQ_ALIVE_START) & 0x1F;

pr_debug("%s: alive irq = %d, io = %d\n", __func__, d->irq, bit);

printk("~~~ %s() alive irq:%d, io:%d\n", __func__, d->irq, bit);

/* alive unmask : irq set (enable) */

writel((1

pr_debug("%s: alive irq = %d, io = %d\n", __func__, d->irq, bit);

printk("~~~ %s() alive irq:%d, io:%d\n", __func__, d->irq, bit);

/* alive mask : irq reset (disable) */

writel((1

desc->action->flags |= IRQF_DISABLED;/* disable irq reentrant */

generic_handle_irq_desc(irq, desc);

} else {

printk(KERN_ERR "Error, not registered alive interrupt=%d (%d.%d), disable !!!\n",

irq, phy, bit);

writel(readl(base + ALIVE_INT_SET) & ~(1<

writel(readl(base + ALIVE_INT_STATUS) | (1

if (irq_sources & (1 <

int irq = irq_start + i;

irq_set_chip_data(irq, base);

irq_set_chip_and_handler(irq, &alive_chip, handle_level_irq);

set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);

}

}

/* register alive irq handler data */

irq_set_handler_data(irq_alive, base);

/*

* call alive_mask_irq

* chip and chip data is registerd at gic_init

*/

irq_set_chained_handler(irq_alive, alive_handler);

struct irq_desc *desc = irq_to_desc(irq_alive);

struct irq_chip *chip = desc->irq_data.chip;

printk("~~~ %s() ALIVE GPIO parent irq:%u, chip name:%s\n",\

__func__, irq_alive, chip->name);

}

/*----------------------------------------------------------------------------

*  GPIO irq chain handler

*  start  -> request_irq -> gpio irq_unmask

*  do IRQ -> gpio handler -> gpio irq_mask -> gpio irq_ack -> driver handler -> gpio irq_unmask ->

*  end    -> disable

----------------------------------------------------------------------------*/

static const char *io_name[] = { "GPIOA", "GPIOB", "GPIOC", "GPIOD", "GPIOE", };

#definePIO_IRQ_BASEIRQ_PHY_GPIOA

#defineVIO_IRQ_BASEIRQ_GPIO_START

#defineVIO_NAME(i)(io_name[(i-VIO_IRQ_BASE)/32])

#definePIO_NAME(i)(io_name[(i-PIO_IRQ_BASE)])

#defineGPIO_OUT_ENB0x04

#defineGPIO_INT_MODE00x08// 0x08,0x0C

#defineGPIO_INT_MODE10x28

#defineGPIO_INT_ENB0x10

#defineGPIO_INT_STATUS0x14

#defineGPIO_ALT_MODE0x20// 0x20,0x24

#defineGPIO_INT_DET0x3C

static void gpio_ack_irq(struct irq_data *d)

{

void __iomem *base = irq_data_get_irq_chip_data(d);

int bit = (d->irq - IRQ_GPIO_START) & 0x1F;

pr_debug("%s: gpio irq = %d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

/* gpio ack : irq pend clear */

writel((1

pr_debug("%s: gpio irq = %d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

/* gpio mask : irq disable */

writel(readl(base + GPIO_INT_ENB) & ~(1<

writel(readl(base + GPIO_INT_DET) & ~(1

pr_debug("%s: gpio irq = %d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

/* gpio unmask : irq enable */

writel(readl(base + GPIO_INT_ENB) | (1<

writel(readl(base + GPIO_INT_DET) | (1

unsigned int reg, val, alt;

NX_GPIO_INTMODE mode = 0;

pr_debug("%s: gpio irq = %d, %s.%d, type=0x%x\n",

__func__, d->irq, VIO_NAME(d->irq), bit, type);

switch (type) {

case IRQ_TYPE_NONE:printk(KERN_WARNING "%s: No edge setting!\n", __func__);

break;

case IRQ_TYPE_EDGE_RISING:mode = NX_GPIO_INTMODE_RISINGEDGE;break;

case IRQ_TYPE_EDGE_FALLING:mode = NX_GPIO_INTMODE_FALLINGEDGE;break;

case IRQ_TYPE_EDGE_BOTH:mode = NX_GPIO_INTMODE_BOTHEDGE;break;

case IRQ_TYPE_LEVEL_LOW:mode = NX_GPIO_INTMODE_LOWLEVEL;break;

case IRQ_TYPE_LEVEL_HIGH:mode = NX_GPIO_INTMODE_HIGHLEVEL;break;

default:

printk(KERN_ERR "%s: No such irq type %d", __func__, type);

return -1;

}

/* gpio out : output disable */

writel(readl(base + GPIO_OUT_ENB) & ~(1<

/* gpio mode : interrupt mode */

reg  = (unsigned int)(base + GPIO_INT_MODE0 + (bit/16) * 4);

val  = readl(reg) & ~(3<

val |= (mode&0x3) <

pr_debug("reg=0x%08x, val=0x%08x\n", reg, val);

writel(val, reg);

reg  = (unsigned int)(base + GPIO_INT_MODE1);

val  = readl(reg) & ~(1<>2) & 0x1) <

pr_debug("reg=0x%08x, val=0x%08x\n", reg, val);

writel(val, reg);

/* gpio alt : gpio mode for irq */

reg  = (unsigned int)(base + GPIO_ALT_MODE + (bit/16) * 4);

val  = readl(reg) & ~(3

val |= alt <

pr_debug("reg=0x%08x, val=0x%08x\n", reg, val);

writel(val, reg);

return 0;

}

static int gpio_set_wake(struct irq_data *d, unsigned int on)

{

#if (0)

void __iomem *base = irq_data_get_irq_chip_data(d);

int bit = (d->irq - IRQ_GPIO_START) & 0x1F;

pr_debug("%s: gpio irq = %d, %s.%d wake %s\n",

__func__, d->irq, VIO_NAME(d->irq), bit, on?"on":"off");

#endif

return 0;

}

static void gpio_irq_enable(struct irq_data *d)

{

void __iomem *base = irq_data_get_irq_chip_data(d);

int bit = (d->irq - IRQ_GPIO_START) & 0x1F;

pr_debug("%s: gpio irq = %d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

printk("~~~ %s() gpio irq:%d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

/* gpio unmask : irq enable */

writel(readl(base + GPIO_INT_ENB) | (1<

writel(readl(base + GPIO_INT_DET) | (1

pr_debug("%s: gpio irq = %d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

printk("~~~ %s() gpio irq:%d, %s.%d\n", __func__, d->irq, VIO_NAME(d->irq), bit);

/* gpio mask : irq disable */

writel(readl(base + GPIO_INT_ENB) & ~(1<

writel(readl(base + GPIO_INT_DET) & ~(1

/*desc = irq_desc + irq;*/ /*the global struct irq_desc irq_desc[NR_IRQS]*/

desc = irq_to_desc(irq);

if (desc && desc->action) {

/* disable irq reentrant */

desc->action->flags |= IRQF_DISABLED;

printk("~~~ %s() call generic_handle_irq_desc(), irq_desc->irq_data.irq:%u, atcion name:%s\n", \

__func__, desc->irq_data.irq, desc->action->name);

generic_handle_irq_desc(irq, desc);

} else {

printk(KERN_ERR "Error, not registered gpio interrupt=%d (%s.%d), disable !!!\n",

irq, PIO_NAME(phy), bit);

writel(readl(base + GPIO_INT_ENB) & ~(1<

writel(readl(base + GPIO_INT_STATUS) | (1

printk(KERN_INFO "GPIO  @%p: start %3d, mask 0x%08x (gpio %d)\n",

base, irq_start, irq_sources, irq_gpio);

for (i = 0; ios > i; i++) {

if (irq_sources & (1 <

int irq = irq_start + i;

irq_set_chip_data(irq, base);

irq_set_chip_and_handler(irq, &gpio_chip, handle_level_irq);

set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);

}

}

/* init gpio irq register  */

writel(0xFFFFFFFF, base + GPIO_INT_STATUS);

writel(0x0, base + GPIO_INT_ENB);

writel(0x0, base + GPIO_INT_DET);

printk("~~~ %s() set GPIO* handler_data chained_handler\n", __func__);

/* register gpio irq handler data */

irq_set_handler_data(irq_gpio, base);

/*

* call gpio_mask_irq

* chip and chip data is registerd at gic_init

*/

irq_set_chained_handler(irq_gpio, gpio_handler);

struct irq_desc *desc = irq_to_desc(irq_gpio);

struct irq_chip *chip = desc->irq_data.chip;

printk("~~~ %s() GPIO parent irq:%u, chip name:%s\n",\

__func__, irq_gpio, chip->name);

/* next */

irq_gpio++;

irq_start += ios;

base += GPIO_BASE_OFFSET;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值