1/* 2 * OMAP clkctrl clock support 3 * 4 * Copyright (C) 2017 Texas Instruments, Inc. 5 * 6 * Tero Kristo <t-kristo@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 13 * kind, whether express or implied; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/clk-provider.h> 19#include <linux/slab.h> 20#include <linux/of.h> 21#include <linux/of_address.h> 22#include <linux/clk/ti.h> 23#include <linux/delay.h> 24#include <linux/timekeeping.h> 25#include "clock.h" 26 27#define NO_IDLEST 0 28 29#define OMAP4_MODULEMODE_MASK 0x3 30 31#define MODULEMODE_HWCTRL 0x1 32#define MODULEMODE_SWCTRL 0x2 33 34#define OMAP4_IDLEST_MASK (0x3 << 16) 35#define OMAP4_IDLEST_SHIFT 16 36 37#define OMAP4_STBYST_MASK BIT(18) 38#define OMAP4_STBYST_SHIFT 18 39 40#define CLKCTRL_IDLEST_FUNCTIONAL 0x0 41#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 42#define CLKCTRL_IDLEST_DISABLED 0x3 43 44/* These timeouts are in us */ 45#define OMAP4_MAX_MODULE_READY_TIME 2000 46#define OMAP4_MAX_MODULE_DISABLE_TIME 5000 47 48static bool _early_timeout = true; 49 50struct omap_clkctrl_provider { 51 void __iomem *base; 52 struct list_head clocks; 53 char *clkdm_name; 54}; 55 56struct omap_clkctrl_clk { 57 struct clk_hw *clk; 58 u16 reg_offset; 59 int bit_offset; 60 struct list_head node; 61}; 62 63union omap4_timeout { 64 u32 cycles; 65 ktime_t start; 66}; 67 68static const struct omap_clkctrl_data default_clkctrl_data[] __initconst = { 69 { 0 }, 70}; 71 72static u32 _omap4_idlest(u32 val) 73{ 74 val &= OMAP4_IDLEST_MASK; 75 val >>= OMAP4_IDLEST_SHIFT; 76 77 return val; 78} 79 80static bool _omap4_is_idle(u32 val) 81{ 82 val = _omap4_idlest(val); 83 84 return val == CLKCTRL_IDLEST_DISABLED; 85} 86 87static bool _omap4_is_ready(u32 val) 88{ 89 val = _omap4_idlest(val); 90 91 return val == CLKCTRL_IDLEST_FUNCTIONAL || 92 val == CLKCTRL_IDLEST_INTERFACE_IDLE; 93} 94 95static bool _omap4_is_timeout(union omap4_timeout *time, u32 timeout) 96{ 97 /* 98 * There are two special cases where ktime_to_ns() can't be 99 * used to track the timeouts. First one is during early boot 100 * when the timers haven't been initialized yet. The second 101 * one is during suspend-resume cycle while timekeeping is 102 * being suspended / resumed. Clocksource for the system 103 * can be from a timer that requires pm_runtime access, which 104 * will eventually bring us here with timekeeping_suspended, 105 * during both suspend entry and resume paths. This happens 106 * at least on am43xx platform. Account for flakeyness 107 * with udelay() by multiplying the timeout value by 2. 108 */ 109 if (unlikely(_early_timeout || timekeeping_suspended)) { 110 if (time->cycles++ < timeout) { 111 udelay(1 * 2); 112 return false; 113 } 114 } else { 115 if (!ktime_to_ns(time->start)) { 116 time->start = ktime_get(); 117 return false; 118 } 119 120 if (ktime_us_delta(ktime_get(), time->start) < timeout) { 121 cpu_relax(); 122 return false; 123 } 124 } 125 126 return true; 127} 128 129static int __init _omap4_disable_early_timeout(void) 130{ 131 _early_timeout = false; 132 133 return 0; 134} 135arch_initcall(_omap4_disable_early_timeout); 136 137static int _omap4_clkctrl_clk_enable(struct clk_hw *hw) 138{ 139 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 140 u32 val; 141 int ret; 142 union omap4_timeout timeout = { 0 }; 143 144 if (clk->clkdm) { 145 ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); 146 if (ret) { 147 WARN(1, 148 "%s: could not enable %s's clockdomain %s: %d\n", 149 __func__, clk_hw_get_name(hw), 150 clk->clkdm_name, ret); 151 return ret; 152 } 153 } 154 155 if (!clk->enable_bit) 156 return 0; 157 158 val = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 159 160 val &= ~OMAP4_MODULEMODE_MASK; 161 val |= clk->enable_bit; 162 163 ti_clk_ll_ops->clk_writel(val, &clk->enable_reg); 164 165 if (test_bit(NO_IDLEST, &clk->flags)) 166 return 0; 167 168 /* Wait until module is enabled */ 169 while (!_omap4_is_ready(ti_clk_ll_ops->clk_readl(&clk->enable_reg))) { 170 if (_omap4_is_timeout(&timeout, OMAP4_MAX_MODULE_READY_TIME)) { 171 pr_err("%s: failed to enable\n", clk_hw_get_name(hw)); 172 return -EBUSY; 173 } 174 } 175 176 return 0; 177} 178 179static void _omap4_clkctrl_clk_disable(struct clk_hw *hw) 180{ 181 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 182 u32 val; 183 union omap4_timeout timeout = { 0 }; 184 185 if (!clk->enable_bit) 186 goto exit; 187 188 val = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 189 190 val &= ~OMAP4_MODULEMODE_MASK; 191 192 ti_clk_ll_ops->clk_writel(val, &clk->enable_reg); 193 194 if (test_bit(NO_IDLEST, &clk->flags)) 195 goto exit; 196 197 /* Wait until module is disabled */ 198 while (!_omap4_is_idle(ti_clk_ll_ops->clk_readl(&clk->enable_reg))) { 199 if (_omap4_is_timeout(&timeout, 200 OMAP4_MAX_MODULE_DISABLE_TIME)) { 201 pr_err("%s: failed to disable\n", clk_hw_get_name(hw)); 202 break; 203 } 204 } 205 206exit: 207 if (clk->clkdm) 208 ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); 209} 210 211static int _omap4_clkctrl_clk_is_enabled(struct clk_hw *hw) 212{ 213 struct clk_hw_omap *clk = to_clk_hw_omap(hw); 214 u32 val; 215 216 val = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 217 218 if (val & clk->enable_bit) 219 return 1; 220 221 return 0; 222} 223 224static const struct clk_ops omap4_clkctrl_clk_ops = { 225 .enable = _omap4_clkctrl_clk_enable, 226 .disable = _omap4_clkctrl_clk_disable, 227 .is_enabled = _omap4_clkctrl_clk_is_enabled, 228 .init = omap2_init_clk_clkdm, 229}; 230 231static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec, 232 void *data) 233{ 234 struct omap_clkctrl_provider *provider = data; 235 struct omap_clkctrl_clk *entry; 236 bool found = false; 237 238 if (clkspec->args_count != 2) 239 return ERR_PTR(-EINVAL); 240 241 pr_debug("%s: looking for %x:%x\n", __func__, 242 clkspec->args[0], clkspec->args[1]); 243 244 list_for_each_entry(entry, &provider->clocks, node) { 245 if (entry->reg_offset == clkspec->args[0] && 246 entry->bit_offset == clkspec->args[1]) { 247 found = true; 248 break; 249 } 250 } 251 252 if (!found) 253 return ERR_PTR(-EINVAL); 254 255 return entry->clk; 256} 257 258/* Get clkctrl clock base name based on clkctrl_name or dts node */ 259static const char * __init clkctrl_get_clock_name(struct device_node *np, 260 const char *clkctrl_name, 261 int offset, int index, 262 bool legacy_naming) 263{ 264 char *clock_name; 265 266 /* l4per-clkctrl:1234:0 style naming based on clkctrl_name */ 267 if (clkctrl_name && !legacy_naming) { 268 clock_name = kasprintf(GFP_KERNEL, "%s-clkctrl:%04x:%d", 269 clkctrl_name, offset, index); 270 if (!clock_name) 271 return NULL; 272 273 strreplace(clock_name, '_', '-'); 274 275 return clock_name; 276 } 277 278 /* l4per:1234:0 old style naming based on clkctrl_name */ 279 if (clkctrl_name) 280 return kasprintf(GFP_KERNEL, "%s_cm:clk:%04x:%d", 281 clkctrl_name, offset, index); 282 283 /* l4per_cm:1234:0 old style naming based on parent node name */ 284 if (legacy_naming) 285 return kasprintf(GFP_KERNEL, "%pOFn:clk:%04x:%d", 286 np->parent, offset, index); 287 288 /* l4per-clkctrl:1234:0 style naming based on node name */ 289 return kasprintf(GFP_KERNEL, "%pOFn:%04x:%d", np, offset, index); 290} 291 292static int __init 293_ti_clkctrl_clk_register(struct omap_clkctrl_provider *provider, 294 struct device_node *node, struct clk_hw *clk_hw, 295 u16 offset, u8 bit, const char * const *parents, 296 int num_parents, const struct clk_ops *ops, 297 const char *clkctrl_name) 298{ 299 struct clk_init_data init = { NULL }; 300 struct clk *clk; 301 struct omap_clkctrl_clk *clkctrl_clk; 302 int ret = 0; 303 304 init.name = clkctrl_get_clock_name(node, clkctrl_name, offset, bit, 305 ti_clk_get_features()->flags & 306 TI_CLK_CLKCTRL_COMPAT); 307 308 clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL); 309 if (!init.name || !clkctrl_clk) { 310 ret = -ENOMEM; 311 goto cleanup; 312 } 313 314 clk_hw->init = &init; 315 init.parent_names = parents; 316 init.num_parents = num_parents; 317 init.ops = ops; 318 init.flags = 0; 319 320 clk = of_ti_clk_register(node, clk_hw, init.name); 321 if (IS_ERR_OR_NULL(clk)) { 322 ret = -EINVAL; 323 goto cleanup; 324 } 325 326 clkctrl_clk->reg_offset = offset; 327 clkctrl_clk->bit_offset = bit; 328 clkctrl_clk->clk = clk_hw; 329 330 list_add(&clkctrl_clk->node, &provider->clocks); 331 332 return 0; 333 334cleanup: 335 kfree(init.name); 336 kfree(clkctrl_clk); 337 return ret; 338} 339 340static void __init 341_ti_clkctrl_setup_gate(struct omap_clkctrl_provider *provider, 342 struct device_node *node, u16 offset, 343 const struct omap_clkctrl_bit_data *data, 344 void __iomem *reg, const char *clkctrl_name) 345{ 346 struct clk_hw_omap *clk_hw; 347 348 clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); 349 if (!clk_hw) 350 return; 351 352 clk_hw->enable_bit = data->bit; 353 clk_hw->enable_reg.ptr = reg; 354 355 if (_ti_clkctrl_clk_register(provider, node, &clk_hw->hw, offset, 356 data->bit, data->parents, 1, 357 &omap_gate_clk_ops, clkctrl_name)) 358 kfree(clk_hw); 359} 360 361static void __init 362_ti_clkctrl_setup_mux(struct omap_clkctrl_provider *provider, 363 struct device_node *node, u16 offset, 364 const struct omap_clkctrl_bit_data *data, 365 void __iomem *reg, const char *clkctrl_name) 366{ 367 struct clk_omap_mux *mux; 368 int num_parents = 0; 369 const char * const *pname; 370 371 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 372 if (!mux) 373 return; 374 375 pname = data->parents; 376 while (*pname) { 377 num_parents++; 378 pname++; 379 } 380 381 mux->mask = num_parents; 382 if (!(mux->flags & CLK_MUX_INDEX_ONE)) 383 mux->mask--; 384 385 mux->mask = (1 << fls(mux->mask)) - 1; 386 387 mux->shift = data->bit; 388 mux->reg.ptr = reg; 389 390 if (_ti_clkctrl_clk_register(provider, node, &mux->hw, offset, 391 data->bit, data->parents, num_parents, 392 &ti_clk_mux_ops, clkctrl_name)) 393 kfree(mux); 394} 395 396static void __init 397_ti_clkctrl_setup_div(struct omap_clkctrl_provider *provider, 398 struct device_node *node, u16 offset, 399 const struct omap_clkctrl_bit_data *data, 400 void __iomem *reg, const char *clkctrl_name) 401{ 402 struct clk_omap_divider *div; 403 const struct omap_clkctrl_div_data *div_data = data->data; 404 u8 div_flags = 0; 405 406 div = kzalloc(sizeof(*div), GFP_KERNEL); 407 if (!div) 408 return; 409 410 div->reg.ptr = reg; 411 div->shift = data->bit; 412 div->flags = div_data->flags; 413 414 if (div->flags & CLK_DIVIDER_POWER_OF_TWO) 415 div_flags |= CLKF_INDEX_POWER_OF_TWO; 416 417 if (ti_clk_parse_divider_data((int *)div_data->dividers, 0, 418 div_data->max_div, div_flags, 419 div)) { 420 pr_err("%s: Data parsing for %pOF:%04x:%d failed\n", __func__, 421 node, offset, data->bit); 422 kfree(div); 423 return; 424 } 425 426 if (_ti_clkctrl_clk_register(provider, node, &div->hw, offset, 427 data->bit, data->parents, 1, 428 &ti_clk_divider_ops, clkctrl_name)) 429 kfree(div); 430} 431 432static void __init 433_ti_clkctrl_setup_subclks(struct omap_clkctrl_provider *provider, 434 struct device_node *node, 435 const struct omap_clkctrl_reg_data *data, 436 void __iomem *reg, const char *clkctrl_name) 437{ 438 const struct omap_clkctrl_bit_data *bits = data->bit_data; 439 440 if (!bits) 441 return; 442 443 while (bits->bit) { 444 switch (bits->type) { 445 case TI_CLK_GATE: 446 _ti_clkctrl_setup_gate(provider, node, data->offset, 447 bits, reg, clkctrl_name); 448 break; 449 450 case TI_CLK_DIVIDER: 451 _ti_clkctrl_setup_div(provider, node, data->offset, 452 bits, reg, clkctrl_name); 453 break; 454 455 case TI_CLK_MUX: 456 _ti_clkctrl_setup_mux(provider, node, data->offset, 457 bits, reg, clkctrl_name); 458 break; 459 460 default: 461 pr_err("%s: bad subclk type: %d\n", __func__, 462 bits->type); 463 return; 464 } 465 bits++; 466 } 467} 468 469static void __init _clkctrl_add_provider(void *data, 470 struct device_node *np) 471{ 472 of_clk_add_hw_provider(np, _ti_omap4_clkctrl_xlate, data); 473} 474 475/* Get clock name based on compatible string for clkctrl */ 476static char * __init clkctrl_get_name(struct device_node *np) 477{ 478 struct property *prop; 479 const int prefix_len = 11; 480 const char *compat; 481 char *name; 482 483 of_property_for_each_string(np, "compatible", prop, compat) { 484 if (!strncmp("ti,clkctrl-", compat, prefix_len)) { 485 /* Two letter minimum name length for l3, l4 etc */ 486 if (strnlen(compat + prefix_len, 16) < 2) 487 continue; 488 name = kasprintf(GFP_KERNEL, "%s", compat + prefix_len); 489 if (!name) 490 continue; 491 strreplace(name, '-', '_'); 492 493 return name; 494 } 495 } 496 497 return NULL; 498} 499 500static void __init _ti_omap4_clkctrl_setup(struct device_node *node) 501{ 502 struct omap_clkctrl_provider *provider; 503 const struct omap_clkctrl_data *data = default_clkctrl_data; 504 const struct omap_clkctrl_reg_data *reg_data; 505 struct clk_init_data init = { NULL }; 506 struct clk_hw_omap *hw; 507 struct clk *clk; 508 struct omap_clkctrl_clk *clkctrl_clk = NULL; 509 const __be32 *addrp; 510 bool legacy_naming; 511 char *clkctrl_name; 512 u32 addr; 513 int ret; 514 char *c; 515 u16 soc_mask = 0; 516 517 if (!(ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) && 518 of_node_name_eq(node, "clk")) 519 ti_clk_features.flags |= TI_CLK_CLKCTRL_COMPAT; 520 521 addrp = of_get_address(node, 0, NULL, NULL); 522 addr = (u32)of_translate_address(node, addrp); 523 524#ifdef CONFIG_ARCH_OMAP4 525 if (of_machine_is_compatible("ti,omap4")) 526 data = omap4_clkctrl_data; 527#endif 528#ifdef CONFIG_SOC_OMAP5 529 if (of_machine_is_compatible("ti,omap5")) 530 data = omap5_clkctrl_data; 531#endif 532#ifdef CONFIG_SOC_DRA7XX 533 if (of_machine_is_compatible("ti,dra7")) { 534 if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) 535 data = dra7_clkctrl_compat_data; 536 else 537 data = dra7_clkctrl_data; 538 } 539 540 if (of_machine_is_compatible("ti,dra72")) 541 soc_mask = CLKF_SOC_DRA72; 542 if (of_machine_is_compatible("ti,dra74")) 543 soc_mask = CLKF_SOC_DRA74; 544 if (of_machine_is_compatible("ti,dra76")) 545 soc_mask = CLKF_SOC_DRA76; 546#endif 547#ifdef CONFIG_SOC_AM33XX 548 if (of_machine_is_compatible("ti,am33xx")) { 549 if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) 550 data = am3_clkctrl_compat_data; 551 else 552 data = am3_clkctrl_data; 553 } 554#endif 555#ifdef CONFIG_SOC_AM43XX 556 if (of_machine_is_compatible("ti,am4372")) { 557 if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) 558 data = am4_clkctrl_compat_data; 559 else 560 data = am4_clkctrl_data; 561 } 562 563 if (of_machine_is_compatible("ti,am438x")) { 564 if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) 565 data = am438x_clkctrl_compat_data; 566 else 567 data = am438x_clkctrl_data; 568 } 569#endif 570#ifdef CONFIG_SOC_TI81XX 571 if (of_machine_is_compatible("ti,dm814")) 572 data = dm814_clkctrl_data; 573 574 if (of_machine_is_compatible("ti,dm816")) 575 data = dm816_clkctrl_data; 576#endif 577 578 if (ti_clk_get_features()->flags & TI_CLK_DEVICE_TYPE_GP) 579 soc_mask |= CLKF_SOC_NONSEC; 580 581 while (data->addr) { 582 if (addr == data->addr) 583 break; 584 585 data++; 586 } 587 588 if (!data->addr) { 589 pr_err("%pOF not found from clkctrl data.\n", node); 590 return; 591 } 592 593 provider = kzalloc(sizeof(*provider), GFP_KERNEL); 594 if (!provider) 595 return; 596 597 provider->base = of_iomap(node, 0); 598 599 legacy_naming = ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT; 600 clkctrl_name = clkctrl_get_name(node); 601 if (clkctrl_name) { 602 provider->clkdm_name = kasprintf(GFP_KERNEL, 603 "%s_clkdm", clkctrl_name); 604 if (!provider->clkdm_name) { 605 kfree(provider); 606 return; 607 } 608 goto clkdm_found; 609 } 610 611 /* 612 * The code below can be removed when all clkctrl nodes use domain 613 * specific compatible proprerty and standard clock node naming 614 */ 615 if (legacy_naming) { 616 provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFnxxx", node->parent); 617 if (!provider->clkdm_name) { 618 kfree(provider); 619 return; 620 } 621 622 /* 623 * Create default clkdm name, replace _cm from end of parent 624 * node name with _clkdm 625 */ 626 provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0; 627 } else { 628 provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFn", node); 629 if (!provider->clkdm_name) { 630 kfree(provider); 631 return; 632 } 633 634 /* 635 * Create default clkdm name, replace _clkctrl from end of 636 * node name with _clkdm 637 */ 638 provider->clkdm_name[strlen(provider->clkdm_name) - 7] = 0; 639 } 640 641 strcat(provider->clkdm_name, "clkdm"); 642 643 /* Replace any dash from the clkdm name with underscore */ 644 c = provider->clkdm_name; 645 646 while (*c) { 647 if (*c == '-') 648 *c = '_'; 649 c++; 650 } 651clkdm_found: 652 INIT_LIST_HEAD(&provider->clocks); 653 654 /* Generate clocks */ 655 reg_data = data->regs; 656 657 while (reg_data->parent) { 658 if ((reg_data->flags & CLKF_SOC_MASK) && 659 (reg_data->flags & soc_mask) == 0) { 660 reg_data++; 661 continue; 662 } 663 664 hw = kzalloc(sizeof(*hw), GFP_KERNEL); 665 if (!hw) 666 return; 667 668 hw->enable_reg.ptr = provider->base + reg_data->offset; 669 670 _ti_clkctrl_setup_subclks(provider, node, reg_data, 671 hw->enable_reg.ptr, clkctrl_name); 672 673 if (reg_data->flags & CLKF_SW_SUP) 674 hw->enable_bit = MODULEMODE_SWCTRL; 675 if (reg_data->flags & CLKF_HW_SUP) 676 hw->enable_bit = MODULEMODE_HWCTRL; 677 if (reg_data->flags & CLKF_NO_IDLEST) 678 set_bit(NO_IDLEST, &hw->flags); 679 680 if (reg_data->clkdm_name) 681 hw->clkdm_name = reg_data->clkdm_name; 682 else 683 hw->clkdm_name = provider->clkdm_name; 684 685 init.parent_names = ®_data->parent; 686 init.num_parents = 1; 687 init.flags = 0; 688 if (reg_data->flags & CLKF_SET_RATE_PARENT) 689 init.flags |= CLK_SET_RATE_PARENT; 690 691 init.name = clkctrl_get_clock_name(node, clkctrl_name, 692 reg_data->offset, 0, 693 legacy_naming); 694 if (!init.name) 695 goto cleanup; 696 697 clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL); 698 if (!clkctrl_clk) 699 goto cleanup; 700 701 init.ops = &omap4_clkctrl_clk_ops; 702 hw->hw.init = &init; 703 704 clk = of_ti_clk_register_omap_hw(node, &hw->hw, init.name); 705 if (IS_ERR_OR_NULL(clk)) 706 goto cleanup; 707 708 clkctrl_clk->reg_offset = reg_data->offset; 709 clkctrl_clk->clk = &hw->hw; 710 711 list_add(&clkctrl_clk->node, &provider->clocks); 712 713 reg_data++; 714 } 715 716 ret = of_clk_add_hw_provider(node, _ti_omap4_clkctrl_xlate, provider); 717 if (ret == -EPROBE_DEFER) 718 ti_clk_retry_init(node, provider, _clkctrl_add_provider); 719 720 kfree(clkctrl_name); 721 722 return; 723 724cleanup: 725 kfree(hw); 726 kfree(init.name); 727 kfree(clkctrl_name); 728 kfree(clkctrl_clk); 729} 730CLK_OF_DECLARE(ti_omap4_clkctrl_clock, "ti,clkctrl", 731 _ti_omap4_clkctrl_setup); 732 733/** 734 * ti_clk_is_in_standby - Check if clkctrl clock is in standby or not 735 * @clk: clock to check standby status for 736 * 737 * Finds whether the provided clock is in standby mode or not. Returns 738 * true if the provided clock is a clkctrl type clock and it is in standby, 739 * false otherwise. 740 */ 741bool ti_clk_is_in_standby(struct clk *clk) 742{ 743 struct clk_hw *hw; 744 struct clk_hw_omap *hwclk; 745 u32 val; 746 747 hw = __clk_get_hw(clk); 748 749 if (!omap2_clk_is_hw_omap(hw)) 750 return false; 751 752 hwclk = to_clk_hw_omap(hw); 753 754 val = ti_clk_ll_ops->clk_readl(&hwclk->enable_reg); 755 756 if (val & OMAP4_STBYST_MASK) 757 return true; 758 759 return false; 760} 761EXPORT_SYMBOL_GPL(ti_clk_is_in_standby); 762