1bf973285SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0 244358048SMagnus Damm /* 344358048SMagnus Damm * Renesas INTC External IRQ Pin Driver 444358048SMagnus Damm * 544358048SMagnus Damm * Copyright (C) 2013 Magnus Damm 644358048SMagnus Damm */ 744358048SMagnus Damm 844358048SMagnus Damm #include <linux/init.h> 9894db164SGuennadi Liakhovetski #include <linux/of.h> 1044358048SMagnus Damm #include <linux/platform_device.h> 1144358048SMagnus Damm #include <linux/spinlock.h> 1244358048SMagnus Damm #include <linux/interrupt.h> 1344358048SMagnus Damm #include <linux/ioport.h> 1444358048SMagnus Damm #include <linux/io.h> 1544358048SMagnus Damm #include <linux/irq.h> 1644358048SMagnus Damm #include <linux/irqdomain.h> 1744358048SMagnus Damm #include <linux/err.h> 1844358048SMagnus Damm #include <linux/slab.h> 1944358048SMagnus Damm #include <linux/module.h> 20e03f9088SMagnus Damm #include <linux/of_device.h> 21705bc96cSGeert Uytterhoeven #include <linux/pm_runtime.h> 2244358048SMagnus Damm 2344358048SMagnus Damm #define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */ 2444358048SMagnus Damm 2544358048SMagnus Damm #define INTC_IRQPIN_REG_SENSE 0 /* ICRn */ 2644358048SMagnus Damm #define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */ 2744358048SMagnus Damm #define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */ 2844358048SMagnus Damm #define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */ 2944358048SMagnus Damm #define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */ 30e03f9088SMagnus Damm #define INTC_IRQPIN_REG_NR_MANDATORY 5 31e03f9088SMagnus Damm #define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */ 32e03f9088SMagnus Damm #define INTC_IRQPIN_REG_NR 6 3344358048SMagnus Damm 3444358048SMagnus Damm /* INTC external IRQ PIN hardware register access: 3544358048SMagnus Damm * 3644358048SMagnus Damm * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*) 3744358048SMagnus Damm * PRIO is read-write 32-bit with 4-bits per IRQ (**) 3844358048SMagnus Damm * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***) 3944358048SMagnus Damm * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***) 4044358048SMagnus Damm * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***) 4144358048SMagnus Damm * 4244358048SMagnus Damm * (*) May be accessed by more than one driver instance - lock needed 4344358048SMagnus Damm * (**) Read-modify-write access by one driver instance - lock needed 4444358048SMagnus Damm * (***) Accessed by one driver instance only - no locking needed 4544358048SMagnus Damm */ 4644358048SMagnus Damm 4744358048SMagnus Damm struct intc_irqpin_iomem { 4844358048SMagnus Damm void __iomem *iomem; 4944358048SMagnus Damm unsigned long (*read)(void __iomem *iomem); 5044358048SMagnus Damm void (*write)(void __iomem *iomem, unsigned long data); 5144358048SMagnus Damm int width; 5244358048SMagnus Damm }; 5344358048SMagnus Damm 5444358048SMagnus Damm struct intc_irqpin_irq { 5544358048SMagnus Damm int hw_irq; 5633f958f2SMagnus Damm int requested_irq; 5733f958f2SMagnus Damm int domain_irq; 5844358048SMagnus Damm struct intc_irqpin_priv *p; 5944358048SMagnus Damm }; 6044358048SMagnus Damm 6144358048SMagnus Damm struct intc_irqpin_priv { 6244358048SMagnus Damm struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR]; 6344358048SMagnus Damm struct intc_irqpin_irq irq[INTC_IRQPIN_MAX]; 64f9551a9cSGeert Uytterhoeven unsigned int sense_bitfield_width; 6544358048SMagnus Damm struct platform_device *pdev; 6644358048SMagnus Damm struct irq_chip irq_chip; 6744358048SMagnus Damm struct irq_domain *irq_domain; 6866bf8252SGeert Uytterhoeven atomic_t wakeup_path; 6986e57ca7SGeert Uytterhoeven unsigned shared_irqs:1; 70427cc720SBastian Hecht u8 shared_irq_mask; 7144358048SMagnus Damm }; 7244358048SMagnus Damm 7386e57ca7SGeert Uytterhoeven struct intc_irqpin_config { 74b388bdf2SGeert Uytterhoeven int irlm_bit; /* -1 if non-existent */ 75e03f9088SMagnus Damm }; 76e03f9088SMagnus Damm 7744358048SMagnus Damm static unsigned long intc_irqpin_read32(void __iomem *iomem) 7844358048SMagnus Damm { 7944358048SMagnus Damm return ioread32(iomem); 8044358048SMagnus Damm } 8144358048SMagnus Damm 8244358048SMagnus Damm static unsigned long intc_irqpin_read8(void __iomem *iomem) 8344358048SMagnus Damm { 8444358048SMagnus Damm return ioread8(iomem); 8544358048SMagnus Damm } 8644358048SMagnus Damm 8744358048SMagnus Damm static void intc_irqpin_write32(void __iomem *iomem, unsigned long data) 8844358048SMagnus Damm { 8944358048SMagnus Damm iowrite32(data, iomem); 9044358048SMagnus Damm } 9144358048SMagnus Damm 9244358048SMagnus Damm static void intc_irqpin_write8(void __iomem *iomem, unsigned long data) 9344358048SMagnus Damm { 9444358048SMagnus Damm iowrite8(data, iomem); 9544358048SMagnus Damm } 9644358048SMagnus Damm 9744358048SMagnus Damm static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p, 9844358048SMagnus Damm int reg) 9944358048SMagnus Damm { 10044358048SMagnus Damm struct intc_irqpin_iomem *i = &p->iomem[reg]; 101862d3098SMagnus Damm 10244358048SMagnus Damm return i->read(i->iomem); 10344358048SMagnus Damm } 10444358048SMagnus Damm 10544358048SMagnus Damm static inline void intc_irqpin_write(struct intc_irqpin_priv *p, 10644358048SMagnus Damm int reg, unsigned long data) 10744358048SMagnus Damm { 10844358048SMagnus Damm struct intc_irqpin_iomem *i = &p->iomem[reg]; 109862d3098SMagnus Damm 11044358048SMagnus Damm i->write(i->iomem, data); 11144358048SMagnus Damm } 11244358048SMagnus Damm 11344358048SMagnus Damm static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p, 11444358048SMagnus Damm int reg, int hw_irq) 11544358048SMagnus Damm { 11644358048SMagnus Damm return BIT((p->iomem[reg].width - 1) - hw_irq); 11744358048SMagnus Damm } 11844358048SMagnus Damm 11944358048SMagnus Damm static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p, 12044358048SMagnus Damm int reg, int hw_irq) 12144358048SMagnus Damm { 12244358048SMagnus Damm intc_irqpin_write(p, reg, intc_irqpin_hwirq_mask(p, reg, hw_irq)); 12344358048SMagnus Damm } 12444358048SMagnus Damm 12544358048SMagnus Damm static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */ 12644358048SMagnus Damm 12744358048SMagnus Damm static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p, 12844358048SMagnus Damm int reg, int shift, 12944358048SMagnus Damm int width, int value) 13044358048SMagnus Damm { 13144358048SMagnus Damm unsigned long flags; 13244358048SMagnus Damm unsigned long tmp; 13344358048SMagnus Damm 13444358048SMagnus Damm raw_spin_lock_irqsave(&intc_irqpin_lock, flags); 13544358048SMagnus Damm 13644358048SMagnus Damm tmp = intc_irqpin_read(p, reg); 13744358048SMagnus Damm tmp &= ~(((1 << width) - 1) << shift); 13844358048SMagnus Damm tmp |= value << shift; 13944358048SMagnus Damm intc_irqpin_write(p, reg, tmp); 14044358048SMagnus Damm 14144358048SMagnus Damm raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags); 14244358048SMagnus Damm } 14344358048SMagnus Damm 14444358048SMagnus Damm static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p, 14544358048SMagnus Damm int irq, int do_mask) 14644358048SMagnus Damm { 147e55bc558SLaurent Pinchart /* The PRIO register is assumed to be 32-bit with fixed 4-bit fields. */ 148e55bc558SLaurent Pinchart int bitfield_width = 4; 149e55bc558SLaurent Pinchart int shift = 32 - (irq + 1) * bitfield_width; 15044358048SMagnus Damm 15144358048SMagnus Damm intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO, 15244358048SMagnus Damm shift, bitfield_width, 15344358048SMagnus Damm do_mask ? 0 : (1 << bitfield_width) - 1); 15444358048SMagnus Damm } 15544358048SMagnus Damm 15644358048SMagnus Damm static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value) 15744358048SMagnus Damm { 158e55bc558SLaurent Pinchart /* The SENSE register is assumed to be 32-bit. */ 159f9551a9cSGeert Uytterhoeven int bitfield_width = p->sense_bitfield_width; 160e55bc558SLaurent Pinchart int shift = 32 - (irq + 1) * bitfield_width; 16144358048SMagnus Damm 16244358048SMagnus Damm dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value); 16344358048SMagnus Damm 16444358048SMagnus Damm if (value >= (1 << bitfield_width)) 16544358048SMagnus Damm return -EINVAL; 16644358048SMagnus Damm 16744358048SMagnus Damm intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift, 16844358048SMagnus Damm bitfield_width, value); 16944358048SMagnus Damm return 0; 17044358048SMagnus Damm } 17144358048SMagnus Damm 17244358048SMagnus Damm static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str) 17344358048SMagnus Damm { 17444358048SMagnus Damm dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n", 17533f958f2SMagnus Damm str, i->requested_irq, i->hw_irq, i->domain_irq); 17644358048SMagnus Damm } 17744358048SMagnus Damm 17844358048SMagnus Damm static void intc_irqpin_irq_enable(struct irq_data *d) 17944358048SMagnus Damm { 18044358048SMagnus Damm struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 18144358048SMagnus Damm int hw_irq = irqd_to_hwirq(d); 18244358048SMagnus Damm 18344358048SMagnus Damm intc_irqpin_dbg(&p->irq[hw_irq], "enable"); 18444358048SMagnus Damm intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); 18544358048SMagnus Damm } 18644358048SMagnus Damm 18744358048SMagnus Damm static void intc_irqpin_irq_disable(struct irq_data *d) 18844358048SMagnus Damm { 18944358048SMagnus Damm struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 19044358048SMagnus Damm int hw_irq = irqd_to_hwirq(d); 19144358048SMagnus Damm 19244358048SMagnus Damm intc_irqpin_dbg(&p->irq[hw_irq], "disable"); 19344358048SMagnus Damm intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); 19444358048SMagnus Damm } 19544358048SMagnus Damm 196427cc720SBastian Hecht static void intc_irqpin_shared_irq_enable(struct irq_data *d) 197427cc720SBastian Hecht { 198427cc720SBastian Hecht struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 199427cc720SBastian Hecht int hw_irq = irqd_to_hwirq(d); 200427cc720SBastian Hecht 201427cc720SBastian Hecht intc_irqpin_dbg(&p->irq[hw_irq], "shared enable"); 202427cc720SBastian Hecht intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); 203427cc720SBastian Hecht 204427cc720SBastian Hecht p->shared_irq_mask &= ~BIT(hw_irq); 205427cc720SBastian Hecht } 206427cc720SBastian Hecht 207427cc720SBastian Hecht static void intc_irqpin_shared_irq_disable(struct irq_data *d) 208427cc720SBastian Hecht { 209427cc720SBastian Hecht struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 210427cc720SBastian Hecht int hw_irq = irqd_to_hwirq(d); 211427cc720SBastian Hecht 212427cc720SBastian Hecht intc_irqpin_dbg(&p->irq[hw_irq], "shared disable"); 213427cc720SBastian Hecht intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); 214427cc720SBastian Hecht 215427cc720SBastian Hecht p->shared_irq_mask |= BIT(hw_irq); 216427cc720SBastian Hecht } 217427cc720SBastian Hecht 21844358048SMagnus Damm static void intc_irqpin_irq_enable_force(struct irq_data *d) 21944358048SMagnus Damm { 22044358048SMagnus Damm struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 22133f958f2SMagnus Damm int irq = p->irq[irqd_to_hwirq(d)].requested_irq; 22244358048SMagnus Damm 22344358048SMagnus Damm intc_irqpin_irq_enable(d); 224d1b6aecdSMagnus Damm 225d1b6aecdSMagnus Damm /* enable interrupt through parent interrupt controller, 226d1b6aecdSMagnus Damm * assumes non-shared interrupt with 1:1 mapping 227d1b6aecdSMagnus Damm * needed for busted IRQs on some SoCs like sh73a0 228d1b6aecdSMagnus Damm */ 22944358048SMagnus Damm irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq)); 23044358048SMagnus Damm } 23144358048SMagnus Damm 23244358048SMagnus Damm static void intc_irqpin_irq_disable_force(struct irq_data *d) 23344358048SMagnus Damm { 23444358048SMagnus Damm struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 23533f958f2SMagnus Damm int irq = p->irq[irqd_to_hwirq(d)].requested_irq; 23644358048SMagnus Damm 237d1b6aecdSMagnus Damm /* disable interrupt through parent interrupt controller, 238d1b6aecdSMagnus Damm * assumes non-shared interrupt with 1:1 mapping 239d1b6aecdSMagnus Damm * needed for busted IRQs on some SoCs like sh73a0 240d1b6aecdSMagnus Damm */ 24144358048SMagnus Damm irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq)); 24244358048SMagnus Damm intc_irqpin_irq_disable(d); 24344358048SMagnus Damm } 24444358048SMagnus Damm 24544358048SMagnus Damm #define INTC_IRQ_SENSE_VALID 0x10 24644358048SMagnus Damm #define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID) 24744358048SMagnus Damm 24844358048SMagnus Damm static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = { 24944358048SMagnus Damm [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00), 25044358048SMagnus Damm [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01), 25144358048SMagnus Damm [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02), 25244358048SMagnus Damm [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03), 25344358048SMagnus Damm [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04), 25444358048SMagnus Damm }; 25544358048SMagnus Damm 25644358048SMagnus Damm static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type) 25744358048SMagnus Damm { 25844358048SMagnus Damm unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK]; 25944358048SMagnus Damm struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 26044358048SMagnus Damm 26144358048SMagnus Damm if (!(value & INTC_IRQ_SENSE_VALID)) 26244358048SMagnus Damm return -EINVAL; 26344358048SMagnus Damm 26444358048SMagnus Damm return intc_irqpin_set_sense(p, irqd_to_hwirq(d), 26544358048SMagnus Damm value ^ INTC_IRQ_SENSE_VALID); 26644358048SMagnus Damm } 26744358048SMagnus Damm 268705bc96cSGeert Uytterhoeven static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on) 269705bc96cSGeert Uytterhoeven { 270705bc96cSGeert Uytterhoeven struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); 271f4e209cdSGeert Uytterhoeven int hw_irq = irqd_to_hwirq(d); 272f4e209cdSGeert Uytterhoeven 273f4e209cdSGeert Uytterhoeven irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); 274705bc96cSGeert Uytterhoeven if (on) 27566bf8252SGeert Uytterhoeven atomic_inc(&p->wakeup_path); 276705bc96cSGeert Uytterhoeven else 27766bf8252SGeert Uytterhoeven atomic_dec(&p->wakeup_path); 278705bc96cSGeert Uytterhoeven 279705bc96cSGeert Uytterhoeven return 0; 280705bc96cSGeert Uytterhoeven } 281705bc96cSGeert Uytterhoeven 28244358048SMagnus Damm static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id) 28344358048SMagnus Damm { 28444358048SMagnus Damm struct intc_irqpin_irq *i = dev_id; 28544358048SMagnus Damm struct intc_irqpin_priv *p = i->p; 28644358048SMagnus Damm unsigned long bit; 28744358048SMagnus Damm 28844358048SMagnus Damm intc_irqpin_dbg(i, "demux1"); 28944358048SMagnus Damm bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, i->hw_irq); 29044358048SMagnus Damm 29144358048SMagnus Damm if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) { 29244358048SMagnus Damm intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit); 29344358048SMagnus Damm intc_irqpin_dbg(i, "demux2"); 29433f958f2SMagnus Damm generic_handle_irq(i->domain_irq); 29544358048SMagnus Damm return IRQ_HANDLED; 29644358048SMagnus Damm } 29744358048SMagnus Damm return IRQ_NONE; 29844358048SMagnus Damm } 29944358048SMagnus Damm 300427cc720SBastian Hecht static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id) 301427cc720SBastian Hecht { 302427cc720SBastian Hecht struct intc_irqpin_priv *p = dev_id; 303427cc720SBastian Hecht unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE); 304427cc720SBastian Hecht irqreturn_t status = IRQ_NONE; 305427cc720SBastian Hecht int k; 306427cc720SBastian Hecht 307427cc720SBastian Hecht for (k = 0; k < 8; k++) { 308427cc720SBastian Hecht if (reg_source & BIT(7 - k)) { 309427cc720SBastian Hecht if (BIT(k) & p->shared_irq_mask) 310427cc720SBastian Hecht continue; 311427cc720SBastian Hecht 312427cc720SBastian Hecht status |= intc_irqpin_irq_handler(irq, &p->irq[k]); 313427cc720SBastian Hecht } 314427cc720SBastian Hecht } 315427cc720SBastian Hecht 316427cc720SBastian Hecht return status; 317427cc720SBastian Hecht } 318427cc720SBastian Hecht 319769b5cf7SGeert Uytterhoeven /* 320769b5cf7SGeert Uytterhoeven * This lock class tells lockdep that INTC External IRQ Pin irqs are in a 321769b5cf7SGeert Uytterhoeven * different category than their parents, so it won't report false recursion. 322769b5cf7SGeert Uytterhoeven */ 323769b5cf7SGeert Uytterhoeven static struct lock_class_key intc_irqpin_irq_lock_class; 324769b5cf7SGeert Uytterhoeven 32539c3fd58SAndrew Lunn /* And this is for the request mutex */ 32639c3fd58SAndrew Lunn static struct lock_class_key intc_irqpin_irq_request_class; 32739c3fd58SAndrew Lunn 32844358048SMagnus Damm static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, 32944358048SMagnus Damm irq_hw_number_t hw) 33044358048SMagnus Damm { 33144358048SMagnus Damm struct intc_irqpin_priv *p = h->host_data; 33244358048SMagnus Damm 33333f958f2SMagnus Damm p->irq[hw].domain_irq = virq; 33433f958f2SMagnus Damm p->irq[hw].hw_irq = hw; 33533f958f2SMagnus Damm 33644358048SMagnus Damm intc_irqpin_dbg(&p->irq[hw], "map"); 33744358048SMagnus Damm irq_set_chip_data(virq, h->host_data); 33839c3fd58SAndrew Lunn irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class, 33939c3fd58SAndrew Lunn &intc_irqpin_irq_request_class); 34044358048SMagnus Damm irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); 34144358048SMagnus Damm return 0; 34244358048SMagnus Damm } 34344358048SMagnus Damm 34496009736SKrzysztof Kozlowski static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { 34544358048SMagnus Damm .map = intc_irqpin_irq_domain_map, 3469d833bbeSMagnus Damm .xlate = irq_domain_xlate_twocell, 34744358048SMagnus Damm }; 34844358048SMagnus Damm 34986e57ca7SGeert Uytterhoeven static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = { 350e03f9088SMagnus Damm .irlm_bit = 23, /* ICR0.IRLM0 */ 35186e57ca7SGeert Uytterhoeven }; 35286e57ca7SGeert Uytterhoeven 35386e57ca7SGeert Uytterhoeven static const struct intc_irqpin_config intc_irqpin_rmobile = { 354b388bdf2SGeert Uytterhoeven .irlm_bit = -1, 355e03f9088SMagnus Damm }; 356e03f9088SMagnus Damm 357e03f9088SMagnus Damm static const struct of_device_id intc_irqpin_dt_ids[] = { 358e03f9088SMagnus Damm { .compatible = "renesas,intc-irqpin", }, 35926c21dd9SUlrich Hecht { .compatible = "renesas,intc-irqpin-r8a7778", 36026c21dd9SUlrich Hecht .data = &intc_irqpin_irlm_r8a777x }, 361e03f9088SMagnus Damm { .compatible = "renesas,intc-irqpin-r8a7779", 36226c21dd9SUlrich Hecht .data = &intc_irqpin_irlm_r8a777x }, 36386e57ca7SGeert Uytterhoeven { .compatible = "renesas,intc-irqpin-r8a7740", 36486e57ca7SGeert Uytterhoeven .data = &intc_irqpin_rmobile }, 36586e57ca7SGeert Uytterhoeven { .compatible = "renesas,intc-irqpin-sh73a0", 36686e57ca7SGeert Uytterhoeven .data = &intc_irqpin_rmobile }, 367e03f9088SMagnus Damm {}, 368e03f9088SMagnus Damm }; 369e03f9088SMagnus Damm MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids); 370e03f9088SMagnus Damm 37144358048SMagnus Damm static int intc_irqpin_probe(struct platform_device *pdev) 37244358048SMagnus Damm { 37342a5968cSGeert Uytterhoeven const struct intc_irqpin_config *config; 37436845f1bSGeert Uytterhoeven struct device *dev = &pdev->dev; 37544358048SMagnus Damm struct intc_irqpin_priv *p; 37644358048SMagnus Damm struct intc_irqpin_iomem *i; 37744358048SMagnus Damm struct resource *io[INTC_IRQPIN_REG_NR]; 37844358048SMagnus Damm struct irq_chip *irq_chip; 37944358048SMagnus Damm void (*enable_fn)(struct irq_data *d); 38044358048SMagnus Damm void (*disable_fn)(struct irq_data *d); 38136845f1bSGeert Uytterhoeven const char *name = dev_name(dev); 382f9551a9cSGeert Uytterhoeven bool control_parent; 3831affe594SGeert Uytterhoeven unsigned int nirqs; 384427cc720SBastian Hecht int ref_irq; 38544358048SMagnus Damm int ret; 38644358048SMagnus Damm int k; 38744358048SMagnus Damm 38836845f1bSGeert Uytterhoeven p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); 38989626d4bSGeert Uytterhoeven if (!p) 390705bc96cSGeert Uytterhoeven return -ENOMEM; 39144358048SMagnus Damm 39244358048SMagnus Damm /* deal with driver instance configuration */ 39336845f1bSGeert Uytterhoeven of_property_read_u32(dev->of_node, "sense-bitfield-width", 394f9551a9cSGeert Uytterhoeven &p->sense_bitfield_width); 395f9551a9cSGeert Uytterhoeven control_parent = of_property_read_bool(dev->of_node, "control-parent"); 396f9551a9cSGeert Uytterhoeven if (!p->sense_bitfield_width) 397f9551a9cSGeert Uytterhoeven p->sense_bitfield_width = 4; /* default to 4 bits */ 39844358048SMagnus Damm 39944358048SMagnus Damm p->pdev = pdev; 40044358048SMagnus Damm platform_set_drvdata(pdev, p); 40144358048SMagnus Damm 40242a5968cSGeert Uytterhoeven config = of_device_get_match_data(dev); 403705bc96cSGeert Uytterhoeven 404705bc96cSGeert Uytterhoeven pm_runtime_enable(dev); 405705bc96cSGeert Uytterhoeven pm_runtime_get_sync(dev); 406705bc96cSGeert Uytterhoeven 407e03f9088SMagnus Damm /* get hold of register banks */ 408e03f9088SMagnus Damm memset(io, 0, sizeof(io)); 40944358048SMagnus Damm for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { 41044358048SMagnus Damm io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k); 411e03f9088SMagnus Damm if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) { 41236845f1bSGeert Uytterhoeven dev_err(dev, "not enough IOMEM resources\n"); 41344358048SMagnus Damm ret = -EINVAL; 41408eba5baSMagnus Damm goto err0; 41544358048SMagnus Damm } 41644358048SMagnus Damm } 41744358048SMagnus Damm 41844358048SMagnus Damm /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */ 41944358048SMagnus Damm for (k = 0; k < INTC_IRQPIN_MAX; k++) { 420*31bd548fSLad Prabhakar ret = platform_get_irq_optional(pdev, k); 421*31bd548fSLad Prabhakar if (ret == -ENXIO) 42244358048SMagnus Damm break; 423*31bd548fSLad Prabhakar if (ret < 0) 424*31bd548fSLad Prabhakar goto err0; 42544358048SMagnus Damm 42644358048SMagnus Damm p->irq[k].p = p; 427*31bd548fSLad Prabhakar p->irq[k].requested_irq = ret; 42844358048SMagnus Damm } 42944358048SMagnus Damm 4301affe594SGeert Uytterhoeven nirqs = k; 4311affe594SGeert Uytterhoeven if (nirqs < 1) { 43236845f1bSGeert Uytterhoeven dev_err(dev, "not enough IRQ resources\n"); 43344358048SMagnus Damm ret = -EINVAL; 43408eba5baSMagnus Damm goto err0; 43544358048SMagnus Damm } 43644358048SMagnus Damm 43744358048SMagnus Damm /* ioremap IOMEM and setup read/write callbacks */ 43844358048SMagnus Damm for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { 43944358048SMagnus Damm i = &p->iomem[k]; 44044358048SMagnus Damm 441e03f9088SMagnus Damm /* handle optional registers */ 442e03f9088SMagnus Damm if (!io[k]) 443e03f9088SMagnus Damm continue; 444e03f9088SMagnus Damm 44544358048SMagnus Damm switch (resource_size(io[k])) { 44644358048SMagnus Damm case 1: 44744358048SMagnus Damm i->width = 8; 44844358048SMagnus Damm i->read = intc_irqpin_read8; 44944358048SMagnus Damm i->write = intc_irqpin_write8; 45044358048SMagnus Damm break; 45144358048SMagnus Damm case 4: 45244358048SMagnus Damm i->width = 32; 45344358048SMagnus Damm i->read = intc_irqpin_read32; 45444358048SMagnus Damm i->write = intc_irqpin_write32; 45544358048SMagnus Damm break; 45644358048SMagnus Damm default: 45736845f1bSGeert Uytterhoeven dev_err(dev, "IOMEM size mismatch\n"); 45844358048SMagnus Damm ret = -EINVAL; 45908eba5baSMagnus Damm goto err0; 46044358048SMagnus Damm } 46144358048SMagnus Damm 4624bdc0d67SChristoph Hellwig i->iomem = devm_ioremap(dev, io[k]->start, 46308eba5baSMagnus Damm resource_size(io[k])); 46444358048SMagnus Damm if (!i->iomem) { 46536845f1bSGeert Uytterhoeven dev_err(dev, "failed to remap IOMEM\n"); 46644358048SMagnus Damm ret = -ENXIO; 46708eba5baSMagnus Damm goto err0; 46844358048SMagnus Damm } 46944358048SMagnus Damm } 47044358048SMagnus Damm 471e03f9088SMagnus Damm /* configure "individual IRQ mode" where needed */ 472b388bdf2SGeert Uytterhoeven if (config && config->irlm_bit >= 0) { 473e03f9088SMagnus Damm if (io[INTC_IRQPIN_REG_IRLM]) 474e03f9088SMagnus Damm intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM, 47586e57ca7SGeert Uytterhoeven config->irlm_bit, 1, 1); 476e03f9088SMagnus Damm else 477e03f9088SMagnus Damm dev_warn(dev, "unable to select IRLM mode\n"); 478e03f9088SMagnus Damm } 479e03f9088SMagnus Damm 48044358048SMagnus Damm /* mask all interrupts using priority */ 4811affe594SGeert Uytterhoeven for (k = 0; k < nirqs; k++) 48244358048SMagnus Damm intc_irqpin_mask_unmask_prio(p, k, 1); 48344358048SMagnus Damm 484427cc720SBastian Hecht /* clear all pending interrupts */ 485427cc720SBastian Hecht intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, 0x0); 486427cc720SBastian Hecht 487427cc720SBastian Hecht /* scan for shared interrupt lines */ 488427cc720SBastian Hecht ref_irq = p->irq[0].requested_irq; 48986e57ca7SGeert Uytterhoeven p->shared_irqs = 1; 4901affe594SGeert Uytterhoeven for (k = 1; k < nirqs; k++) { 491427cc720SBastian Hecht if (ref_irq != p->irq[k].requested_irq) { 49286e57ca7SGeert Uytterhoeven p->shared_irqs = 0; 493427cc720SBastian Hecht break; 494427cc720SBastian Hecht } 495427cc720SBastian Hecht } 496427cc720SBastian Hecht 49744358048SMagnus Damm /* use more severe masking method if requested */ 498f9551a9cSGeert Uytterhoeven if (control_parent) { 49944358048SMagnus Damm enable_fn = intc_irqpin_irq_enable_force; 50044358048SMagnus Damm disable_fn = intc_irqpin_irq_disable_force; 501427cc720SBastian Hecht } else if (!p->shared_irqs) { 50244358048SMagnus Damm enable_fn = intc_irqpin_irq_enable; 50344358048SMagnus Damm disable_fn = intc_irqpin_irq_disable; 504427cc720SBastian Hecht } else { 505427cc720SBastian Hecht enable_fn = intc_irqpin_shared_irq_enable; 506427cc720SBastian Hecht disable_fn = intc_irqpin_shared_irq_disable; 50744358048SMagnus Damm } 50844358048SMagnus Damm 50944358048SMagnus Damm irq_chip = &p->irq_chip; 510ec93b94aSGeert Uytterhoeven irq_chip->name = "intc-irqpin"; 511ec93b94aSGeert Uytterhoeven irq_chip->parent_device = dev; 51244358048SMagnus Damm irq_chip->irq_mask = disable_fn; 51344358048SMagnus Damm irq_chip->irq_unmask = enable_fn; 51444358048SMagnus Damm irq_chip->irq_set_type = intc_irqpin_irq_set_type; 515705bc96cSGeert Uytterhoeven irq_chip->irq_set_wake = intc_irqpin_irq_set_wake; 516705bc96cSGeert Uytterhoeven irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; 51744358048SMagnus Damm 5181affe594SGeert Uytterhoeven p->irq_domain = irq_domain_add_simple(dev->of_node, nirqs, 0, 5191affe594SGeert Uytterhoeven &intc_irqpin_irq_domain_ops, p); 52044358048SMagnus Damm if (!p->irq_domain) { 52144358048SMagnus Damm ret = -ENXIO; 52236845f1bSGeert Uytterhoeven dev_err(dev, "cannot initialize irq domain\n"); 52308eba5baSMagnus Damm goto err0; 52444358048SMagnus Damm } 52544358048SMagnus Damm 526427cc720SBastian Hecht if (p->shared_irqs) { 527427cc720SBastian Hecht /* request one shared interrupt */ 52836845f1bSGeert Uytterhoeven if (devm_request_irq(dev, p->irq[0].requested_irq, 529427cc720SBastian Hecht intc_irqpin_shared_irq_handler, 530427cc720SBastian Hecht IRQF_SHARED, name, p)) { 53136845f1bSGeert Uytterhoeven dev_err(dev, "failed to request low IRQ\n"); 53244358048SMagnus Damm ret = -ENOENT; 53308eba5baSMagnus Damm goto err1; 53444358048SMagnus Damm } 535427cc720SBastian Hecht } else { 536427cc720SBastian Hecht /* request interrupts one by one */ 5371affe594SGeert Uytterhoeven for (k = 0; k < nirqs; k++) { 53836845f1bSGeert Uytterhoeven if (devm_request_irq(dev, p->irq[k].requested_irq, 53936845f1bSGeert Uytterhoeven intc_irqpin_irq_handler, 0, name, 54036845f1bSGeert Uytterhoeven &p->irq[k])) { 54136845f1bSGeert Uytterhoeven dev_err(dev, "failed to request low IRQ\n"); 542427cc720SBastian Hecht ret = -ENOENT; 543427cc720SBastian Hecht goto err1; 54444358048SMagnus Damm } 545427cc720SBastian Hecht } 546427cc720SBastian Hecht } 547427cc720SBastian Hecht 548427cc720SBastian Hecht /* unmask all interrupts on prio level */ 5491affe594SGeert Uytterhoeven for (k = 0; k < nirqs; k++) 550427cc720SBastian Hecht intc_irqpin_mask_unmask_prio(p, k, 0); 55144358048SMagnus Damm 5521affe594SGeert Uytterhoeven dev_info(dev, "driving %d irqs\n", nirqs); 55344358048SMagnus Damm 55444358048SMagnus Damm return 0; 55544358048SMagnus Damm 55644358048SMagnus Damm err1: 55708eba5baSMagnus Damm irq_domain_remove(p->irq_domain); 55844358048SMagnus Damm err0: 559705bc96cSGeert Uytterhoeven pm_runtime_put(dev); 560705bc96cSGeert Uytterhoeven pm_runtime_disable(dev); 56144358048SMagnus Damm return ret; 56244358048SMagnus Damm } 56344358048SMagnus Damm 56444358048SMagnus Damm static int intc_irqpin_remove(struct platform_device *pdev) 56544358048SMagnus Damm { 56644358048SMagnus Damm struct intc_irqpin_priv *p = platform_get_drvdata(pdev); 56744358048SMagnus Damm 56844358048SMagnus Damm irq_domain_remove(p->irq_domain); 569705bc96cSGeert Uytterhoeven pm_runtime_put(&pdev->dev); 570705bc96cSGeert Uytterhoeven pm_runtime_disable(&pdev->dev); 57144358048SMagnus Damm return 0; 57244358048SMagnus Damm } 57344358048SMagnus Damm 57466bf8252SGeert Uytterhoeven static int __maybe_unused intc_irqpin_suspend(struct device *dev) 57566bf8252SGeert Uytterhoeven { 57666bf8252SGeert Uytterhoeven struct intc_irqpin_priv *p = dev_get_drvdata(dev); 57766bf8252SGeert Uytterhoeven 57866bf8252SGeert Uytterhoeven if (atomic_read(&p->wakeup_path)) 57966bf8252SGeert Uytterhoeven device_set_wakeup_path(dev); 58066bf8252SGeert Uytterhoeven 58166bf8252SGeert Uytterhoeven return 0; 58266bf8252SGeert Uytterhoeven } 58366bf8252SGeert Uytterhoeven 58466bf8252SGeert Uytterhoeven static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); 58566bf8252SGeert Uytterhoeven 58644358048SMagnus Damm static struct platform_driver intc_irqpin_device_driver = { 58744358048SMagnus Damm .probe = intc_irqpin_probe, 58844358048SMagnus Damm .remove = intc_irqpin_remove, 58944358048SMagnus Damm .driver = { 59044358048SMagnus Damm .name = "renesas_intc_irqpin", 5919d833bbeSMagnus Damm .of_match_table = intc_irqpin_dt_ids, 59266bf8252SGeert Uytterhoeven .pm = &intc_irqpin_pm_ops, 59344358048SMagnus Damm } 59444358048SMagnus Damm }; 59544358048SMagnus Damm 59644358048SMagnus Damm static int __init intc_irqpin_init(void) 59744358048SMagnus Damm { 59844358048SMagnus Damm return platform_driver_register(&intc_irqpin_device_driver); 59944358048SMagnus Damm } 60044358048SMagnus Damm postcore_initcall(intc_irqpin_init); 60144358048SMagnus Damm 60244358048SMagnus Damm static void __exit intc_irqpin_exit(void) 60344358048SMagnus Damm { 60444358048SMagnus Damm platform_driver_unregister(&intc_irqpin_device_driver); 60544358048SMagnus Damm } 60644358048SMagnus Damm module_exit(intc_irqpin_exit); 60744358048SMagnus Damm 60844358048SMagnus Damm MODULE_AUTHOR("Magnus Damm"); 60944358048SMagnus Damm MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver"); 61044358048SMagnus Damm MODULE_LICENSE("GPL v2"); 611