"Unpreparing critical %s\n", core->name))
                return;
 
+       if (core->flags & CLK_SET_RATE_GATE)
+               clk_core_rate_unprotect(core);
+
        if (--core->prepare_count > 0)
                return;
 
 
        core->prepare_count++;
 
+       /*
+        * CLK_SET_RATE_GATE is a special case of clock protection
+        * Instead of a consumer claiming exclusive rate control, it is
+        * actually the provider which prevents any consumer from making any
+        * operation which could result in a rate change or rate glitch while
+        * the clock is prepared.
+        */
+       if (core->flags & CLK_SET_RATE_GATE)
+               clk_core_rate_protect(core);
+
        return 0;
 unprepare:
        clk_core_unprepare(core->parent);
        if (clk_core_rate_is_protected(core))
                return -EBUSY;
 
-       if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
-               return -EBUSY;
-
        /* calculate new rates and get the topmost changed clock */
        top = clk_calc_new_rates(core, req_rate);
        if (!top)