}
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
 
+int _get_opp_count(struct opp_table *opp_table)
+{
+       struct dev_pm_opp *opp;
+       int count = 0;
+
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(opp, &opp_table->opp_list, node) {
+               if (opp->available)
+                       count++;
+       }
+
+       mutex_unlock(&opp_table->lock);
+
+       return count;
+}
+
 /**
  * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
  * @dev:       device for which we do this operation
 int dev_pm_opp_get_opp_count(struct device *dev)
 {
        struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp;
-       int count = 0;
+       int count;
 
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                count = PTR_ERR(opp_table);
                dev_dbg(dev, "%s: OPP table not found (%d)\n",
                        __func__, count);
-               return count;
-       }
-
-       mutex_lock(&opp_table->lock);
-
-       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available)
-                       count++;
+               return 0;
        }
 
-       mutex_unlock(&opp_table->lock);
+       count = _get_opp_count(opp_table);
        dev_pm_opp_put_opp_table(opp_table);
 
        return count;
        return true;
 }
 
-/*
- * Returns:
- * 0: On success. And appropriate error message for duplicate OPPs.
- * -EBUSY: For OPP with same freq/volt and is available. The callers of
- *  _opp_add() must return 0 if they receive -EBUSY from it. This is to make
- *  sure we don't print error messages unnecessarily if different parts of
- *  kernel try to initialize the OPP table.
- * -EEXIST: For OPP with same freq but different volt or is unavailable. This
- *  should be considered an error by the callers of _opp_add().
- */
-int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
-            struct opp_table *opp_table)
+static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
+                            struct opp_table *opp_table,
+                            struct list_head **head)
 {
        struct dev_pm_opp *opp;
-       struct list_head *head;
-       int ret;
 
        /*
         * Insert new OPP in order of increasing frequency and discard if
         * loop, don't replace it with head otherwise it will become an infinite
         * loop.
         */
-       mutex_lock(&opp_table->lock);
-       head = &opp_table->opp_list;
-
        list_for_each_entry(opp, &opp_table->opp_list, node) {
                if (new_opp->rate > opp->rate) {
-                       head = &opp->node;
+                       *head = &opp->node;
                        continue;
                }
 
                if (new_opp->rate < opp->rate)
-                       break;
+                       return 0;
 
                /* Duplicate OPPs */
                dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
                         new_opp->supplies[0].u_volt, new_opp->available);
 
                /* Should we compare voltages for all regulators here ? */
-               ret = opp->available &&
-                     new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
+               return opp->available &&
+                      new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
+       }
+
+       return 0;
+}
+
+/*
+ * Returns:
+ * 0: On success. And appropriate error message for duplicate OPPs.
+ * -EBUSY: For OPP with same freq/volt and is available. The callers of
+ *  _opp_add() must return 0 if they receive -EBUSY from it. This is to make
+ *  sure we don't print error messages unnecessarily if different parts of
+ *  kernel try to initialize the OPP table.
+ * -EEXIST: For OPP with same freq but different volt or is unavailable. This
+ *  should be considered an error by the callers of _opp_add().
+ */
+int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
+            struct opp_table *opp_table, bool rate_not_available)
+{
+       struct list_head *head;
+       int ret;
+
+       mutex_lock(&opp_table->lock);
+       head = &opp_table->opp_list;
 
-               mutex_unlock(&opp_table->lock);
-               return ret;
+       if (likely(!rate_not_available)) {
+               ret = _opp_is_duplicate(dev, new_opp, opp_table, &head);
+               if (ret) {
+                       mutex_unlock(&opp_table->lock);
+                       return ret;
+               }
        }
 
        if (opp_table->get_pstate)
        new_opp->available = true;
        new_opp->dynamic = dynamic;
 
-       ret = _opp_add(dev, new_opp, opp_table);
+       ret = _opp_add(dev, new_opp, opp_table, false);
        if (ret) {
                /* Don't return error for duplicate OPPs */
                if (ret == -EBUSY)
 
        u64 rate;
        u32 val;
        int ret;
+       bool rate_not_available = false;
 
        new_opp = _opp_allocate(opp_table);
        if (!new_opp)
 
        ret = of_property_read_u64(np, "opp-hz", &rate);
        if (ret < 0) {
-               dev_err(dev, "%s: opp-hz not found\n", __func__);
-               goto free_opp;
+               /* "opp-hz" is optional for devices like power domains. */
+               if (!of_find_property(dev->of_node, "#power-domain-cells",
+                                     NULL)) {
+                       dev_err(dev, "%s: opp-hz not found\n", __func__);
+                       goto free_opp;
+               }
+
+               rate_not_available = true;
+       } else {
+               /*
+                * Rate is defined as an unsigned long in clk API, and so
+                * casting explicitly to its type. Must be fixed once rate is 64
+                * bit guaranteed in clk API.
+                */
+               new_opp->rate = (unsigned long)rate;
        }
 
        /* Check if the OPP supports hardware's hierarchy of versions or not */
                goto free_opp;
        }
 
-       /*
-        * Rate is defined as an unsigned long in clk API, and so casting
-        * explicitly to its type. Must be fixed once rate is 64 bit
-        * guaranteed in clk API.
-        */
-       new_opp->rate = (unsigned long)rate;
        new_opp->turbo = of_property_read_bool(np, "turbo-mode");
 
        new_opp->np = np;
        if (ret)
                goto free_opp;
 
-       ret = _opp_add(dev, new_opp, opp_table);
+       ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
        if (ret) {
                /* Don't return error for duplicate OPPs */
                if (ret == -EBUSY)
 
 
 /* Routines internal to opp core */
 void _get_opp_table_kref(struct opp_table *opp_table);
+int _get_opp_count(struct opp_table *opp_table);
 struct opp_table *_find_opp_table(struct device *dev);
 struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
 void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
 void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
 struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
 void _opp_free(struct dev_pm_opp *opp);
-int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
+int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
 int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
 void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
 struct opp_table *_add_opp_table(struct device *dev);