diff options
author | Alex Elder <elder@linaro.org> | 2014-04-21 17:11:43 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-04-30 14:51:38 -0400 |
commit | dc613840a625bfad38141d2d8bbdb0c7bc3d45eb (patch) | |
tree | 9cc26fa89833eee39df05a074cbcf8eb414d023d | |
parent | a597faccc7eedd406313e880ed05ff75bc522910 (diff) |
clk: bcm281xx: add clock hysteresis support
Add support for clock gate hysteresis control. For now, if it's
defined for a clock, it's enabled.
Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/bcm/clk-kona-setup.c | 30 | ||||
-rw-r--r-- | drivers/clk/bcm/clk-kona.c | 33 | ||||
-rw-r--r-- | drivers/clk/bcm/clk-kona.h | 19 |
3 files changed, 82 insertions, 0 deletions
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 773ad7c7dd59..e5aededdd322 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c | |||
@@ -81,6 +81,7 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | |||
81 | struct peri_clk_data *peri; | 81 | struct peri_clk_data *peri; |
82 | struct bcm_clk_policy *policy; | 82 | struct bcm_clk_policy *policy; |
83 | struct bcm_clk_gate *gate; | 83 | struct bcm_clk_gate *gate; |
84 | struct bcm_clk_hyst *hyst; | ||
84 | struct bcm_clk_div *div; | 85 | struct bcm_clk_div *div; |
85 | struct bcm_clk_sel *sel; | 86 | struct bcm_clk_sel *sel; |
86 | struct bcm_clk_trig *trig; | 87 | struct bcm_clk_trig *trig; |
@@ -106,12 +107,25 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) | |||
106 | } | 107 | } |
107 | 108 | ||
108 | gate = &peri->gate; | 109 | gate = &peri->gate; |
110 | hyst = &peri->hyst; | ||
109 | if (gate_exists(gate)) { | 111 | if (gate_exists(gate)) { |
110 | if (gate->offset > limit) { | 112 | if (gate->offset > limit) { |
111 | pr_err("%s: bad gate offset for %s (%u > %u)\n", | 113 | pr_err("%s: bad gate offset for %s (%u > %u)\n", |
112 | __func__, name, gate->offset, limit); | 114 | __func__, name, gate->offset, limit); |
113 | return false; | 115 | return false; |
114 | } | 116 | } |
117 | |||
118 | if (hyst_exists(hyst)) { | ||
119 | if (hyst->offset > limit) { | ||
120 | pr_err("%s: bad hysteresis offset for %s " | ||
121 | "(%u > %u)\n", __func__, | ||
122 | name, hyst->offset, limit); | ||
123 | return false; | ||
124 | } | ||
125 | } | ||
126 | } else if (hyst_exists(hyst)) { | ||
127 | pr_err("%s: hysteresis but no gate for %s\n", __func__, name); | ||
128 | return false; | ||
115 | } | 129 | } |
116 | 130 | ||
117 | div = &peri->div; | 131 | div = &peri->div; |
@@ -261,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name, | |||
261 | return true; | 275 | return true; |
262 | } | 276 | } |
263 | 277 | ||
278 | static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name) | ||
279 | { | ||
280 | if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name)) | ||
281 | return false; | ||
282 | |||
283 | if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name)) | ||
284 | return false; | ||
285 | |||
286 | return true; | ||
287 | } | ||
288 | |||
264 | /* | 289 | /* |
265 | * A selector bitfield must be valid. Its parent_sel array must | 290 | * A selector bitfield must be valid. Its parent_sel array must |
266 | * also be reasonable for the field. | 291 | * also be reasonable for the field. |
@@ -379,6 +404,7 @@ peri_clk_data_valid(struct kona_clk *bcm_clk) | |||
379 | struct peri_clk_data *peri; | 404 | struct peri_clk_data *peri; |
380 | struct bcm_clk_policy *policy; | 405 | struct bcm_clk_policy *policy; |
381 | struct bcm_clk_gate *gate; | 406 | struct bcm_clk_gate *gate; |
407 | struct bcm_clk_hyst *hyst; | ||
382 | struct bcm_clk_sel *sel; | 408 | struct bcm_clk_sel *sel; |
383 | struct bcm_clk_div *div; | 409 | struct bcm_clk_div *div; |
384 | struct bcm_clk_div *pre_div; | 410 | struct bcm_clk_div *pre_div; |
@@ -406,6 +432,10 @@ peri_clk_data_valid(struct kona_clk *bcm_clk) | |||
406 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) | 432 | if (gate_exists(gate) && !gate_valid(gate, "gate", name)) |
407 | return false; | 433 | return false; |
408 | 434 | ||
435 | hyst = &peri->hyst; | ||
436 | if (hyst_exists(hyst) && !hyst_valid(hyst, name)) | ||
437 | return false; | ||
438 | |||
409 | sel = &peri->sel; | 439 | sel = &peri->sel; |
410 | if (selector_exists(sel)) { | 440 | if (selector_exists(sel)) { |
411 | if (!sel_valid(sel, "selector", name)) | 441 | if (!sel_valid(sel, "selector", name)) |
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 7d90c34d1336..d603c4e22fca 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c | |||
@@ -527,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name, | |||
527 | return -EIO; | 527 | return -EIO; |
528 | } | 528 | } |
529 | 529 | ||
530 | /* Hysteresis operations */ | ||
531 | |||
532 | /* | ||
533 | * If a clock gate requires a turn-off delay it will have | ||
534 | * "hysteresis" register bits defined. The first, if set, enables | ||
535 | * the delay; and if enabled, the second bit determines whether the | ||
536 | * delay is "low" or "high" (1 means high). For now, if it's | ||
537 | * defined for a clock, we set it. | ||
538 | */ | ||
539 | static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst) | ||
540 | { | ||
541 | u32 offset; | ||
542 | u32 reg_val; | ||
543 | u32 mask; | ||
544 | |||
545 | if (!hyst_exists(hyst)) | ||
546 | return true; | ||
547 | |||
548 | offset = hyst->offset; | ||
549 | mask = (u32)1 << hyst->en_bit; | ||
550 | mask |= (u32)1 << hyst->val_bit; | ||
551 | |||
552 | reg_val = __ccu_read(ccu, offset); | ||
553 | reg_val |= mask; | ||
554 | __ccu_write(ccu, offset, reg_val); | ||
555 | |||
556 | return true; | ||
557 | } | ||
558 | |||
530 | /* Trigger operations */ | 559 | /* Trigger operations */ |
531 | 560 | ||
532 | /* | 561 | /* |
@@ -1131,6 +1160,10 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk) | |||
1131 | pr_err("%s: error initializing gate for %s\n", __func__, name); | 1160 | pr_err("%s: error initializing gate for %s\n", __func__, name); |
1132 | return false; | 1161 | return false; |
1133 | } | 1162 | } |
1163 | if (!hyst_init(ccu, &peri->hyst)) { | ||
1164 | pr_err("%s: error initializing hyst for %s\n", __func__, name); | ||
1165 | return false; | ||
1166 | } | ||
1134 | if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { | 1167 | if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { |
1135 | pr_err("%s: error initializing divider for %s\n", __func__, | 1168 | pr_err("%s: error initializing divider for %s\n", __func__, |
1136 | name); | 1169 | name); |
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index 4bcba1331561..2537b3072910 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h | |||
@@ -60,6 +60,8 @@ | |||
60 | 60 | ||
61 | #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) | 61 | #define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) |
62 | 62 | ||
63 | #define hyst_exists(hyst) ((hyst)->offset != 0) | ||
64 | |||
63 | #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) | 65 | #define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) |
64 | #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) | 66 | #define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) |
65 | #define divider_has_fraction(div) (!divider_is_fixed(div) && \ | 67 | #define divider_has_fraction(div) (!divider_is_fixed(div) && \ |
@@ -205,6 +207,22 @@ struct bcm_clk_gate { | |||
205 | .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ | 207 | .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ |
206 | } | 208 | } |
207 | 209 | ||
210 | /* Gate hysteresis for clocks */ | ||
211 | struct bcm_clk_hyst { | ||
212 | u32 offset; /* hyst register offset (normally CLKGATE) */ | ||
213 | u32 en_bit; /* bit used to enable hysteresis */ | ||
214 | u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */ | ||
215 | }; | ||
216 | |||
217 | /* Hysteresis initialization macro */ | ||
218 | |||
219 | #define HYST(_offset, _en_bit, _val_bit) \ | ||
220 | { \ | ||
221 | .offset = (_offset), \ | ||
222 | .en_bit = (_en_bit), \ | ||
223 | .val_bit = (_val_bit), \ | ||
224 | } | ||
225 | |||
208 | /* | 226 | /* |
209 | * Each clock can have zero, one, or two dividers which change the | 227 | * Each clock can have zero, one, or two dividers which change the |
210 | * output rate of the clock. Each divider can be either fixed or | 228 | * output rate of the clock. Each divider can be either fixed or |
@@ -372,6 +390,7 @@ struct bcm_clk_trig { | |||
372 | struct peri_clk_data { | 390 | struct peri_clk_data { |
373 | struct bcm_clk_policy policy; | 391 | struct bcm_clk_policy policy; |
374 | struct bcm_clk_gate gate; | 392 | struct bcm_clk_gate gate; |
393 | struct bcm_clk_hyst hyst; | ||
375 | struct bcm_clk_trig pre_trig; | 394 | struct bcm_clk_trig pre_trig; |
376 | struct bcm_clk_div pre_div; | 395 | struct bcm_clk_div pre_div; |
377 | struct bcm_clk_trig trig; | 396 | struct bcm_clk_trig trig; |