|
@@ -3923,3 +3923,170 @@ int omap_hwmod_for_each_by_class(const char *classname,
|
|
|
|
|
|
if (!classname || !fn)
|
|
|
return -EINVAL;
|
|
|
+
|
|
|
+ pr_debug("omap_hwmod: %s: looking for modules of class %s\n",
|
|
|
+ __func__, classname);
|
|
|
+
|
|
|
+ list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
|
|
|
+ if (!strcmp(temp_oh->class->name, classname)) {
|
|
|
+ pr_debug("omap_hwmod: %s: %s: calling callback fn\n",
|
|
|
+ __func__, temp_oh->name);
|
|
|
+ ret = (*fn)(temp_oh, user);
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ pr_debug("omap_hwmod: %s: iterator terminated early: %d\n",
|
|
|
+ __func__, ret);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @state: state that _setup() should leave the hwmod in
|
|
|
+ *
|
|
|
+ * Sets the hwmod state that @oh will enter at the end of _setup()
|
|
|
+ * (called by omap_hwmod_setup_*()). See also the documentation
|
|
|
+ * for _setup_postsetup(), above. Returns 0 upon success or
|
|
|
+ * -EINVAL if there is a problem with the arguments or if the hwmod is
|
|
|
+ * in the wrong state.
|
|
|
+ */
|
|
|
+int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (!oh)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (state != _HWMOD_STATE_DISABLED &&
|
|
|
+ state != _HWMOD_STATE_ENABLED &&
|
|
|
+ state != _HWMOD_STATE_IDLE)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&oh->_lock, flags);
|
|
|
+
|
|
|
+ if (oh->_state != _HWMOD_STATE_REGISTERED) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto ohsps_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ oh->_postsetup_state = state;
|
|
|
+ ret = 0;
|
|
|
+
|
|
|
+ohsps_unlock:
|
|
|
+ spin_unlock_irqrestore(&oh->_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_get_context_loss_count - get lost context count
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Returns the context loss count of associated @oh
|
|
|
+ * upon success, or zero if no context loss data is available.
|
|
|
+ *
|
|
|
+ * On OMAP4, this queries the per-hwmod context loss register,
|
|
|
+ * assuming one exists. If not, or on OMAP2/3, this queries the
|
|
|
+ * enclosing powerdomain context loss count.
|
|
|
+ */
|
|
|
+int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ struct powerdomain *pwrdm;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (soc_ops.get_context_lost)
|
|
|
+ return soc_ops.get_context_lost(oh);
|
|
|
+
|
|
|
+ pwrdm = omap_hwmod_get_pwrdm(oh);
|
|
|
+ if (pwrdm)
|
|
|
+ ret = pwrdm_get_context_loss_count(pwrdm);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_no_setup_reset - prevent a hwmod from being reset upon setup
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Prevent the hwmod @oh from being reset during the setup process.
|
|
|
+ * Intended for use by board-*.c files on boards with devices that
|
|
|
+ * cannot tolerate being reset. Must be called before the hwmod has
|
|
|
+ * been set up. Returns 0 upon success or negative error code upon
|
|
|
+ * failure.
|
|
|
+ */
|
|
|
+int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!oh)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (oh->_state != _HWMOD_STATE_REGISTERED) {
|
|
|
+ pr_err("omap_hwmod: %s: cannot prevent setup reset; in wrong state\n",
|
|
|
+ oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ oh->flags |= HWMOD_INIT_NO_RESET;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ
|
|
|
+ * @oh: struct omap_hwmod * containing hwmod mux entries
|
|
|
+ * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup
|
|
|
+ * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup
|
|
|
+ *
|
|
|
+ * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux
|
|
|
+ * entry number @pad_idx for the hwmod @oh, trigger the interrupt
|
|
|
+ * service routine for the hwmod's mpu_irqs array index @irq_idx. If
|
|
|
+ * this function is not called for a given pad_idx, then the ISR
|
|
|
+ * associated with @oh's first MPU IRQ will be triggered when an I/O
|
|
|
+ * pad wakeup occurs on that pad. Note that @pad_idx is the index of
|
|
|
+ * the _dynamic or wakeup_ entry: if there are other entries not
|
|
|
+ * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these
|
|
|
+ * entries are NOT COUNTED in the dynamic pad index. This function
|
|
|
+ * must be called separately for each pad that requires its interrupt
|
|
|
+ * to be re-routed this way. Returns -EINVAL if there is an argument
|
|
|
+ * problem or if @oh does not have hwmod mux entries or MPU IRQs;
|
|
|
+ * returns -ENOMEM if memory cannot be allocated; or 0 upon success.
|
|
|
+ *
|
|
|
+ * XXX This function interface is fragile. Rather than using array
|
|
|
+ * indexes, which are subject to unpredictable change, it should be
|
|
|
+ * using hwmod IRQ names, and some other stable key for the hwmod mux
|
|
|
+ * pad records.
|
|
|
+ */
|
|
|
+int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
|
|
|
+{
|
|
|
+ int nr_irqs;
|
|
|
+
|
|
|
+ might_sleep();
|
|
|
+
|
|
|
+ if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 ||
|
|
|
+ pad_idx >= oh->mux->nr_pads_dynamic)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Check the number of available mpu_irqs */
|
|
|
+ for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++)
|
|
|
+ ;
|
|
|
+
|
|
|
+ if (irq_idx >= nr_irqs)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->mux->irqs) {
|
|
|
+ /* XXX What frees this? */
|
|
|
+ oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!oh->mux->irqs)
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ oh->mux->irqs[pad_idx] = irq_idx;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|