1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2011-2017, The Linux Foundation
6 #include <linux/errno.h>
10 * slim_ctrl_clk_pause() - Called by slimbus controller to enter/exit
12 * @ctrl: controller requesting bus to be paused or woken up
13 * @wakeup: Wakeup this controller from clock pause.
14 * @restart: Restart time value per spec used for clock pause. This value
15 * isn't used when controller is to be woken up.
17 * Slimbus specification needs this sequence to turn-off clocks for the bus.
18 * The sequence involves sending 3 broadcast messages (reconfiguration
19 * sequence) to inform all devices on the bus.
20 * To exit clock-pause, controller typically wakes up active framer device.
21 * This API executes clock pause reconfiguration sequence if wakeup is false.
22 * If wakeup is true, controller's wakeup is called.
23 * For entering clock-pause, -EBUSY is returned if a message txn in pending.
25 int slim_ctrl_clk_pause(struct slim_controller
*ctrl
, bool wakeup
, u8 restart
)
29 struct slim_sched
*sched
= &ctrl
->sched
;
30 struct slim_val_inf msg
= {0, 0, NULL
, NULL
};
32 DEFINE_SLIM_BCAST_TXN(txn
, SLIM_MSG_MC_BEGIN_RECONFIGURATION
,
33 3, SLIM_LA_MANAGER
, &msg
);
35 if (wakeup
== false && restart
> SLIM_CLK_UNSPECIFIED
)
38 mutex_lock(&sched
->m_reconf
);
40 if (sched
->clk_state
== SLIM_CLK_ACTIVE
) {
41 mutex_unlock(&sched
->m_reconf
);
46 * Fine-tune calculation based on clock gear,
47 * message-bandwidth after bandwidth management
49 ret
= wait_for_completion_timeout(&sched
->pause_comp
,
50 msecs_to_jiffies(100));
52 mutex_unlock(&sched
->m_reconf
);
53 pr_err("Previous clock pause did not finish");
59 * Slimbus framework will call controller wakeup
60 * Controller should make sure that it sets active framer
63 if (sched
->clk_state
== SLIM_CLK_PAUSED
&& ctrl
->wakeup
)
64 ret
= ctrl
->wakeup(ctrl
);
66 sched
->clk_state
= SLIM_CLK_ACTIVE
;
67 mutex_unlock(&sched
->m_reconf
);
73 if (ctrl
->sched
.clk_state
== SLIM_CLK_PAUSED
) {
74 mutex_unlock(&sched
->m_reconf
);
78 spin_lock_irqsave(&ctrl
->txn_lock
, flags
);
79 for (i
= 0; i
< SLIM_MAX_TIDS
; i
++) {
80 /* Pending response for a message */
81 if (idr_find(&ctrl
->tid_idr
, i
)) {
82 spin_unlock_irqrestore(&ctrl
->txn_lock
, flags
);
83 mutex_unlock(&sched
->m_reconf
);
87 spin_unlock_irqrestore(&ctrl
->txn_lock
, flags
);
89 sched
->clk_state
= SLIM_CLK_ENTERING_PAUSE
;
91 /* clock pause sequence */
92 ret
= slim_do_transfer(ctrl
, &txn
);
96 txn
.mc
= SLIM_MSG_MC_NEXT_PAUSE_CLOCK
;
100 ret
= slim_do_transfer(ctrl
, &txn
);
104 txn
.mc
= SLIM_MSG_MC_RECONFIGURE_NOW
;
108 ret
= slim_do_transfer(ctrl
, &txn
);
112 sched
->clk_state
= SLIM_CLK_ACTIVE
;
114 sched
->clk_state
= SLIM_CLK_PAUSED
;
115 complete(&sched
->pause_comp
);
117 mutex_unlock(&sched
->m_reconf
);
121 EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause
);