ARM: OMAP2+: omap_hwmod: Introduce HWMOD_NEEDS_REIDLE
[rpmsg/hwspinlock.git] / arch / arm / mach-omap2 / omap_device.c
index 41c7b905980a9e7a37a512cf26c06a428b4e9ca6..4933e44a7e7e95f1cc887819752448cad01b01d8 100644 (file)
@@ -216,6 +216,27 @@ odbfd_exit:
        return ret;
 }
 
+/**
+ * _omap_device_check_reidle_hwmods - check all hwmods in device for reidle flag
+ * @od: struct omap_device *od
+ *
+ * Checks underlying hwmods for reidle flag, if present, remove from hwmod
+ * list and set flag in omap_device to keep track.  Returns 0.
+ */
+static int _omap_device_check_reidle_hwmods(struct omap_device *od)
+{
+       int i;
+
+       for (i = 0; i < od->hwmods_cnt; i++) {
+               if (od->hwmods[i]->flags & HWMOD_NEEDS_REIDLE) {
+                       od->flags |= OMAP_DEVICE_HAS_REIDLE_HWMODS;
+                       omap_hwmod_disable_reidle(od->hwmods[i]);
+               }
+       }
+
+       return 0;
+}
+
 static int _omap_device_notifier_call(struct notifier_block *nb,
                                      unsigned long event, void *dev)
 {
@@ -245,6 +266,13 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
                        pm_runtime_set_active(dev);
                }
                break;
+       case BUS_NOTIFY_BOUND_DRIVER:
+               od = to_omap_device(pdev);
+               if (od) {
+                       od->_driver_status = BUS_NOTIFY_BOUND_DRIVER;
+                       _omap_device_check_reidle_hwmods(od);
+               }
+               break;
        case BUS_NOTIFY_ADD_DEVICE:
                if (pdev->dev.of_node)
                        omap_device_build_from_dt(pdev);
@@ -293,6 +321,24 @@ static int _omap_device_idle_hwmods(struct omap_device *od)
        return ret;
 }
 
+/**
+ * _omap_device_reidle_hwmods - call omap_hwmod_enable_reidle on all hwmods
+ * @od: struct omap_device *od
+ *
+ * Add all underlying hwmods to hwmod reidle list.  Returns 0.
+ */
+static int _omap_device_reidle_hwmods(struct omap_device *od)
+{
+       int i;
+
+       for (i = 0; i < od->hwmods_cnt; i++)
+               if (od->hwmods[i]->flags | HWMOD_NEEDS_REIDLE)
+                       omap_hwmod_enable_reidle(od->hwmods[i]);
+
+       /* XXX pass along return value here? */
+       return 0;
+}
+
 /* Public functions for use by core code */
 
 /**
@@ -378,6 +424,9 @@ void omap_device_delete(struct omap_device *od)
        if (!od)
                return;
 
+       if (od->flags & OMAP_DEVICE_HAS_REIDLE_HWMODS)
+               _omap_device_reidle_hwmods(od);
+
        od->pdev->archdata.od = NULL;
        kfree(od->hwmods);
        kfree(od);
@@ -829,6 +878,7 @@ static struct notifier_block platform_nb = {
 
 static int __init omap_device_init(void)
 {
+       omap_hwmod_setup_reidle();
        bus_register_notifier(&platform_bus_type, &platform_nb);
        return 0;
 }