Skip to content

Commit fc8726a

Browse files
Dong Aishengbebarino
authored andcommitted
clk: core: support clocks which requires parents enable (part 2)
On Freescale i.MX7D platform, all clocks operations, including enable/disable, rate change and re-parent, requires its parent clock on. Current clock core can not support it well. This patch adding flag CLK_OPS_PARENT_ENABLE to handle this special case in clock core that enable its parent clock firstly for each operation and disable it later after operation complete. The patch part 2 fixes set clock rate and set parent while its parent is off. The most special case is for set_parent() operation which requires all parents including both old and new one to be enabled at the same time during the operation. Cc: Michael Turquette <[email protected]> Cc: Stephen Boyd <[email protected]> Cc: Shawn Guo <[email protected]> Signed-off-by: Dong Aisheng <[email protected]> [[email protected]: Move set_rate tracepoint after prepare_enable] Signed-off-by: Stephen Boyd <[email protected]>
1 parent a4b3518 commit fc8726a

File tree

1 file changed

+33
-15
lines changed

1 file changed

+33
-15
lines changed

drivers/clk/clk.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,9 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core,
11721172
struct clk_core *old_parent = core->parent;
11731173

11741174
/*
1175-
* Migrate prepare state between parents and prevent race with
1175+
* 1. enable parents for CLK_OPS_PARENT_ENABLE clock
1176+
*
1177+
* 2. Migrate prepare state between parents and prevent race with
11761178
* clk_enable().
11771179
*
11781180
* If the clock is not prepared, then a race with
@@ -1188,12 +1190,17 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core,
11881190
*
11891191
* See also: Comment for clk_set_parent() below.
11901192
*/
1193+
1194+
/* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */
1195+
if (core->flags & CLK_OPS_PARENT_ENABLE) {
1196+
clk_core_prepare_enable(old_parent);
1197+
clk_core_prepare_enable(parent);
1198+
}
1199+
1200+
/* migrate prepare count if > 0 */
11911201
if (core->prepare_count) {
1192-
clk_core_prepare(parent);
1193-
flags = clk_enable_lock();
1194-
clk_core_enable(parent);
1195-
clk_core_enable(core);
1196-
clk_enable_unlock(flags);
1202+
clk_core_prepare_enable(parent);
1203+
clk_core_enable_lock(core);
11971204
}
11981205

11991206
/* update the clk tree topology */
@@ -1208,18 +1215,19 @@ static void __clk_set_parent_after(struct clk_core *core,
12081215
struct clk_core *parent,
12091216
struct clk_core *old_parent)
12101217
{
1211-
unsigned long flags;
1212-
12131218
/*
12141219
* Finish the migration of prepare state and undo the changes done
12151220
* for preventing a race with clk_enable().
12161221
*/
12171222
if (core->prepare_count) {
1218-
flags = clk_enable_lock();
1219-
clk_core_disable(core);
1220-
clk_core_disable(old_parent);
1221-
clk_enable_unlock(flags);
1222-
clk_core_unprepare(old_parent);
1223+
clk_core_disable_lock(core);
1224+
clk_core_disable_unprepare(old_parent);
1225+
}
1226+
1227+
/* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */
1228+
if (core->flags & CLK_OPS_PARENT_ENABLE) {
1229+
clk_core_disable_unprepare(parent);
1230+
clk_core_disable_unprepare(old_parent);
12231231
}
12241232
}
12251233

@@ -1466,13 +1474,17 @@ static void clk_change_rate(struct clk_core *core)
14661474
unsigned long best_parent_rate = 0;
14671475
bool skip_set_rate = false;
14681476
struct clk_core *old_parent;
1477+
struct clk_core *parent = NULL;
14691478

14701479
old_rate = core->rate;
14711480

1472-
if (core->new_parent)
1481+
if (core->new_parent) {
1482+
parent = core->new_parent;
14731483
best_parent_rate = core->new_parent->rate;
1474-
else if (core->parent)
1484+
} else if (core->parent) {
1485+
parent = core->parent;
14751486
best_parent_rate = core->parent->rate;
1487+
}
14761488

14771489
if (core->flags & CLK_SET_RATE_UNGATE) {
14781490
unsigned long flags;
@@ -1500,6 +1512,9 @@ static void clk_change_rate(struct clk_core *core)
15001512
__clk_set_parent_after(core, core->new_parent, old_parent);
15011513
}
15021514

1515+
if (core->flags & CLK_OPS_PARENT_ENABLE)
1516+
clk_core_prepare_enable(parent);
1517+
15031518
trace_clk_set_rate(core, core->new_rate);
15041519

15051520
if (!skip_set_rate && core->ops->set_rate)
@@ -1518,6 +1533,9 @@ static void clk_change_rate(struct clk_core *core)
15181533
clk_core_unprepare(core);
15191534
}
15201535

1536+
if (core->flags & CLK_OPS_PARENT_ENABLE)
1537+
clk_core_disable_unprepare(parent);
1538+
15211539
if (core->notifier_count && old_rate != core->rate)
15221540
__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
15231541

0 commit comments

Comments
 (0)