0001
0002
0003
0004
0005
0006 #include <linux/errno.h>
0007 #include "slimbus.h"
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
0026 {
0027 int i, ret = 0;
0028 unsigned long flags;
0029 struct slim_sched *sched = &ctrl->sched;
0030 struct slim_val_inf msg = {0, 0, NULL, NULL};
0031
0032 DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
0033 3, SLIM_LA_MANAGER, &msg);
0034
0035 if (wakeup == false && restart > SLIM_CLK_UNSPECIFIED)
0036 return -EINVAL;
0037
0038 mutex_lock(&sched->m_reconf);
0039 if (wakeup) {
0040 if (sched->clk_state == SLIM_CLK_ACTIVE) {
0041 mutex_unlock(&sched->m_reconf);
0042 return 0;
0043 }
0044
0045
0046
0047
0048
0049 ret = wait_for_completion_timeout(&sched->pause_comp,
0050 msecs_to_jiffies(100));
0051 if (!ret) {
0052 mutex_unlock(&sched->m_reconf);
0053 pr_err("Previous clock pause did not finish");
0054 return -ETIMEDOUT;
0055 }
0056 ret = 0;
0057
0058
0059
0060
0061
0062
0063 if (sched->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
0064 ret = ctrl->wakeup(ctrl);
0065 if (!ret)
0066 sched->clk_state = SLIM_CLK_ACTIVE;
0067 mutex_unlock(&sched->m_reconf);
0068
0069 return ret;
0070 }
0071
0072
0073 if (ctrl->sched.clk_state == SLIM_CLK_PAUSED) {
0074 mutex_unlock(&sched->m_reconf);
0075 return 0;
0076 }
0077
0078 spin_lock_irqsave(&ctrl->txn_lock, flags);
0079 for (i = 0; i < SLIM_MAX_TIDS; i++) {
0080
0081 if (idr_find(&ctrl->tid_idr, i)) {
0082 spin_unlock_irqrestore(&ctrl->txn_lock, flags);
0083 mutex_unlock(&sched->m_reconf);
0084 return -EBUSY;
0085 }
0086 }
0087 spin_unlock_irqrestore(&ctrl->txn_lock, flags);
0088
0089 sched->clk_state = SLIM_CLK_ENTERING_PAUSE;
0090
0091
0092 ret = slim_do_transfer(ctrl, &txn);
0093 if (ret)
0094 goto clk_pause_ret;
0095
0096 txn.mc = SLIM_MSG_MC_NEXT_PAUSE_CLOCK;
0097 txn.rl = 4;
0098 msg.num_bytes = 1;
0099 msg.wbuf = &restart;
0100 ret = slim_do_transfer(ctrl, &txn);
0101 if (ret)
0102 goto clk_pause_ret;
0103
0104 txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
0105 txn.rl = 3;
0106 msg.num_bytes = 1;
0107 msg.wbuf = NULL;
0108 ret = slim_do_transfer(ctrl, &txn);
0109
0110 clk_pause_ret:
0111 if (ret) {
0112 sched->clk_state = SLIM_CLK_ACTIVE;
0113 } else {
0114 sched->clk_state = SLIM_CLK_PAUSED;
0115 complete(&sched->pause_comp);
0116 }
0117 mutex_unlock(&sched->m_reconf);
0118
0119 return ret;
0120 }
0121 EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);