diff --git a/hw/nseries.c b/hw/nseries.c
index f7ace99..48fe188 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -200,7 +200,9 @@ static void n8x0_i2c_setup(struct n800_s *s)
 
     /* Attach a menelaus PM chip */
     dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR);
-    qdev_connect_gpio_out(dev, 3, s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]);
+    qdev_connect_gpio_out(dev, 3,
+                          qdev_get_gpio_in(s->cpu->ih[0],
+                                           OMAP_INT_24XX_SYS_NIRQ));
 
     /* Attach a TMP105 PM chip (A0 wired to ground) */
     dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
diff --git a/hw/omap.h b/hw/omap.h
index d9ab006..cd80f7e 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -99,18 +99,6 @@ target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
 int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                 CPUWriteMemoryFunc * const *mem_write, void *opaque);
 
-/* OMAP interrupt controller */
-struct omap_intr_handler_s;
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk);
-void omap_inth_reset(struct omap_intr_handler_s *s);
-qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n);
-
 /* OMAP2 SDRAM controller */
 struct omap_sdrc_s;
 struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
@@ -691,8 +679,6 @@ struct uWireSlave {
     void *opaque;
 };
 struct omap_uwire_s;
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk);
 void omap_uwire_attach(struct omap_uwire_s *s,
                 uWireSlave *slave, int chipselect);
 
@@ -730,8 +716,6 @@ struct I2SCodec {
     } in, out;
 };
 struct omap_mcbsp_s;
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk);
 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
 
 void omap_tap_init(struct omap_target_agent_s *ta,
@@ -821,7 +805,6 @@ struct omap_mpu_state_s {
 
     CPUState *env;
 
-    qemu_irq *irq[2];
     qemu_irq *drq;
 
     qemu_irq wakeup;
@@ -878,7 +861,7 @@ struct omap_mpu_state_s {
     struct omap_lpg_s *led[2];
 
     /* MPU private TIPB peripherals */
-    struct omap_intr_handler_s *ih[2];
+    DeviceState *ih[2];
 
     struct soc_dma_s *dma;
 
diff --git a/hw/omap1.c b/hw/omap1.c
index 614fd31..6f6d80f 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -506,7 +506,7 @@ static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr)
     case 0x14:	/* IT_STATUS */
         ret = s->ulpd_pm_regs[addr >> 2];
         s->ulpd_pm_regs[addr >> 2] = 0;
-        qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]);
+        qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
         return ret;
 
     case 0x18:	/* Reserved */
@@ -603,7 +603,7 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
                     s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
 
                 s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;	/* IT_GAUGING */
-                qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]);
+                qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
             }
         }
         s->ulpd_pm_regs[addr >> 2] = value;
@@ -2206,15 +2206,17 @@ static void omap_uwire_reset(struct omap_uwire_s *s)
     s->setup[4] = 0;
 }
 
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk)
+static struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq dma,
+                                            omap_clk clk)
 {
     int iomemtype;
     struct omap_uwire_s *s = (struct omap_uwire_s *)
             g_malloc0(sizeof(struct omap_uwire_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma;
     omap_uwire_reset(s);
 
@@ -2815,14 +2817,15 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
 }
 
 static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
-                qemu_irq *irq, omap_clk clk)
+                                        qemu_irq timerirq, qemu_irq alarmirq,
+                                        omap_clk clk)
 {
     int iomemtype;
     struct omap_rtc_s *s = (struct omap_rtc_s *)
             g_malloc0(sizeof(struct omap_rtc_s));
 
-    s->irq = irq[0];
-    s->alarm = irq[1];
+    s->irq = timerirq;
+    s->alarm = alarmirq;
     s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s);
 
     omap_rtc_reset(s);
@@ -3334,15 +3337,16 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
     qemu_del_timer(s->sink_timer);
 }
 
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk)
+static struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq *dma, omap_clk clk)
 {
     int iomemtype;
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
             g_malloc0(sizeof(struct omap_mcbsp_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma[0];
     s->rxdrq = dma[1];
     s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s);
@@ -3564,8 +3568,6 @@ static void omap1_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
-    omap_inth_reset(mpu->ih[1]);
     omap_dma_reset(mpu->dma);
     omap_mpu_timer_reset(mpu->timer[0]);
     omap_mpu_timer_reset(mpu->timer[1]);
@@ -3716,6 +3718,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     qemu_irq *cpu_irq;
     qemu_irq dma_irqs[6];
     DriveInfo *dinfo;
+    SysBusDevice *busdev;
 
     if (!core)
         core = "ti925t";
@@ -3746,17 +3749,30 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     omap_clkm_init(0xfffece00, 0xe1008000, s);
 
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "arminth_ck"));
-    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1],
-                    omap_inth_get_pin(s->ih[0], OMAP_INT_15XX_IH2_IRQ),
-		    NULL, omap_findclk(s, "arminth_ck"));
-
-    for (i = 0; i < 6; i ++)
-        dma_irqs[i] =
-                s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr];
-    s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
+    s->ih[0] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[0], "size", 0x100);
+    qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0xfffecb00);
+    s->ih[1] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[1], "size", 0x800);
+    qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[1]);
+    busdev = sysbus_from_qdev(s->ih[1]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ));
+    /* The second interrupt controller's FIQ output is not wired up */
+    sysbus_mmio_map(busdev, 0, 0xfffe0000);
+
+    for (i = 0; i < 6; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih],
+                                       omap1_dma_irq_map[i].intr);
+    }
+    s->dma = omap_dma_init(0xfffed800, dma_irqs,
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD),
                            s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
 
     s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
@@ -3773,24 +3789,25 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
                     imif_base, OMAP_IMIF_BASE, s->sram_size);
 
     s->timer[0] = omap_mpu_timer_init(0xfffec500,
-                    s->irq[0][OMAP_INT_TIMER1],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1),
                     omap_findclk(s, "mputim_ck"));
     s->timer[1] = omap_mpu_timer_init(0xfffec600,
-                    s->irq[0][OMAP_INT_TIMER2],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2),
                     omap_findclk(s, "mputim_ck"));
     s->timer[2] = omap_mpu_timer_init(0xfffec700,
-                    s->irq[0][OMAP_INT_TIMER3],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3),
                     omap_findclk(s, "mputim_ck"));
 
     s->wdt = omap_wd_timer_init(0xfffec800,
-                    s->irq[0][OMAP_INT_WD_TIMER],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER),
                     omap_findclk(s, "armwdt_ck"));
 
     s->os_timer = omap_os_timer_init(0xfffb9000,
-                    s->irq[1][OMAP_INT_OS_TIMER],
+                    qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
+    s->lcd = omap_lcdc_init(0xfffec000,
+                            qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL),
                     omap_dma_get_lcdch(s->dma), imif_base, emiff_base,
                     omap_findclk(s, "lcd_ck"));
 
@@ -3801,27 +3818,30 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     omap_mpui_init(0xfffec900, s);
 
     s->private_tipb = omap_tipb_bridge_init(0xfffeca00,
-                    s->irq[0][OMAP_INT_BRIDGE_PRIV],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV),
                     omap_findclk(s, "tipb_ck"));
     s->public_tipb = omap_tipb_bridge_init(0xfffed300,
-                    s->irq[0][OMAP_INT_BRIDGE_PUB],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB),
                     omap_findclk(s, "tipb_ck"));
 
     omap_tcmi_init(0xfffecc00, s);
 
-    s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
+    s->uart[0] = omap_uart_init(0xfffb0000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
                     omap_findclk(s, "uart1_ck"),
                     omap_findclk(s, "uart1_ck"),
                     s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
                     "uart1",
                     serial_hds[0]);
-    s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
+    s->uart[1] = omap_uart_init(0xfffb0800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
                     omap_findclk(s, "uart2_ck"),
                     omap_findclk(s, "uart2_ck"),
                     s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
-    s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
+    s->uart[2] = omap_uart_init(0xfffb9800,
+                                qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
                     omap_findclk(s, "uart3_ck"),
                     omap_findclk(s, "uart3_ck"),
                     s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
@@ -3838,37 +3858,52 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->mmc = omap_mmc_init(0xfffb7800, dinfo->bdrv,
-                    s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX],
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
+                           &s->drq[OMAP_DMA_MMC_TX],
                     omap_findclk(s, "mmc_ck"));
 
     s->mpuio = omap_mpuio_init(0xfffb5000,
-                    s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO),
                     s->wakeup, omap_findclk(s, "clk32-kHz"));
 
     s->gpio = qdev_create(NULL, "omap-gpio");
     qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
     qdev_init_nofail(s->gpio);
     sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
-                    s->irq[0][OMAP_INT_GPIO_BANK1]);
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
     sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
 
-    s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
+    s->microwire = omap_uwire_init(0xfffb3000,
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX),
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
                     s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
 
     omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck"));
     omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck"));
 
-    s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
+    s->i2c[0] = omap_i2c_init(0xfffb3800,
+                              qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
                     &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
 
-    s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
+    s->rtc = omap_rtc_init(0xfffb4800,
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
+    s->mcbsp1 = omap_mcbsp_init(0xfffb1800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX),
                     &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
-    s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
+    s->mcbsp2 = omap_mcbsp_init(0xfffb1000,
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_TX),
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_RX),
                     &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
-    s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
+    s->mcbsp3 = omap_mcbsp_init(0xfffb7000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX),
                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
 
     s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
diff --git a/hw/omap2.c b/hw/omap2.c
index ca088d9..1025007 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2180,7 +2180,6 @@ static void omap2_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
     omap_dma_reset(mpu->dma);
     omap_prcm_reset(mpu->prcm);
     omap_sysctl_reset(mpu->sysc);
@@ -2264,20 +2263,27 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
 
     /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "mpu_intc_fclk"),
-                    omap_findclk(s, "mpu_intc_iclk"));
-
+    s->ih[0] = qdev_create(NULL, "omap2-intc");
+    qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
+    qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
+    qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0x480fe000);
     s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
-                    s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s);
+                             qdev_get_gpio_in(s->ih[0],
+                                              OMAP_INT_24XX_PRCM_MPU_IRQ),
+                             NULL, NULL, s);
 
     s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
                     omap_findclk(s, "omapctrl_iclk"), s);
 
-    for (i = 0; i < 4; i ++)
-        dma_irqs[i] =
-                s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr];
+    for (i = 0; i < 4; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
+                                       omap2_dma_irq_map[i].intr);
+    }
     s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
                     omap_findclk(s, "sdma_iclk"),
                     omap_findclk(s, "sdma_fclk"));
@@ -2288,7 +2294,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
 
     s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
-                    s->irq[0][OMAP_INT_24XX_UART1_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART1_IRQ),
                     omap_findclk(s, "uart1_fclk"),
                     omap_findclk(s, "uart1_iclk"),
                     s->drq[OMAP24XX_DMA_UART1_TX],
@@ -2296,7 +2303,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart1",
                     serial_hds[0]);
     s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
-                    s->irq[0][OMAP_INT_24XX_UART2_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART2_IRQ),
                     omap_findclk(s, "uart2_fclk"),
                     omap_findclk(s, "uart2_iclk"),
                     s->drq[OMAP24XX_DMA_UART2_TX],
@@ -2304,7 +2312,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
     s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
-                    s->irq[0][OMAP_INT_24XX_UART3_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART3_IRQ),
                     omap_findclk(s, "uart3_fclk"),
                     omap_findclk(s, "uart3_iclk"),
                     s->drq[OMAP24XX_DMA_UART3_TX],
@@ -2313,51 +2322,51 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
     s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER1],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
                     omap_findclk(s, "wu_gpt1_clk"),
                     omap_findclk(s, "wu_l4_iclk"));
     s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER2],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
                     omap_findclk(s, "core_gpt2_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER3],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
                     omap_findclk(s, "core_gpt3_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER4],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
                     omap_findclk(s, "core_gpt4_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER5],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
                     omap_findclk(s, "core_gpt5_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER6],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
                     omap_findclk(s, "core_gpt6_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER7],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
                     omap_findclk(s, "core_gpt7_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER8],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
                     omap_findclk(s, "core_gpt8_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER9],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
                     omap_findclk(s, "core_gpt9_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER10],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
                     omap_findclk(s, "core_gpt10_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER11],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
                     omap_findclk(s, "core_gpt11_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER12],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
                     omap_findclk(s, "core_gpt12_clk"),
                     omap_findclk(s, "core_l4_iclk"));
 
@@ -2368,12 +2377,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "core_l4_iclk"));
 
     s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
-                    s->irq[0][OMAP_INT_24XX_I2C1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C1_TX],
                     omap_findclk(s, "i2c1.fclk"),
                     omap_findclk(s, "i2c1.iclk"));
     s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
-                    s->irq[0][OMAP_INT_24XX_I2C2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C2_TX],
                     omap_findclk(s, "i2c2.fclk"),
                     omap_findclk(s, "i2c2.iclk"));
@@ -2390,10 +2399,14 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     }
     qdev_init_nofail(s->gpio);
     busdev = sysbus_from_qdev(s->gpio);
-    sysbus_connect_irq(busdev, 0, s->irq[0][OMAP_INT_24XX_GPIO_BANK1]);
-    sysbus_connect_irq(busdev, 3, s->irq[0][OMAP_INT_24XX_GPIO_BANK2]);
-    sysbus_connect_irq(busdev, 6, s->irq[0][OMAP_INT_24XX_GPIO_BANK3]);
-    sysbus_connect_irq(busdev, 9, s->irq[0][OMAP_INT_24XX_GPIO_BANK4]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
+    sysbus_connect_irq(busdev, 3,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
+    sysbus_connect_irq(busdev, 6,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
+    sysbus_connect_irq(busdev, 9,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
     ta = omap_l4ta(s->l4, 3);
     sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
     sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
@@ -2402,7 +2415,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
 
     s->sdrc = omap_sdrc_init(0x68009000);
-    s->gpmc = omap_gpmc_init(s, 0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ],
+    s->gpmc = omap_gpmc_init(s, 0x6800a000,
+                             qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
                              s->drq[OMAP24XX_DMA_GPMC]);
 
     dinfo = drive_get(IF_SD, 0, 0);
@@ -2411,36 +2425,38 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
-                    s->irq[0][OMAP_INT_24XX_MMC_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
                     &s->drq[OMAP24XX_DMA_MMC1_TX],
                     omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
 
     s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
-                    s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI1_TX0],
                     omap_findclk(s, "spi1_fclk"),
                     omap_findclk(s, "spi1_iclk"));
     s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
-                    s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI2_TX0],
                     omap_findclk(s, "spi2_fclk"),
                     omap_findclk(s, "spi2_iclk"));
 
     s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800,
                     /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
-                    s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
+                           s->drq[OMAP24XX_DMA_DSS],
                     omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
                     omap_findclk(s, "dss_54m_clk"),
                     omap_findclk(s, "dss_l3_iclk"),
                     omap_findclk(s, "dss_l4_iclk"));
 
     omap_sti_init(omap_l4ta(s->l4, 18), 0x54000000,
-                    s->irq[0][OMAP_INT_24XX_STI], omap_findclk(s, "emul_ck"),
+                  qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
+                  omap_findclk(s, "emul_ck"),
                     serial_hds[0] && serial_hds[1] && serial_hds[2] ?
                     serial_hds[3] : NULL);
 
     s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
-                    s->irq[0][OMAP_INT_24XX_EAC_IRQ],
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
                     /* Ten consecutive lines */
                     &s->drq[OMAP24XX_DMA_EAC_AC_RD],
                     omap_findclk(s, "func_96m_clk"),
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 38637c6..0f7fd9d 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -19,7 +19,7 @@
  */
 #include "hw.h"
 #include "omap.h"
-#include "exec-memory.h"
+#include "sysbus.h"
 
 /* Interrupt Handlers */
 struct omap_intr_handler_bank_s {
@@ -33,25 +33,26 @@ struct omap_intr_handler_bank_s {
 };
 
 struct omap_intr_handler_s {
+    SysBusDevice busdev;
     qemu_irq *pins;
     qemu_irq parent_intr[2];
     MemoryRegion mmio;
+    void *iclk;
+    void *fclk;
     unsigned char nbanks;
     int level_only;
+    uint32_t size;
+
+    uint8_t revision;
 
     /* state */
     uint32_t new_agr[2];
     int sir_intr[2];
     int autoidle;
     uint32_t mask;
-    struct omap_intr_handler_bank_s bank[];
+    struct omap_intr_handler_bank_s bank[3];
 };
 
-inline qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n)
-{
-    return s->pins[n];
-}
-
 static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
 {
     int i, j, sir_intr, p_intr, p, f;
@@ -325,8 +326,10 @@ static const MemoryRegionOps omap_inth_mem_ops = {
     },
 };
 
-void omap_inth_reset(struct omap_intr_handler_s *s)
+static void omap_inth_reset(DeviceState *dev)
 {
+    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
+                                                sysbus_from_qdev(dev));
     int i;
 
     for (i = 0; i < s->nbanks; ++i){
@@ -353,29 +356,35 @@ void omap_inth_reset(struct omap_intr_handler_s *s)
     qemu_set_irq(s->parent_intr[1], 0);
 }
 
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
+static int omap_intc_init(SysBusDevice *dev)
 {
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            g_malloc0(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
-    s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s, "omap-intc", size);
-    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
-
-    omap_inth_reset(s);
-
-    return s;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap-intc: clk not connected\n");
+    }
+    s->nbanks = 1;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
+                          "omap-intc", s->size);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
 }
 
+static SysBusDeviceInfo omap_intc_info = {
+    .init = omap_intc_init,
+    .qdev.name = "omap-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+        DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
 static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
 {
@@ -394,7 +403,7 @@ static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
 
     switch (offset) {
     case 0x00:	/* INTC_REVISION */
-        return 0x21;
+        return s->revision;
 
     case 0x10:	/* INTC_SYSCONFIG */
         return (s->autoidle >> 2) & 1;
@@ -475,7 +484,7 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
         s->autoidle &= 4;
         s->autoidle |= (value & 1) << 2;
         if (value & 2)						/* SOFTRESET */
-            omap_inth_reset(s);
+            omap_inth_reset(&s->busdev.qdev);
         return;
 
     case 0x48:	/* INTC_CONTROL */
@@ -568,27 +577,45 @@ static const MemoryRegionOps omap2_inth_mem_ops = {
     },
 };
 
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk)
+static int omap2_intc_init(SysBusDevice *dev)
 {
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            g_malloc0(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-intc: iclk not connected\n");
+    }
+    if (!s->fclk) {
+        hw_error("omap2-intc: fclk not connected\n");
+    }
     s->level_only = 1;
-    s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s, "omap2-intc", size);
-    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
+    s->nbanks = 3;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
+                          "omap2-intc", 0x1000);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
+}
 
-    omap_inth_reset(s);
+static SysBusDeviceInfo omap2_intc_info = {
+    .init = omap2_intc_init,
+    .qdev.name = "omap2-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+                          revision, 0x21),
+        DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
+static void omap_intc_register_device(void)
+{
+    sysbus_register_withprop(&omap_intc_info);
+    sysbus_register_withprop(&omap2_intc_info);
 }
+
+device_init(omap_intc_register_device)
