|
@@ -143,3 +143,117 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|
|
chip->irq_eoi(&desc->irq_data);
|
|
|
chip->irq_unmask(&desc->irq_data);
|
|
|
|
|
|
+ prcm_irq_setup->ocp_barrier(); /* avoid spurious IRQs */
|
|
|
+}
|
|
|
+
|
|
|
+/* Public functions */
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_prcm_event_to_irq - given a PRCM event name, returns the
|
|
|
+ * corresponding IRQ on which the handler should be registered
|
|
|
+ * @name: name of the PRCM interrupt bit to look up - see struct omap_prcm_irq
|
|
|
+ *
|
|
|
+ * Returns the Linux internal IRQ ID corresponding to @name upon success,
|
|
|
+ * or -ENOENT upon failure.
|
|
|
+ */
|
|
|
+int omap_prcm_event_to_irq(const char *name)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!prcm_irq_setup || !name)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ for (i = 0; i < prcm_irq_setup->nr_irqs; i++)
|
|
|
+ if (!strcmp(prcm_irq_setup->irqs[i].name, name))
|
|
|
+ return prcm_irq_setup->base_irq +
|
|
|
+ prcm_irq_setup->irqs[i].offset;
|
|
|
+
|
|
|
+ return -ENOENT;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_prcm_irq_cleanup - reverses memory allocated and other steps
|
|
|
+ * done by omap_prcm_register_chain_handler()
|
|
|
+ *
|
|
|
+ * No return value.
|
|
|
+ */
|
|
|
+void omap_prcm_irq_cleanup(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!prcm_irq_setup) {
|
|
|
+ pr_err("PRCM: IRQ handler not initialized; cannot cleanup\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (prcm_irq_chips) {
|
|
|
+ for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
|
|
|
+ if (prcm_irq_chips[i])
|
|
|
+ irq_remove_generic_chip(prcm_irq_chips[i],
|
|
|
+ 0xffffffff, 0, 0);
|
|
|
+ prcm_irq_chips[i] = NULL;
|
|
|
+ }
|
|
|
+ kfree(prcm_irq_chips);
|
|
|
+ prcm_irq_chips = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ kfree(prcm_irq_setup->saved_mask);
|
|
|
+ prcm_irq_setup->saved_mask = NULL;
|
|
|
+
|
|
|
+ kfree(prcm_irq_setup->priority_mask);
|
|
|
+ prcm_irq_setup->priority_mask = NULL;
|
|
|
+
|
|
|
+ irq_set_chained_handler(prcm_irq_setup->irq, NULL);
|
|
|
+
|
|
|
+ if (prcm_irq_setup->base_irq > 0)
|
|
|
+ irq_free_descs(prcm_irq_setup->base_irq,
|
|
|
+ prcm_irq_setup->nr_regs * 32);
|
|
|
+ prcm_irq_setup->base_irq = 0;
|
|
|
+}
|
|
|
+
|
|
|
+void omap_prcm_irq_prepare(void)
|
|
|
+{
|
|
|
+ prcm_irq_setup->suspended = true;
|
|
|
+}
|
|
|
+
|
|
|
+void omap_prcm_irq_complete(void)
|
|
|
+{
|
|
|
+ prcm_irq_setup->suspended = false;
|
|
|
+
|
|
|
+ /* If we have not saved the masks, do not attempt to restore */
|
|
|
+ if (!prcm_irq_setup->suspend_save_flag)
|
|
|
+ return;
|
|
|
+
|
|
|
+ prcm_irq_setup->suspend_save_flag = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Re-enable all masked PRCM irq sources, this causes the PRCM
|
|
|
+ * interrupt to fire immediately if the events were masked
|
|
|
+ * previously in the chain handler
|
|
|
+ */
|
|
|
+ prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
|
|
|
+ * handler based on provided parameters
|
|
|
+ * @irq_setup: hardware data about the underlying PRM/PRCM
|
|
|
+ *
|
|
|
+ * Set up the PRCM chained interrupt handler on the PRCM IRQ. Sets up
|
|
|
+ * one generic IRQ chip per PRM interrupt status/enable register pair.
|
|
|
+ * Returns 0 upon success, -EINVAL if called twice or if invalid
|
|
|
+ * arguments are passed, or -ENOMEM on any other error.
|
|
|
+ */
|
|
|
+int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
|
|
|
+{
|
|
|
+ int nr_regs;
|
|
|
+ u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
|
|
|
+ int offset, i;
|
|
|
+ struct irq_chip_generic *gc;
|
|
|
+ struct irq_chip_type *ct;
|
|
|
+
|
|
|
+ if (!irq_setup)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ nr_regs = irq_setup->nr_regs;
|
|
|
+
|