Loading Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +3 −1 Original line number Original line Diff line number Diff line Loading @@ -4,7 +4,7 @@ Required properties: - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. Examples with soctypes are: Examples with soctypes are: - "renesas,irqc-r8a73a4" (R-Mobile AP6) - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7792" (R-Car V2H) - "renesas,irqc-r8a7792" (R-Car V2H) Loading @@ -12,6 +12,7 @@ Required properties: - "renesas,irqc-r8a7794" (R-Car E2) - "renesas,irqc-r8a7794" (R-Car E2) - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in interrupts.txt in this directory interrupts.txt in this directory - clocks: Must contain a reference to the functional clock. Optional properties: Optional properties: Loading @@ -29,4 +30,5 @@ Example: <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 3 IRQ_TYPE_LEVEL_HIGH>; <0 3 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp4_clks R8A7790_CLK_IRQC>; }; }; drivers/irqchip/irq-renesas-irqc.c +48 −6 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ */ #include <linux/clk.h> #include <linux/init.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/spinlock.h> Loading @@ -29,15 +30,26 @@ #include <linux/slab.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/module.h> #include <linux/platform_data/irq-renesas-irqc.h> #include <linux/platform_data/irq-renesas-irqc.h> #include <linux/pm_runtime.h> #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_REQ_STS 0x00 /* Interrupt Request Status Register */ #define IRQC_EN_STS 0x04 #define IRQC_EN_STS 0x04 /* Interrupt Enable Status Register */ #define IRQC_EN_SET 0x08 #define IRQC_EN_SET 0x08 /* Interrupt Enable Set Register */ #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) #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)) #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) /* IRQn Configuration Register */ struct irqc_irq { struct irqc_irq { int hw_irq; int hw_irq; Loading @@ -55,6 +67,7 @@ struct irqc_priv { struct platform_device *pdev; struct platform_device *pdev; struct irq_chip irq_chip; struct irq_chip irq_chip; struct irq_domain *irq_domain; struct irq_domain *irq_domain; struct clk *clk; }; }; static void irqc_dbg(struct irqc_irq *i, char *str) static void irqc_dbg(struct irqc_irq *i, char *str) Loading Loading @@ -108,6 +121,21 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) return 0; 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) static irqreturn_t irqc_irq_handler(int irq, void *dev_id) { { struct irqc_irq *i = dev_id; struct irqc_irq *i = dev_id; Loading Loading @@ -170,6 +198,15 @@ static int irqc_probe(struct platform_device *pdev) p->pdev = pdev; p->pdev = pdev; platform_set_drvdata(pdev, p); 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 */ /* get hold of manadatory IOMEM */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) { if (!io) { Loading Loading @@ -210,7 +247,8 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->irq_mask = irqc_irq_disable; irq_chip->irq_mask = irqc_irq_disable; irq_chip->irq_unmask = irqc_irq_enable; irq_chip->irq_unmask = irqc_irq_enable; irq_chip->irq_set_type = irqc_irq_set_type; 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->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->number_of_irqs, p->number_of_irqs, Loading Loading @@ -250,6 +288,8 @@ static int irqc_probe(struct platform_device *pdev) err2: err2: iounmap(p->iomem); iounmap(p->iomem); err1: err1: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); kfree(p); kfree(p); err0: err0: return ret; return ret; Loading @@ -265,6 +305,8 @@ static int irqc_remove(struct platform_device *pdev) irq_domain_remove(p->irq_domain); irq_domain_remove(p->irq_domain); iounmap(p->iomem); iounmap(p->iomem); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); kfree(p); kfree(p); return 0; return 0; } } Loading Loading
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +3 −1 Original line number Original line Diff line number Diff line Loading @@ -4,7 +4,7 @@ Required properties: - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. Examples with soctypes are: Examples with soctypes are: - "renesas,irqc-r8a73a4" (R-Mobile AP6) - "renesas,irqc-r8a73a4" (R-Mobile APE6) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7790" (R-Car H2) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7791" (R-Car M2-W) - "renesas,irqc-r8a7792" (R-Car V2H) - "renesas,irqc-r8a7792" (R-Car V2H) Loading @@ -12,6 +12,7 @@ Required properties: - "renesas,irqc-r8a7794" (R-Car E2) - "renesas,irqc-r8a7794" (R-Car E2) - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in interrupts.txt in this directory interrupts.txt in this directory - clocks: Must contain a reference to the functional clock. Optional properties: Optional properties: Loading @@ -29,4 +30,5 @@ Example: <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 1 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 2 IRQ_TYPE_LEVEL_HIGH>, <0 3 IRQ_TYPE_LEVEL_HIGH>; <0 3 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp4_clks R8A7790_CLK_IRQC>; }; };
drivers/irqchip/irq-renesas-irqc.c +48 −6 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ */ #include <linux/clk.h> #include <linux/init.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/spinlock.h> Loading @@ -29,15 +30,26 @@ #include <linux/slab.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/module.h> #include <linux/platform_data/irq-renesas-irqc.h> #include <linux/platform_data/irq-renesas-irqc.h> #include <linux/pm_runtime.h> #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_REQ_STS 0x00 /* Interrupt Request Status Register */ #define IRQC_EN_STS 0x04 #define IRQC_EN_STS 0x04 /* Interrupt Enable Status Register */ #define IRQC_EN_SET 0x08 #define IRQC_EN_SET 0x08 /* Interrupt Enable Set Register */ #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) #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)) #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) /* IRQn Configuration Register */ struct irqc_irq { struct irqc_irq { int hw_irq; int hw_irq; Loading @@ -55,6 +67,7 @@ struct irqc_priv { struct platform_device *pdev; struct platform_device *pdev; struct irq_chip irq_chip; struct irq_chip irq_chip; struct irq_domain *irq_domain; struct irq_domain *irq_domain; struct clk *clk; }; }; static void irqc_dbg(struct irqc_irq *i, char *str) static void irqc_dbg(struct irqc_irq *i, char *str) Loading Loading @@ -108,6 +121,21 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) return 0; 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) static irqreturn_t irqc_irq_handler(int irq, void *dev_id) { { struct irqc_irq *i = dev_id; struct irqc_irq *i = dev_id; Loading Loading @@ -170,6 +198,15 @@ static int irqc_probe(struct platform_device *pdev) p->pdev = pdev; p->pdev = pdev; platform_set_drvdata(pdev, p); 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 */ /* get hold of manadatory IOMEM */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) { if (!io) { Loading Loading @@ -210,7 +247,8 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->irq_mask = irqc_irq_disable; irq_chip->irq_mask = irqc_irq_disable; irq_chip->irq_unmask = irqc_irq_enable; irq_chip->irq_unmask = irqc_irq_enable; irq_chip->irq_set_type = irqc_irq_set_type; 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->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->number_of_irqs, p->number_of_irqs, Loading Loading @@ -250,6 +288,8 @@ static int irqc_probe(struct platform_device *pdev) err2: err2: iounmap(p->iomem); iounmap(p->iomem); err1: err1: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); kfree(p); kfree(p); err0: err0: return ret; return ret; Loading @@ -265,6 +305,8 @@ static int irqc_remove(struct platform_device *pdev) irq_domain_remove(p->irq_domain); irq_domain_remove(p->irq_domain); iounmap(p->iomem); iounmap(p->iomem); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); kfree(p); kfree(p); return 0; return 0; } } Loading