bool                    orphan;
        unsigned int            enable_count;
        unsigned int            prepare_count;
+       unsigned int            protect_count;
        unsigned long           min_rate;
        unsigned long           max_rate;
        unsigned long           accuracy;
        spin_unlock_irqrestore(&enable_lock, flags);
 }
 
+static bool clk_core_rate_is_protected(struct clk_core *core)
+{
+       return core->protect_count;
+}
+
 static bool clk_core_is_prepared(struct clk_core *core)
 {
        bool ret = false;
        return clk_core_is_prepared(hw->core);
 }
 
+bool clk_hw_rate_is_protected(const struct clk_hw *hw)
+{
+       return clk_core_rate_is_protected(hw->core);
+}
+
 bool clk_hw_is_enabled(const struct clk_hw *hw)
 {
        return clk_core_is_enabled(hw->core);
 
 /***        clk api        ***/
 
+static void clk_core_rate_unprotect(struct clk_core *core)
+{
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
+               return;
+
+       if (WARN_ON(core->protect_count == 0))
+               return;
+
+       if (--core->protect_count > 0)
+               return;
+
+       clk_core_rate_unprotect(core->parent);
+}
+
+static int clk_core_rate_nuke_protect(struct clk_core *core)
+{
+       int ret;
+
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
+               return -EINVAL;
+
+       if (core->protect_count == 0)
+               return 0;
+
+       ret = core->protect_count;
+       core->protect_count = 1;
+       clk_core_rate_unprotect(core);
+
+       return ret;
+}
+
+static void clk_core_rate_protect(struct clk_core *core)
+{
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
+               return;
+
+       if (core->protect_count == 0)
+               clk_core_rate_protect(core->parent);
+
+       core->protect_count++;
+}
+
+static void clk_core_rate_restore_protect(struct clk_core *core, int count)
+{
+       lockdep_assert_held(&prepare_lock);
+
+       if (!core)
+               return;
+
+       if (count == 0)
+               return;
+
+       clk_core_rate_protect(core);
+       core->protect_count = count;
+}
+
 static void clk_core_unprepare(struct clk_core *core)
 {
        lockdep_assert_held(&prepare_lock);
        if (!core)
                return 0;
 
-       if (core->ops->determine_rate) {
+       if (clk_core_rate_is_protected(core)) {
+               req->rate = core->rate;
+       } else if (core->ops->determine_rate) {
                return core->ops->determine_rate(core->hw, req);
        } else if (core->ops->round_rate) {
                rate = core->ops->round_rate(core->hw, req->rate,
 static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
                                                     unsigned long req_rate)
 {
-       int ret;
+       int ret, cnt;
        struct clk_rate_request req;
 
        lockdep_assert_held(&prepare_lock);
        if (!core)
                return 0;
 
+       /* simulate what the rate would be if it could be freely set */
+       cnt = clk_core_rate_nuke_protect(core);
+       if (cnt < 0)
+               return cnt;
+
        clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
        req.rate = req_rate;
 
        ret = clk_core_round_rate_nolock(core, &req);
 
+       /* restore the protection */
+       clk_core_rate_restore_protect(core, cnt);
+
        return ret ? 0 : req.rate;
 }
 
        if (rate == clk_core_get_rate_nolock(core))
                return 0;
 
+       /* fail on a direct rate set of a protected provider */
+       if (clk_core_rate_is_protected(core))
+               return -EBUSY;
+
        if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
                return -EBUSY;
 
        if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
                return -EBUSY;
 
+       if (clk_core_rate_is_protected(core))
+               return -EBUSY;
+
        /* try finding the new parent index */
        if (parent) {
                p_index = clk_fetch_parent_index(core, parent);
        if (!core)
                return 0;
 
+       if (clk_core_rate_is_protected(core))
+               return -EBUSY;
+
        trace_clk_set_phase(core, degrees);
 
        if (core->ops->set_phase)
        if (!c)
                return;
 
-       seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
+       seq_printf(s, "%*s%-*s %11d %12d %12d %11lu %10lu %-3d\n",
                   level * 3 + 1, "",
                   30 - level * 3, c->name,
-                  c->enable_count, c->prepare_count, clk_core_get_rate(c),
-                  clk_core_get_accuracy(c), clk_core_get_phase(c));
+                  c->enable_count, c->prepare_count, c->protect_count,
+                  clk_core_get_rate(c), clk_core_get_accuracy(c),
+                  clk_core_get_phase(c));
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
        struct clk_core *c;
        struct hlist_head **lists = (struct hlist_head **)s->private;
 
-       seq_puts(s, "   clock                         enable_cnt  prepare_cnt        rate   accuracy   phase\n");
-       seq_puts(s, "----------------------------------------------------------------------------------------\n");
+       seq_puts(s, "   clock                         enable_cnt  prepare_cnt  protect_cnt        rate   accuracy   phase\n");
+       seq_puts(s, "----------------------------------------------------------------------------------------------------\n");
 
        clk_prepare_lock();
 
        seq_printf(s, "\"%s\": { ", c->name);
        seq_printf(s, "\"enable_count\": %d,", c->enable_count);
        seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+       seq_printf(s, "\"protect_count\": %d,", c->protect_count);
        seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
        seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
        seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
        if (!d)
                goto err_out;
 
+       d = debugfs_create_u32("clk_protect_count", S_IRUGO, core->dentry,
+                       (u32 *)&core->protect_count);
+       if (!d)
+               goto err_out;
+
        d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry,
                        (u32 *)&core->notifier_count);
        if (!d)
        if (clk->core->prepare_count)
                pr_warn("%s: unregistering prepared clock: %s\n",
                                        __func__, clk->core->name);
+
+       if (clk->core->protect_count)
+               pr_warn("%s: unregistering protected clock: %s\n",
+                                       __func__, clk->core->name);
+
        kref_put(&clk->core->ref, __clk_release);
 unlock:
        clk_prepare_unlock();