|
@@ -297,3 +297,131 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
|
|
|
|
|
|
for (j = i - 1; j >= 0; j--)
|
|
|
kfree(hmux->pads[j].name);
|
|
|
+ goto err3;
|
|
|
+ }
|
|
|
+ strcpy(pad->name, bpad->name);
|
|
|
+
|
|
|
+ pad->flags = bpad->flags;
|
|
|
+ pad->enable = bpad->enable;
|
|
|
+ pad->idle = bpad->idle;
|
|
|
+ pad->off = bpad->off;
|
|
|
+
|
|
|
+ if (pad->flags &
|
|
|
+ (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP))
|
|
|
+ nr_pads_dynamic++;
|
|
|
+
|
|
|
+ pr_debug("%s: Initialized %s\n", __func__, pad->name);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!nr_pads_dynamic)
|
|
|
+ return hmux;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add pads that need dynamic muxing into a separate list
|
|
|
+ */
|
|
|
+
|
|
|
+ hmux->nr_pads_dynamic = nr_pads_dynamic;
|
|
|
+ hmux->pads_dynamic = kzalloc(sizeof(struct omap_device_pad *) *
|
|
|
+ nr_pads_dynamic, GFP_KERNEL);
|
|
|
+ if (!hmux->pads_dynamic) {
|
|
|
+ pr_err("%s: Could not allocate dynamic pads\n", __func__);
|
|
|
+ return hmux;
|
|
|
+ }
|
|
|
+
|
|
|
+ nr_pads_dynamic = 0;
|
|
|
+ for (i = 0; i < hmux->nr_pads; i++) {
|
|
|
+ struct omap_device_pad *pad = &hmux->pads[i];
|
|
|
+
|
|
|
+ if (pad->flags &
|
|
|
+ (OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP)) {
|
|
|
+ pr_debug("%s: pad %s tagged dynamic\n",
|
|
|
+ __func__, pad->name);
|
|
|
+ hmux->pads_dynamic[nr_pads_dynamic] = pad;
|
|
|
+ nr_pads_dynamic++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return hmux;
|
|
|
+
|
|
|
+err3:
|
|
|
+ kfree(hmux->pads);
|
|
|
+err2:
|
|
|
+ kfree(hmux);
|
|
|
+err1:
|
|
|
+ pr_err("%s: Could not allocate device mux entry\n", __func__);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads
|
|
|
+ * @hmux: Pads for a hwmod
|
|
|
+ * @mpu_irqs: MPU irq array for a hwmod
|
|
|
+ *
|
|
|
+ * Scans the wakeup status of pads for a single hwmod. If an irq
|
|
|
+ * array is defined for this mux, the parser will call the registered
|
|
|
+ * ISRs for corresponding pads, otherwise the parser will stop at the
|
|
|
+ * first wakeup active pad and return. Returns true if there is a
|
|
|
+ * pending and non-served wakeup event for the mux, otherwise false.
|
|
|
+ */
|
|
|
+static bool omap_hwmod_mux_scan_wakeups(struct omap_hwmod_mux_info *hmux,
|
|
|
+ struct omap_hwmod_irq_info *mpu_irqs)
|
|
|
+{
|
|
|
+ int i, irq;
|
|
|
+ unsigned int val;
|
|
|
+ u32 handled_irqs = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < hmux->nr_pads_dynamic; i++) {
|
|
|
+ struct omap_device_pad *pad = hmux->pads_dynamic[i];
|
|
|
+
|
|
|
+ if (!(pad->flags & OMAP_DEVICE_PAD_WAKEUP) ||
|
|
|
+ !(pad->idle & OMAP_WAKEUP_EN))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ val = omap_mux_read(pad->partition, pad->mux->reg_offset);
|
|
|
+ if (!(val & OMAP_WAKEUP_EVENT))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!hmux->irqs)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ irq = hmux->irqs[i];
|
|
|
+ /* make sure we only handle each irq once */
|
|
|
+ if (handled_irqs & 1 << irq)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ handled_irqs |= 1 << irq;
|
|
|
+
|
|
|
+ generic_handle_irq(mpu_irqs[irq].irq);
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod
|
|
|
+ *
|
|
|
+ * Checks a single hwmod for every wakeup capable pad to see if there is an
|
|
|
+ * active wakeup event. If this is the case, call the corresponding ISR.
|
|
|
+ */
|
|
|
+static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data)
|
|
|
+{
|
|
|
+ if (!oh->mux || !oh->mux->enabled)
|
|
|
+ return 0;
|
|
|
+ if (omap_hwmod_mux_scan_wakeups(oh->mux, oh->mpu_irqs))
|
|
|
+ generic_handle_irq(oh->mpu_irqs[0].irq);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_mux_handle_irq - Process pad wakeup irqs.
|
|
|
+ *
|
|
|
+ * Calls a function for each registered omap_hwmod to check
|
|
|
+ * pad wakeup statuses.
|
|
|
+ */
|
|
|
+static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused)
|
|
|
+{
|
|
|
+ omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|