unsigned int state_idx = genpd->state_idx;
        ktime_t time_start;
        s64 elapsed_ns;
-       int ret;
+       int ret, nr_calls = 0;
+
+       /* Notify consumers that we are about to power on. */
+       ret = __raw_notifier_call_chain(&genpd->power_notifiers,
+                                       GENPD_NOTIFY_PRE_ON, NULL, -1,
+                                       &nr_calls);
+       ret = notifier_to_errno(ret);
+       if (ret)
+               goto err;
 
        if (!genpd->power_on)
-               return 0;
+               goto out;
 
-       if (!timed)
-               return genpd->power_on(genpd);
+       if (!timed) {
+               ret = genpd->power_on(genpd);
+               if (ret)
+                       goto err;
+
+               goto out;
+       }
 
        time_start = ktime_get();
        ret = genpd->power_on(genpd);
        if (ret)
-               return ret;
+               goto err;
 
        elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
        if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
-               return ret;
+               goto out;
 
        genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
        genpd->max_off_time_changed = true;
        pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
                 genpd->name, "on", elapsed_ns);
 
+out:
+       raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
+       return 0;
+err:
+       raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
+                               NULL);
        return ret;
 }
 
        unsigned int state_idx = genpd->state_idx;
        ktime_t time_start;
        s64 elapsed_ns;
-       int ret;
+       int ret, nr_calls = 0;
+
+       /* Notify consumers that we are about to power off. */
+       ret = __raw_notifier_call_chain(&genpd->power_notifiers,
+                                       GENPD_NOTIFY_PRE_OFF, NULL, -1,
+                                       &nr_calls);
+       ret = notifier_to_errno(ret);
+       if (ret)
+               goto busy;
 
        if (!genpd->power_off)
-               return 0;
+               goto out;
+
+       if (!timed) {
+               ret = genpd->power_off(genpd);
+               if (ret)
+                       goto busy;
 
-       if (!timed)
-               return genpd->power_off(genpd);
+               goto out;
+       }
 
        time_start = ktime_get();
        ret = genpd->power_off(genpd);
        if (ret)
-               return ret;
+               goto busy;
 
        elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
        if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
-               return 0;
+               goto out;
 
        genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
        genpd->max_off_time_changed = true;
        pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
                 genpd->name, "off", elapsed_ns);
 
+out:
+       raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
+                               NULL);
        return 0;
+busy:
+       if (nr_calls)
+               __raw_notifier_call_chain(&genpd->power_notifiers,
+                                         GENPD_NOTIFY_ON, NULL, nr_calls - 1,
+                                         NULL);
+       return ret;
 }
 
 /**
 }
 EXPORT_SYMBOL_GPL(pm_genpd_remove_device);
 
+/**
+ * dev_pm_genpd_add_notifier - Add a genpd power on/off notifier for @dev
+ *
+ * @dev: Device that should be associated with the notifier
+ * @nb: The notifier block to register
+ *
+ * Users may call this function to add a genpd power on/off notifier for an
+ * attached @dev. Only one notifier per device is allowed. The notifier is
+ * sent when genpd is powering on/off the PM domain.
+ *
+ * It is assumed that the user guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Returns 0 on success and negative error values on failures.
+ */
+int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb)
+{
+       struct generic_pm_domain *genpd;
+       struct generic_pm_domain_data *gpd_data;
+       int ret;
+
+       genpd = dev_to_genpd_safe(dev);
+       if (!genpd)
+               return -ENODEV;
+
+       if (WARN_ON(!dev->power.subsys_data ||
+                    !dev->power.subsys_data->domain_data))
+               return -EINVAL;
+
+       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       if (gpd_data->power_nb)
+               return -EEXIST;
+
+       genpd_lock(genpd);
+       ret = raw_notifier_chain_register(&genpd->power_notifiers, nb);
+       genpd_unlock(genpd);
+
+       if (ret) {
+               dev_warn(dev, "failed to add notifier for PM domain %s\n",
+                        genpd->name);
+               return ret;
+       }
+
+       gpd_data->power_nb = nb;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_add_notifier);
+
+/**
+ * dev_pm_genpd_remove_notifier - Remove a genpd power on/off notifier for @dev
+ *
+ * @dev: Device that is associated with the notifier
+ *
+ * Users may call this function to remove a genpd power on/off notifier for an
+ * attached @dev.
+ *
+ * It is assumed that the user guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Returns 0 on success and negative error values on failures.
+ */
+int dev_pm_genpd_remove_notifier(struct device *dev)
+{
+       struct generic_pm_domain *genpd;
+       struct generic_pm_domain_data *gpd_data;
+       int ret;
+
+       genpd = dev_to_genpd_safe(dev);
+       if (!genpd)
+               return -ENODEV;
+
+       if (WARN_ON(!dev->power.subsys_data ||
+                    !dev->power.subsys_data->domain_data))
+               return -EINVAL;
+
+       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       if (!gpd_data->power_nb)
+               return -ENODEV;
+
+       genpd_lock(genpd);
+       ret = raw_notifier_chain_unregister(&genpd->power_notifiers,
+                                           gpd_data->power_nb);
+       genpd_unlock(genpd);
+
+       if (ret) {
+               dev_warn(dev, "failed to remove notifier for PM domain %s\n",
+                        genpd->name);
+               return ret;
+       }
+
+       gpd_data->power_nb = NULL;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_remove_notifier);
+
 static int genpd_add_subdomain(struct generic_pm_domain *genpd,
                               struct generic_pm_domain *subdomain)
 {
        INIT_LIST_HEAD(&genpd->parent_links);
        INIT_LIST_HEAD(&genpd->child_links);
        INIT_LIST_HEAD(&genpd->dev_list);
+       RAW_INIT_NOTIFIER_HEAD(&genpd->power_notifiers);
        genpd_lock_init(genpd);
        genpd->gov = gov;
        INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 
        GENPD_STATE_OFF,        /* PM domain is off */
 };
 
+enum genpd_notication {
+       GENPD_NOTIFY_PRE_OFF = 0,
+       GENPD_NOTIFY_OFF,
+       GENPD_NOTIFY_PRE_ON,
+       GENPD_NOTIFY_ON,
+};
+
 struct dev_power_governor {
        bool (*power_down_ok)(struct dev_pm_domain *domain);
        bool (*suspend_ok)(struct device *dev);
        cpumask_var_t cpus;             /* A cpumask of the attached CPUs */
        int (*power_off)(struct generic_pm_domain *domain);
        int (*power_on)(struct generic_pm_domain *domain);
+       struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
        struct opp_table *opp_table;    /* OPP table of the genpd */
        unsigned int (*opp_to_performance_state)(struct generic_pm_domain *genpd,
                                                 struct dev_pm_opp *opp);
        struct pm_domain_data base;
        struct gpd_timing_data td;
        struct notifier_block nb;
+       struct notifier_block *power_nb;
        int cpu;
        unsigned int performance_state;
        void *data;
                  struct dev_power_governor *gov, bool is_off);
 int pm_genpd_remove(struct generic_pm_domain *genpd);
 int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
+int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
+int dev_pm_genpd_remove_notifier(struct device *dev);
 
 extern struct dev_power_governor simple_qos_governor;
 extern struct dev_power_governor pm_domain_always_on_gov;
        return -ENOTSUPP;
 }
 
+static inline int dev_pm_genpd_add_notifier(struct device *dev,
+                                           struct notifier_block *nb)
+{
+       return -ENOTSUPP;
+}
+
+static inline int dev_pm_genpd_remove_notifier(struct device *dev)
+{
+       return -ENOTSUPP;
+}
+
 #define simple_qos_governor            (*(struct dev_power_governor *)(NULL))
 #define pm_domain_always_on_gov                (*(struct dev_power_governor *)(NULL))
 #endif