diff options
| author | Tero Kristo <t-kristo@ti.com> | 2018-02-15 02:49:27 -0500 |
|---|---|---|
| committer | Tero Kristo <t-kristo@ti.com> | 2018-03-08 04:42:04 -0500 |
| commit | b44a03008da5e20e24c0d11d566796fb9b0f912e (patch) | |
| tree | ff7b2093df05aff4cd0c4fc72148684fa15a26f1 | |
| parent | e31922eda18c950d6b51450711ae459b97eae097 (diff) | |
clk: ti: add support for clock latching to divider clocks
Latching the clock settings is needed with certain clocks, where
the setting is "cached" in HW before doing the actual re-programming
of the clock source. This patch adds support for clock latching to
the divider clock.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
| -rw-r--r-- | drivers/clk/ti/clock.h | 1 | ||||
| -rw-r--r-- | drivers/clk/ti/divider.c | 26 |
2 files changed, 21 insertions, 6 deletions
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 2f8af8fd886a..62b108cc10de 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h | |||
| @@ -22,6 +22,7 @@ struct clk_omap_divider { | |||
| 22 | u8 shift; | 22 | u8 shift; |
| 23 | u8 width; | 23 | u8 width; |
| 24 | u8 flags; | 24 | u8 flags; |
| 25 | s8 latch; | ||
| 25 | const struct clk_div_table *table; | 26 | const struct clk_div_table *table; |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 77f93f6d2806..aaa277dd6d99 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c | |||
| @@ -263,6 +263,8 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 263 | val |= value << divider->shift; | 263 | val |= value << divider->shift; |
| 264 | ti_clk_ll_ops->clk_writel(val, ÷r->reg); | 264 | ti_clk_ll_ops->clk_writel(val, ÷r->reg); |
| 265 | 265 | ||
| 266 | ti_clk_latch(÷r->reg, divider->latch); | ||
| 267 | |||
| 266 | return 0; | 268 | return 0; |
| 267 | } | 269 | } |
| 268 | 270 | ||
| @@ -276,7 +278,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
| 276 | const char *parent_name, | 278 | const char *parent_name, |
| 277 | unsigned long flags, | 279 | unsigned long flags, |
| 278 | struct clk_omap_reg *reg, | 280 | struct clk_omap_reg *reg, |
| 279 | u8 shift, u8 width, u8 clk_divider_flags, | 281 | u8 shift, u8 width, s8 latch, |
| 282 | u8 clk_divider_flags, | ||
| 280 | const struct clk_div_table *table) | 283 | const struct clk_div_table *table) |
| 281 | { | 284 | { |
| 282 | struct clk_omap_divider *div; | 285 | struct clk_omap_divider *div; |
| @@ -305,6 +308,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
| 305 | memcpy(&div->reg, reg, sizeof(*reg)); | 308 | memcpy(&div->reg, reg, sizeof(*reg)); |
| 306 | div->shift = shift; | 309 | div->shift = shift; |
| 307 | div->width = width; | 310 | div->width = width; |
| 311 | div->latch = latch; | ||
| 308 | div->flags = clk_divider_flags; | 312 | div->flags = clk_divider_flags; |
| 309 | div->hw.init = &init; | 313 | div->hw.init = &init; |
| 310 | div->table = table; | 314 | div->table = table; |
| @@ -420,6 +424,7 @@ struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup) | |||
| 420 | div->table = _get_div_table_from_setup(setup, &div->width); | 424 | div->table = _get_div_table_from_setup(setup, &div->width); |
| 421 | 425 | ||
| 422 | div->shift = setup->bit_shift; | 426 | div->shift = setup->bit_shift; |
| 427 | div->latch = -EINVAL; | ||
| 423 | 428 | ||
| 424 | return &div->hw; | 429 | return &div->hw; |
| 425 | } | 430 | } |
| @@ -452,7 +457,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup) | |||
| 452 | 457 | ||
| 453 | clk = _register_divider(NULL, setup->name, div->parent, | 458 | clk = _register_divider(NULL, setup->name, div->parent, |
| 454 | flags, ®, div->bit_shift, | 459 | flags, ®, div->bit_shift, |
| 455 | width, div_flags, table); | 460 | width, -EINVAL, div_flags, table); |
| 456 | 461 | ||
| 457 | if (IS_ERR(clk)) | 462 | if (IS_ERR(clk)) |
| 458 | kfree(table); | 463 | kfree(table); |
| @@ -556,7 +561,7 @@ static int _get_divider_width(struct device_node *node, | |||
| 556 | 561 | ||
| 557 | static int __init ti_clk_divider_populate(struct device_node *node, | 562 | static int __init ti_clk_divider_populate(struct device_node *node, |
| 558 | struct clk_omap_reg *reg, const struct clk_div_table **table, | 563 | struct clk_omap_reg *reg, const struct clk_div_table **table, |
| 559 | u32 *flags, u8 *div_flags, u8 *width, u8 *shift) | 564 | u32 *flags, u8 *div_flags, u8 *width, u8 *shift, s8 *latch) |
| 560 | { | 565 | { |
| 561 | u32 val; | 566 | u32 val; |
| 562 | int ret; | 567 | int ret; |
| @@ -570,6 +575,13 @@ static int __init ti_clk_divider_populate(struct device_node *node, | |||
| 570 | else | 575 | else |
| 571 | *shift = 0; | 576 | *shift = 0; |
| 572 | 577 | ||
| 578 | if (latch) { | ||
| 579 | if (!of_property_read_u32(node, "ti,latch-bit", &val)) | ||
| 580 | *latch = val; | ||
| 581 | else | ||
| 582 | *latch = -EINVAL; | ||
| 583 | } | ||
| 584 | |||
| 573 | *flags = 0; | 585 | *flags = 0; |
| 574 | *div_flags = 0; | 586 | *div_flags = 0; |
| 575 | 587 | ||
| @@ -606,17 +618,18 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) | |||
| 606 | u8 clk_divider_flags = 0; | 618 | u8 clk_divider_flags = 0; |
| 607 | u8 width = 0; | 619 | u8 width = 0; |
| 608 | u8 shift = 0; | 620 | u8 shift = 0; |
| 621 | s8 latch = -EINVAL; | ||
| 609 | const struct clk_div_table *table = NULL; | 622 | const struct clk_div_table *table = NULL; |
| 610 | u32 flags = 0; | 623 | u32 flags = 0; |
| 611 | 624 | ||
| 612 | parent_name = of_clk_get_parent_name(node, 0); | 625 | parent_name = of_clk_get_parent_name(node, 0); |
| 613 | 626 | ||
| 614 | if (ti_clk_divider_populate(node, ®, &table, &flags, | 627 | if (ti_clk_divider_populate(node, ®, &table, &flags, |
| 615 | &clk_divider_flags, &width, &shift)) | 628 | &clk_divider_flags, &width, &shift, &latch)) |
| 616 | goto cleanup; | 629 | goto cleanup; |
| 617 | 630 | ||
| 618 | clk = _register_divider(NULL, node->name, parent_name, flags, ®, | 631 | clk = _register_divider(NULL, node->name, parent_name, flags, ®, |
| 619 | shift, width, clk_divider_flags, table); | 632 | shift, width, latch, clk_divider_flags, table); |
| 620 | 633 | ||
| 621 | if (!IS_ERR(clk)) { | 634 | if (!IS_ERR(clk)) { |
| 622 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 635 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
| @@ -639,7 +652,8 @@ static void __init of_ti_composite_divider_clk_setup(struct device_node *node) | |||
| 639 | return; | 652 | return; |
| 640 | 653 | ||
| 641 | if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, | 654 | if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, |
| 642 | &div->flags, &div->width, &div->shift) < 0) | 655 | &div->flags, &div->width, &div->shift, |
| 656 | NULL) < 0) | ||
| 643 | goto cleanup; | 657 | goto cleanup; |
| 644 | 658 | ||
| 645 | if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) | 659 | if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) |
