|
@@ -8,7 +8,9 @@
|
|
|
* the License, or (at your option) any later version.
|
|
|
*/
|
|
|
|
|
|
+#include <linux/clk.h>
|
|
|
#include <linux/clk-provider.h>
|
|
|
+#include <linux/delay.h>
|
|
|
|
|
|
#include "ccu_gate.h"
|
|
|
#include "ccu_mux.h"
|
|
@@ -199,3 +201,37 @@ const struct clk_ops ccu_mux_ops = {
|
|
|
.determine_rate = __clk_mux_determine_rate,
|
|
|
.recalc_rate = ccu_mux_recalc_rate,
|
|
|
};
|
|
|
+
|
|
|
+/*
|
|
|
+ * This clock notifier is called when the frequency of the of the parent
|
|
|
+ * PLL clock is to be changed. The idea is to switch the parent to a
|
|
|
+ * stable clock, such as the main oscillator, while the PLL frequency
|
|
|
+ * stabilizes.
|
|
|
+ */
|
|
|
+static int ccu_mux_notifier_cb(struct notifier_block *nb,
|
|
|
+ unsigned long event, void *data)
|
|
|
+{
|
|
|
+ struct ccu_mux_nb *mux = to_ccu_mux_nb(nb);
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (event == PRE_RATE_CHANGE) {
|
|
|
+ mux->original_index = ccu_mux_helper_get_parent(mux->common,
|
|
|
+ mux->cm);
|
|
|
+ ret = ccu_mux_helper_set_parent(mux->common, mux->cm,
|
|
|
+ mux->bypass_index);
|
|
|
+ } else if (event == POST_RATE_CHANGE) {
|
|
|
+ ret = ccu_mux_helper_set_parent(mux->common, mux->cm,
|
|
|
+ mux->original_index);
|
|
|
+ }
|
|
|
+
|
|
|
+ udelay(mux->delay_us);
|
|
|
+
|
|
|
+ return notifier_from_errno(ret);
|
|
|
+}
|
|
|
+
|
|
|
+int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb)
|
|
|
+{
|
|
|
+ mux_nb->clk_nb.notifier_call = ccu_mux_notifier_cb;
|
|
|
+
|
|
|
+ return clk_notifier_register(clk, &mux_nb->clk_nb);
|
|
|
+}
|