static void rpm_clk_disable(struct clk *clk) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); spin_lock_irqsave(&rpm_clock_lock, flags); if (r->last_set_khz) { uint32_t value; struct rpm_clk *peer = r->peer; unsigned long peer_khz = 0, peer_sleep_khz = 0; int rc; if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = r->branch ? !!peer_khz : peer_khz; rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = r->branch ? !!peer_sleep_khz : peer_sleep_khz; rc = clk_rpmrs_set_rate_sleep_noirq(r, value); } r->enabled = false; out: spin_unlock_irqrestore(&rpm_clock_lock, flags); return; }
static int rpm_clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); unsigned long this_khz, this_sleep_khz; int rc = 0; this_khz = DIV_ROUND_UP(rate, r->factor); spin_lock_irqsave(&rpm_clock_lock, flags); /* Active-only clocks don't care what the rate is during sleep. So, * they vote for zero. */ if (r->active_only) this_sleep_khz = 0; else this_sleep_khz = this_khz; if (r->enabled) { uint32_t value; struct rpm_clk *peer = r->peer; unsigned long peer_khz = 0, peer_sleep_khz = 0; /* Take peer clock's rate into account only if it's enabled. */ if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = max(this_khz, peer_khz); rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = max(this_sleep_khz, peer_sleep_khz); rc = clk_rpmrs_set_rate_sleep_noirq(r, value); } if (!rc) { r->last_set_khz = this_khz; r->last_set_sleep_khz = this_sleep_khz; } out: spin_unlock_irqrestore(&rpm_clock_lock, flags); return rc; }
static int rpm_clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); unsigned long this_khz, this_sleep_khz; int rc = 0; this_khz = DIV_ROUND_UP(rate, r->factor); spin_lock_irqsave(&rpm_clock_lock, flags); if (r->active_only) this_sleep_khz = 0; else this_sleep_khz = this_khz; if (r->enabled) { uint32_t value; struct rpm_clk *peer = r->peer; unsigned long peer_khz = 0, peer_sleep_khz = 0; if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = max(this_khz, peer_khz); rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = max(this_sleep_khz, peer_sleep_khz); rc = clk_rpmrs_set_rate_sleep_noirq(r, value); } if (!rc) { r->last_set_khz = this_khz; r->last_set_sleep_khz = this_sleep_khz; } out: spin_unlock_irqrestore(&rpm_clock_lock, flags); return rc; }
static int clk_rpmrs_set_rate(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq) { struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id, .value = value, }; if (noirq) return msm_rpmrs_set_noirq(context, &iv, 1); else return msm_rpmrs_set(context, &iv, 1); } static int clk_rpmrs_get_rate(struct rpm_clk *r) { int rc; struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, }; rc = msm_rpm_get_status(&iv, 1); return (rc < 0) ? rc : iv.value * r->factor; } static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq) { struct msm_rpm_kvp kvp = { .key = r->rpm_key, .data = (void *)&value, .length = sizeof(value), }; if (noirq) return msm_rpm_send_message_noirq(context, r->rpm_res_type, r->rpm_clk_id, &kvp, 1); else return msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id, &kvp, 1); } struct clk_rpmrs_data { int (*set_rate_fn)(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq); int (*get_rate_fn)(struct rpm_clk *r); int ctx_active_id; int ctx_sleep_id; }; struct clk_rpmrs_data clk_rpmrs_data = { .set_rate_fn = clk_rpmrs_set_rate, .get_rate_fn = clk_rpmrs_get_rate, .ctx_active_id = MSM_RPM_CTX_SET_0, .ctx_sleep_id = MSM_RPM_CTX_SET_SLEEP, }; struct clk_rpmrs_data clk_rpmrs_data_smd = { .set_rate_fn = clk_rpmrs_set_rate_smd, .ctx_active_id = MSM_RPM_CTX_ACTIVE_SET, .ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET, }; static DEFINE_SPINLOCK(rpm_clock_lock); static int rpm_clk_enable(struct clk *clk) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); uint32_t value; int rc = 0; unsigned long this_khz, this_sleep_khz; unsigned long peer_khz = 0, peer_sleep_khz = 0; struct rpm_clk *peer = r->peer; spin_lock_irqsave(&rpm_clock_lock, flags); this_khz = r->last_set_khz; /* Don't send requests to the RPM if the rate has not been set. */ if (this_khz == 0) goto out; this_sleep_khz = r->last_set_sleep_khz; /* Take peer clock's rate into account only if it's enabled. */ if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = max(this_khz, peer_khz); if (r->branch) value = !!value; rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = max(this_sleep_khz, peer_sleep_khz); if (r->branch) value = !!value; rc = clk_rpmrs_set_rate_sleep_noirq(r, value); if (rc) { /* Undo the active set vote and restore it to peer_khz */ value = peer_khz; rc = clk_rpmrs_set_rate_active_noirq(r, value); } out: if (!rc) r->enabled = true; spin_unlock_irqrestore(&rpm_clock_lock, flags); return rc; } static void rpm_clk_disable(struct clk *clk) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); spin_lock_irqsave(&rpm_clock_lock, flags); if (r->last_set_khz) { uint32_t value; struct rpm_clk *peer = r->peer; unsigned long peer_khz = 0, peer_sleep_khz = 0; int rc; /* Take peer clock's rate into account only if it's enabled. */ if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = r->branch ? !!peer_khz : peer_khz; rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = r->branch ? !!peer_sleep_khz : peer_sleep_khz; rc = clk_rpmrs_set_rate_sleep_noirq(r, value); } r->enabled = false; out: spin_unlock_irqrestore(&rpm_clock_lock, flags); return; }
static int clk_rpmrs_set_rate(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq) { struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id, .value = value, }; if (noirq) return msm_rpmrs_set_noirq(context, &iv, 1); else return msm_rpmrs_set(context, &iv, 1); } static int clk_rpmrs_get_rate(struct rpm_clk *r) { int rc; struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, }; rc = msm_rpm_get_status(&iv, 1); return (rc < 0) ? rc : iv.value * r->factor; } #define RPM_SMD_KEY_RATE 0x007A484B #define RPM_SMD_KEY_ENABLE 0x62616E45 static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq) { u32 rpm_key = r->branch ? RPM_SMD_KEY_ENABLE : RPM_SMD_KEY_RATE; struct msm_rpm_kvp kvp = { .key = rpm_key, .data = (void *)&value, .length = sizeof(value), }; if (noirq) return msm_rpm_send_message_noirq(context, r->rpm_res_type, r->rpm_clk_id, &kvp, 1); else return msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id, &kvp, 1); } struct clk_rpmrs_data { int (*set_rate_fn)(struct rpm_clk *r, uint32_t value, uint32_t context, int noirq); int (*get_rate_fn)(struct rpm_clk *r); int ctx_active_id; int ctx_sleep_id; }; struct clk_rpmrs_data clk_rpmrs_data = { .set_rate_fn = clk_rpmrs_set_rate, .get_rate_fn = clk_rpmrs_get_rate, .ctx_active_id = MSM_RPM_CTX_SET_0, .ctx_sleep_id = MSM_RPM_CTX_SET_SLEEP, }; struct clk_rpmrs_data clk_rpmrs_data_smd = { .set_rate_fn = clk_rpmrs_set_rate_smd, .ctx_active_id = MSM_RPM_CTX_ACTIVE_SET, .ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET, }; static DEFINE_SPINLOCK(rpm_clock_lock); static int rpm_clk_enable(struct clk *clk) { unsigned long flags; struct rpm_clk *r = to_rpm_clk(clk); uint32_t value; int rc = 0; unsigned long this_khz, this_sleep_khz; unsigned long peer_khz = 0, peer_sleep_khz = 0; struct rpm_clk *peer = r->peer; spin_lock_irqsave(&rpm_clock_lock, flags); this_khz = r->last_set_khz; if (this_khz == 0) goto out; this_sleep_khz = r->last_set_sleep_khz; if (peer->enabled) { peer_khz = peer->last_set_khz; peer_sleep_khz = peer->last_set_sleep_khz; } value = max(this_khz, peer_khz); if (r->branch) value = !!value; rc = clk_rpmrs_set_rate_active_noirq(r, value); if (rc) goto out; value = max(this_sleep_khz, peer_sleep_khz); if (r->branch) value = !!value; rc = clk_rpmrs_set_rate_sleep_noirq(r, value); if (rc) { value = peer_khz; rc = clk_rpmrs_set_rate_active_noirq(r, value); } out: if (!rc) r->enabled = true; spin_unlock_irqrestore(&rpm_clock_lock, flags); return rc; }