diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index 1a88e62228e5..63633bdea7e4 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt @@ -4,7 +4,7 @@ Required properties: - compatible: has to be "renesas,irqc-", "renesas,irqc" as fallback. Examples with soctypes are: - - "renesas,irqc-r8a73a4" (R-Mobile AP6) + - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7792" (R-Car V2H) @@ -12,6 +12,7 @@ Required properties: - "renesas,irqc-r8a7794" (R-Car E2) - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in interrupts.txt in this directory +- clocks: Must contain a reference to the functional clock. Optional properties: @@ -29,4 +30,5 @@ Example: <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp4_clks R8A7790_CLK_IRQC>; }; diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 2ea3412fdf8c..cdf80b7794cd 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -29,15 +30,26 @@ #include #include #include +#include -#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ +#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ -#define IRQC_REQ_STS 0x00 -#define IRQC_EN_STS 0x04 -#define IRQC_EN_SET 0x08 +#define IRQC_REQ_STS 0x00 /* Interrupt Request Status Register */ +#define IRQC_EN_STS 0x04 /* Interrupt Enable Status Register */ +#define IRQC_EN_SET 0x08 /* Interrupt Enable Set Register */ #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) -#define DETECT_STATUS 0x100 + /* SYS-CPU vs. RT-CPU */ +#define DETECT_STATUS 0x100 /* IRQn Detect Status Register */ +#define MONITOR 0x104 /* IRQn Signal Level Monitor Register */ +#define HLVL_STS 0x108 /* IRQn High Level Detect Status Register */ +#define LLVL_STS 0x10c /* IRQn Low Level Detect Status Register */ +#define S_R_EDGE_STS 0x110 /* IRQn Sync Rising Edge Detect Status Reg. */ +#define S_F_EDGE_STS 0x114 /* IRQn Sync Falling Edge Detect Status Reg. */ +#define A_R_EDGE_STS 0x118 /* IRQn Async Rising Edge Detect Status Reg. */ +#define A_F_EDGE_STS 0x11c /* IRQn Async Falling Edge Detect Status Reg. */ +#define CHTEN_STS 0x120 /* Chattering Reduction Status Register */ #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) + /* IRQn Configuration Register */ struct irqc_irq { int hw_irq; @@ -55,6 +67,7 @@ struct irqc_priv { struct platform_device *pdev; struct irq_chip irq_chip; struct irq_domain *irq_domain; + struct clk *clk; }; static void irqc_dbg(struct irqc_irq *i, char *str) @@ -108,6 +121,21 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static int irqc_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct irqc_priv *p = irq_data_get_irq_chip_data(d); + + if (!p->clk) + return 0; + + if (on) + clk_enable(p->clk); + else + clk_disable(p->clk); + + return 0; +} + static irqreturn_t irqc_irq_handler(int irq, void *dev_id) { struct irqc_irq *i = dev_id; @@ -170,6 +198,15 @@ static int irqc_probe(struct platform_device *pdev) p->pdev = pdev; platform_set_drvdata(pdev, p); + p->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(p->clk)) { + dev_warn(&pdev->dev, "unable to get clock\n"); + p->clk = NULL; + } + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + /* get hold of manadatory IOMEM */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) { @@ -210,7 +247,8 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->irq_mask = irqc_irq_disable; irq_chip->irq_unmask = irqc_irq_enable; irq_chip->irq_set_type = irqc_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; + irq_chip->irq_set_wake = irqc_irq_set_wake; + irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->number_of_irqs, @@ -250,6 +288,8 @@ err3: err2: iounmap(p->iomem); err1: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); kfree(p); err0: return ret; @@ -265,6 +305,8 @@ static int irqc_remove(struct platform_device *pdev) irq_domain_remove(p->irq_domain); iounmap(p->iomem); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); kfree(p); return 0; }