OSDN Git Service

irqchip: Add SuperH IPR driver.
authorYoshinori Sato <ysato@users.sourceforge.jp>
Thu, 14 Apr 2016 07:46:47 +0000 (16:46 +0900)
committerYoshinori Sato <ysato@users.sourceforge.jp>
Thu, 14 Apr 2016 08:05:32 +0000 (17:05 +0900)
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-io-landisk.c [new file with mode: 0644]
drivers/irqchip/irq-renesas-shipr.c [new file with mode: 0644]

index 3e12479..abfaa06 100644 (file)
@@ -244,3 +244,8 @@ config IRQ_MXS
 config MVEBU_ODMI
        bool
        select GENERIC_MSI_IRQ_DOMAIN
+
+config RENESAS_SH_INTC
+       bool
+       select IRQ_DOMAIN
+       select IRQ_DOMAIN_HIERARCHY
index b03cfcb..3f9fc5c 100644 (file)
@@ -65,3 +65,4 @@ obj-$(CONFIG_INGENIC_IRQ)             += irq-ingenic.o
 obj-$(CONFIG_IMX_GPCV2)                        += irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)               += irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_ODMI)               += irq-mvebu-odmi.o
+obj-$(CONFIG_RENESAS_SH_INTC)          += irq-renesas-shipr.o irq-io-landisk.o
diff --git a/drivers/irqchip/irq-io-landisk.c b/drivers/irqchip/irq-io-landisk.c
new file mode 100644 (file)
index 0000000..67cb848
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * IO-DATA LANDISK CPLD IRQ driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/io.h>
+
+static void landisk_mask_irq(struct irq_data *data)
+{
+       u8 mask = __raw_readb(data->chip_data + 5);
+       mask &= !(1 << (8 - data->irq - 1));
+       __raw_writeb(mask, data->chip_data + 5);
+}
+
+static void landisk_unmask_irq(struct irq_data *data)
+{
+       u8 mask = __raw_readb(data->chip_data + 5);
+       mask |= (1 << (8 - data->irq - 1));
+       __raw_writeb(mask, data->chip_data + 5);
+}
+
+static struct irq_chip cpld_irq_chip = {
+       .name           = "LANDISK-CPLD",
+       .irq_unmask     = landisk_unmask_irq,
+       .irq_mask       = landisk_mask_irq,
+};
+
+static int cpld_map(struct irq_domain *d, unsigned int virq,
+                   irq_hw_number_t hw_irq_num)
+{
+       irq_set_chip_and_handler(virq, &cpld_irq_chip,
+                                handle_simple_irq);
+       irq_set_chip_data(virq, d->host_data);
+
+       return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+       .xlate  = irq_domain_xlate_twocell,
+       .map    = cpld_map,
+};
+
+static int __init landisk_intc_of_init(struct device_node *intc,
+                                   struct device_node *parent)
+{
+       struct irq_domain *domain, *pdomain;
+       int num_irqpin;
+       void *baseaddr;
+
+       baseaddr = of_iomap(intc, 0);
+       pdomain = irq_find_host(parent);
+       of_get_property(intc, "interrupt-map", &num_irqpin);
+       num_irqpin /= sizeof(u32) * 3;
+       domain = irq_domain_create_hierarchy(pdomain, 0, num_irqpin,
+                                            of_node_to_fwnode(intc),
+                                            &irq_ops, baseaddr);
+       BUG_ON(!domain);
+       irq_domain_associate_many(domain, 0, 0, 8);
+       return 0;
+}
+
+IRQCHIP_DECLARE(cpld_intc, "iodata,landisk-intc", landisk_intc_of_init);
diff --git a/drivers/irqchip/irq-renesas-shipr.c b/drivers/irqchip/irq-renesas-shipr.c
new file mode 100644 (file)
index 0000000..0772895
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * SH IPR-INTC interrupt contoller driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <asm/io.h>
+
+static struct sh7751_intc_regs {
+       u32 *icr;
+       u32 *ipr;
+       u32 *intpri00;
+       u32 *intreq00;
+       u32 *intmsk00;
+       u32 *intmskclr00;
+} sh7751_regs;
+       
+static const unsigned int ipr_table[] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */
+       0x41, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 8 - 15 */
+       0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x11, /* 16 - 23 */
+       0x11, 0x11, 0x11, 0x13, 0x12, 0x12, 0xff, 0xff, /* 24 - 31 */
+       0x30, 0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x21, /* 32 - 39 */
+       0x21, 0x21, 0x21, 0x21, 0x32, 0x32, 0x32, 0x32, /* 40 - 47 */
+       0xff, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 48 - 55 */
+       0xff, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 56 - 63 */
+};
+
+static const unsigned int pri_table[] = {
+       0, 4, 4, 4, 4, 4, 4, 4,
+       8, 32, 32, 32, 12, 32, 32, 32,
+};
+
+static void sh_disable_irq(struct irq_data *data)
+{
+       int pos;
+       unsigned int addr;
+       unsigned long pri;
+       int irq = data->irq;
+       struct sh7751_intc_regs *reg = data->chip_data;
+
+       if (irq < 64) {
+               if (ipr_table[irq] != 0xff) {
+                       addr = ipr_table[irq] & 0xf0 >> 2;
+                       pos = ipr_table[irq] & 0x0f << 4;
+                       pri = ~(0x000f << pos);
+                       pri &= __raw_readw(reg->ipr + addr);
+                       __raw_writew(pri, reg->ipr + addr);
+               }
+       } else {
+               if (pri_table[irq - 64] < 32) {
+                       pos = pri_table[irq - 64];
+                       pri = ~(0x000f << pos);
+                       pri &= __raw_readw(reg->intpri00);
+                       __raw_writew(pri, reg->intpri00);
+               }
+       }
+}
+
+static void sh_enable_irq(struct irq_data *data)
+{
+       int pos;
+       unsigned int addr;
+       unsigned long pri;
+       int irq = data->irq;
+       struct sh7751_intc_regs *reg = data->chip_data;
+
+       if (irq < 64) {
+               if (ipr_table[irq] != 0xff) {
+                       addr = (ipr_table[irq] & 0xf0) >> 2;
+                       pos = (ipr_table[irq] & 0x0f) * 4;
+                       pri = ~(0x000f << pos);
+                       pri &= __raw_readw(reg->ipr + addr);
+                       pri |= 1 << pos;
+                       __raw_writew(pri, reg->ipr + addr);
+               }
+       } else {
+               if (pri_table[irq - 64] < 32) {
+                       pos = pri_table[irq - 64];
+                       pri = ~(0x000f << pos);
+                       pri &= __raw_readw(reg->intpri00);
+                       pri |= 1 << pos;
+                       __raw_writew(pri, reg->intpri00);
+               }
+       }
+}
+
+struct irq_chip sh_irq_chip = {
+       .name           = "SH-IPR",
+       .irq_enable     = sh_enable_irq,
+       .irq_disable    = sh_disable_irq,
+};
+
+static __init int irq_map(struct irq_domain *h, unsigned int virq,
+                         irq_hw_number_t hw_irq_num)
+{
+       irq_set_chip_and_handler(virq, &sh_irq_chip, handle_simple_irq);
+       irq_get_irq_data(virq)->chip_data = h->host_data;
+
+       return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+       .map    = irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static int __init sh_intc_of_init(struct device_node *intc,
+                                 struct device_node *parent)
+{
+       struct irq_domain *domain;
+       void *intc_baseaddr;
+       void *intc_baseaddr2;
+
+       intc_baseaddr = of_iomap(intc, 0);
+       intc_baseaddr2 = of_iomap(intc, 1);
+       BUG_ON(!intc_baseaddr);
+
+       sh7751_regs.icr = intc_baseaddr;
+       sh7751_regs.ipr = intc_baseaddr + 4;
+       sh7751_regs.intpri00 = intc_baseaddr2;
+       sh7751_regs.intreq00 = intc_baseaddr2 + 0x20;
+       sh7751_regs.intmsk00 = intc_baseaddr2 + 0x40;
+       sh7751_regs.intmskclr00 = intc_baseaddr2 + 0x60;
+
+       domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, &sh7751_regs);
+       BUG_ON(!domain);
+       irq_set_default_host(domain);
+       return 0;
+}
+
+IRQCHIP_DECLARE(sh_7751_intc, "renesas,sh7751-intc", sh_intc_of_init);