summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt8
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt32
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c85
4 files changed, 96 insertions, 30 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
index 1f8b0c507c26..c73acd060093 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
@@ -2,7 +2,13 @@ DT bindings for the R-/SH-Mobile irqpin controller
Required properties:
-- compatible: has to be "renesas,intc-irqpin"
+- compatible: has to be "renesas,intc-irqpin-<soctype>", "renesas,intc-irqpin"
+ as fallback.
+ Examples with soctypes are:
+ - "renesas,intc-irqpin-r8a7740" (R-Mobile A1)
+ - "renesas,intc-irqpin-r8a7778" (R-Car M1A)
+ - "renesas,intc-irqpin-r8a7779" (R-Car H1)
+ - "renesas,intc-irqpin-sh73a0" (SH-Mobile AG5)
- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
interrupts.txt in this directory
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
new file mode 100644
index 000000000000..1a88e62228e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
@@ -0,0 +1,32 @@
+DT bindings for the R-Mobile/R-Car interrupt controller
+
+Required properties:
+
+- compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback.
+ Examples with soctypes are:
+ - "renesas,irqc-r8a73a4" (R-Mobile AP6)
+ - "renesas,irqc-r8a7790" (R-Car H2)
+ - "renesas,irqc-r8a7791" (R-Car M2-W)
+ - "renesas,irqc-r8a7792" (R-Car V2H)
+ - "renesas,irqc-r8a7793" (R-Car M2-N)
+ - "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
+
+Optional properties:
+
+- any properties, listed in interrupts.txt, and any standard resource allocation
+ properties
+
+Example:
+
+ irqc0: interrupt-controller@e61c0000 {
+ compatible = "renesas,irqc-r8a7790", "renesas,irqc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0 0xe61c0000 0 0x200>;
+ interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>,
+ <0 1 IRQ_TYPE_LEVEL_HIGH>,
+ <0 2 IRQ_TYPE_LEVEL_HIGH>,
+ <0 3 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index aefa94841ff3..71e86afa6820 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4948,6 +4948,7 @@ L: linux-kernel@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
T: git git://git.infradead.org/users/jcooper/linux.git irqchip/core
+F: Documentation/devicetree/bindings/interrupt-controller/
F: drivers/irqchip/
IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 3ee78f02e5d7..542e850f4946 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/clk.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -30,6 +31,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_data/irq-renesas-intc-irqpin.h>
+#include <linux/pm_runtime.h>
#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
@@ -75,6 +77,7 @@ struct intc_irqpin_priv {
struct platform_device *pdev;
struct irq_chip irq_chip;
struct irq_domain *irq_domain;
+ struct clk *clk;
bool shared_irqs;
u8 shared_irq_mask;
};
@@ -270,6 +273,21 @@ static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type)
value ^ INTC_IRQ_SENSE_VALID);
}
+static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct intc_irqpin_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 intc_irqpin_irq_handler(int irq, void *dev_id)
{
struct intc_irqpin_irq *i = dev_id;
@@ -329,7 +347,8 @@ static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
static int intc_irqpin_probe(struct platform_device *pdev)
{
- struct renesas_intc_irqpin_config *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct renesas_intc_irqpin_config *pdata = dev->platform_data;
struct intc_irqpin_priv *p;
struct intc_irqpin_iomem *i;
struct resource *io[INTC_IRQPIN_REG_NR];
@@ -337,25 +356,24 @@ static int intc_irqpin_probe(struct platform_device *pdev)
struct irq_chip *irq_chip;
void (*enable_fn)(struct irq_data *d);
void (*disable_fn)(struct irq_data *d);
- const char *name = dev_name(&pdev->dev);
+ const char *name = dev_name(dev);
int ref_irq;
int ret;
int k;
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
- ret = -ENOMEM;
- goto err0;
+ dev_err(dev, "failed to allocate driver data\n");
+ return -ENOMEM;
}
/* deal with driver instance configuration */
if (pdata) {
memcpy(&p->config, pdata, sizeof(*pdata));
} else {
- of_property_read_u32(pdev->dev.of_node, "sense-bitfield-width",
+ of_property_read_u32(dev->of_node, "sense-bitfield-width",
&p->config.sense_bitfield_width);
- p->config.control_parent = of_property_read_bool(pdev->dev.of_node,
+ p->config.control_parent = of_property_read_bool(dev->of_node,
"control-parent");
}
if (!p->config.sense_bitfield_width)
@@ -364,11 +382,20 @@ static int intc_irqpin_probe(struct platform_device *pdev)
p->pdev = pdev;
platform_set_drvdata(pdev, p);
+ p->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(p->clk)) {
+ dev_warn(dev, "unable to get clock\n");
+ p->clk = NULL;
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
/* get hold of manadatory IOMEM */
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
if (!io[k]) {
- dev_err(&pdev->dev, "not enough IOMEM resources\n");
+ dev_err(dev, "not enough IOMEM resources\n");
ret = -EINVAL;
goto err0;
}
@@ -386,7 +413,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
p->number_of_irqs = k;
if (p->number_of_irqs < 1) {
- dev_err(&pdev->dev, "not enough IRQ resources\n");
+ dev_err(dev, "not enough IRQ resources\n");
ret = -EINVAL;
goto err0;
}
@@ -407,15 +434,15 @@ static int intc_irqpin_probe(struct platform_device *pdev)
i->write = intc_irqpin_write32;
break;
default:
- dev_err(&pdev->dev, "IOMEM size mismatch\n");
+ dev_err(dev, "IOMEM size mismatch\n");
ret = -EINVAL;
goto err0;
}
- i->iomem = devm_ioremap_nocache(&pdev->dev, io[k]->start,
+ i->iomem = devm_ioremap_nocache(dev, io[k]->start,
resource_size(io[k]));
if (!i->iomem) {
- dev_err(&pdev->dev, "failed to remap IOMEM\n");
+ dev_err(dev, "failed to remap IOMEM\n");
ret = -ENXIO;
goto err0;
}
@@ -454,39 +481,36 @@ static int intc_irqpin_probe(struct platform_device *pdev)
irq_chip->name = name;
irq_chip->irq_mask = disable_fn;
irq_chip->irq_unmask = enable_fn;
- irq_chip->irq_enable = enable_fn;
- irq_chip->irq_disable = disable_fn;
irq_chip->irq_set_type = intc_irqpin_irq_set_type;
- irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+ irq_chip->irq_set_wake = intc_irqpin_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(dev->of_node,
p->number_of_irqs,
p->config.irq_base,
&intc_irqpin_irq_domain_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
- dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ dev_err(dev, "cannot initialize irq domain\n");
goto err0;
}
if (p->shared_irqs) {
/* request one shared interrupt */
- if (devm_request_irq(&pdev->dev, p->irq[0].requested_irq,
+ if (devm_request_irq(dev, p->irq[0].requested_irq,
intc_irqpin_shared_irq_handler,
IRQF_SHARED, name, p)) {
- dev_err(&pdev->dev, "failed to request low IRQ\n");
+ dev_err(dev, "failed to request low IRQ\n");
ret = -ENOENT;
goto err1;
}
} else {
/* request interrupts one by one */
for (k = 0; k < p->number_of_irqs; k++) {
- if (devm_request_irq(&pdev->dev,
- p->irq[k].requested_irq,
- intc_irqpin_irq_handler,
- 0, name, &p->irq[k])) {
- dev_err(&pdev->dev,
- "failed to request low IRQ\n");
+ if (devm_request_irq(dev, p->irq[k].requested_irq,
+ intc_irqpin_irq_handler, 0, name,
+ &p->irq[k])) {
+ dev_err(dev, "failed to request low IRQ\n");
ret = -ENOENT;
goto err1;
}
@@ -497,12 +521,12 @@ static int intc_irqpin_probe(struct platform_device *pdev)
for (k = 0; k < p->number_of_irqs; k++)
intc_irqpin_mask_unmask_prio(p, k, 0);
- dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
+ dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
/* warn in case of mismatch if irq base is specified */
if (p->config.irq_base) {
if (p->config.irq_base != p->irq[0].domain_irq)
- dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
+ dev_warn(dev, "irq base mismatch (%d/%d)\n",
p->config.irq_base, p->irq[0].domain_irq);
}
@@ -511,6 +535,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
err1:
irq_domain_remove(p->irq_domain);
err0:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
return ret;
}
@@ -519,7 +545,8 @@ static int intc_irqpin_remove(struct platform_device *pdev)
struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
irq_domain_remove(p->irq_domain);
-
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}