/* * Standard clock functions defined in include/linux/clk.h */ int clk_enable(struct clk *clk) { int ret = 0; unsigned long flags; struct clk *parent; if (!clk) return 0; spin_lock_irqsave(&clk->lock, flags); if (clk->count == 0) { parent = clk_get_parent(clk); if (!(clk->flags&CLKFLAG_IGNORE)) { ret = clk_enable(parent); if (ret) goto err_enable_parent; ret = clk_enable(clk->depends); if (ret) goto err_enable_depends; } ret = vote_rate_vdd(clk, clk->rate); if (ret) goto err_vote_vdd; if (clk->ops->enable) ret = clk->ops->enable(clk); if (ret) goto err_enable_clock; /*added by htc for clock debugging*/ if (!(clk->flags&CLKFLAG_IGNORE)) { spin_lock(&clk_enable_list_lock); list_add(&clk->enable_list, &clk_enable_list); spin_unlock(&clk_enable_list_lock); } } else if (clk->flags & CLKFLAG_HANDOFF_RATE) { /* * The clock was already enabled by handoff code so there is no * need to enable it again here. Clearing the handoff flag will * prevent the lateinit handoff code from disabling the clock if * a client driver still has it enabled. */ clk->flags &= ~CLKFLAG_HANDOFF_RATE; goto out; } clk->count++; out: spin_unlock_irqrestore(&clk->lock, flags); return 0; err_enable_clock: unvote_rate_vdd(clk, clk->rate); err_vote_vdd: clk_disable(clk->depends); err_enable_depends: clk_disable(parent); err_enable_parent: spin_unlock_irqrestore(&clk->lock, flags); return ret; }
/* * Standard clock functions defined in include/linux/clk.h */ int clk_enable(struct clk *clk) { int ret = 0; unsigned long flags; struct clk *parent; if (!clk) return 0; if (IS_ERR(clk)) return -EINVAL; spin_lock_irqsave(&clk->lock, flags); if (WARN(!clk->warned && !clk->prepare_count, "%s: Don't call enable on unprepared clocks\n", clk->dbg_name)) clk->warned = true; if (clk->count == 0) { parent = clk_get_parent(clk); ret = clk_enable(parent); if (ret) goto err_enable_parent; ret = clk_enable(clk->depends); if (ret) goto err_enable_depends; ret = vote_rate_vdd(clk, clk->rate); if (ret) goto err_vote_vdd; trace_clock_enable(clk->dbg_name, 1, smp_processor_id()); if (clk->ops->enable) ret = clk->ops->enable(clk); if (ret) goto err_enable_clock; } else if (clk->flags & CLKFLAG_HANDOFF_RATE) { /* * The clock was already enabled by handoff code so there is no * need to enable it again here. Clearing the handoff flag will * prevent the lateinit handoff code from disabling the clock if * a client driver still has it enabled. */ clk->flags &= ~CLKFLAG_HANDOFF_RATE; goto out; } clk->count++; out: spin_unlock_irqrestore(&clk->lock, flags); return 0; err_enable_clock: unvote_rate_vdd(clk, clk->rate); err_vote_vdd: clk_disable(clk->depends); err_enable_depends: clk_disable(parent); err_enable_parent: spin_unlock_irqrestore(&clk->lock, flags); return ret; }
int clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long start_rate, flags; int rc; if (IS_ERR_OR_NULL(clk)) return -EINVAL; if (!clk->ops->set_rate) return -ENOSYS; spin_lock_irqsave(&clk->lock, flags); trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id()); if (clk->count) { start_rate = clk->rate; /* Enforce vdd requirements for target frequency. */ rc = vote_rate_vdd(clk, rate); if (rc) goto err_vote_vdd; rc = clk->ops->set_rate(clk, rate); if (rc) goto err_set_rate; /* Release vdd requirements for starting frequency. */ unvote_rate_vdd(clk, start_rate); } else { rc = clk->ops->set_rate(clk, rate); } if (!rc) clk->rate = rate; spin_unlock_irqrestore(&clk->lock, flags); return rc; err_set_rate: unvote_rate_vdd(clk, rate); err_vote_vdd: spin_unlock_irqrestore(&clk->lock, flags); return rc; }
static int _clk_set_rate(struct clk *clk, unsigned long rate, int (*set_fn)(struct clk *, unsigned long)) { unsigned long start_rate, flags; int rc; if (!set_fn) return -ENOSYS; spin_lock_irqsave(&clk->lock, flags); if (clk->count) { start_rate = clk->rate; /* Enforce vdd requirements for target frequency. */ rc = vote_rate_vdd(clk, rate); if (rc) goto err_vote_vdd; rc = set_fn(clk, rate); if (rc) goto err_set_rate; /* Release vdd requirements for starting frequency. */ unvote_rate_vdd(clk, start_rate); } else { rc = set_fn(clk, rate); } if (!rc) clk->rate = rate; spin_unlock_irqrestore(&clk->lock, flags); return rc; err_set_rate: unvote_rate_vdd(clk, rate); err_vote_vdd: spin_unlock_irqrestore(&clk->lock, flags); return rc; }