.. | .. |
---|
24 | 24 | #include <linux/timekeeping.h> |
---|
25 | 25 | #include "clock.h" |
---|
26 | 26 | |
---|
27 | | -#define NO_IDLEST 0x1 |
---|
| 27 | +#define NO_IDLEST 0 |
---|
28 | 28 | |
---|
29 | 29 | #define OMAP4_MODULEMODE_MASK 0x3 |
---|
30 | 30 | |
---|
.. | .. |
---|
33 | 33 | |
---|
34 | 34 | #define OMAP4_IDLEST_MASK (0x3 << 16) |
---|
35 | 35 | #define OMAP4_IDLEST_SHIFT 16 |
---|
| 36 | + |
---|
| 37 | +#define OMAP4_STBYST_MASK BIT(18) |
---|
| 38 | +#define OMAP4_STBYST_SHIFT 18 |
---|
36 | 39 | |
---|
37 | 40 | #define CLKCTRL_IDLEST_FUNCTIONAL 0x0 |
---|
38 | 41 | #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 |
---|
.. | .. |
---|
159 | 162 | |
---|
160 | 163 | ti_clk_ll_ops->clk_writel(val, &clk->enable_reg); |
---|
161 | 164 | |
---|
162 | | - if (clk->flags & NO_IDLEST) |
---|
| 165 | + if (test_bit(NO_IDLEST, &clk->flags)) |
---|
163 | 166 | return 0; |
---|
164 | 167 | |
---|
165 | 168 | /* Wait until module is enabled */ |
---|
.. | .. |
---|
188 | 191 | |
---|
189 | 192 | ti_clk_ll_ops->clk_writel(val, &clk->enable_reg); |
---|
190 | 193 | |
---|
191 | | - if (clk->flags & NO_IDLEST) |
---|
| 194 | + if (test_bit(NO_IDLEST, &clk->flags)) |
---|
192 | 195 | goto exit; |
---|
193 | 196 | |
---|
194 | 197 | /* Wait until module is disabled */ |
---|
.. | .. |
---|
252 | 255 | return entry->clk; |
---|
253 | 256 | } |
---|
254 | 257 | |
---|
| 258 | +/* Get clkctrl clock base name based on clkctrl_name or dts node */ |
---|
| 259 | +static 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 | + |
---|
255 | 292 | static int __init |
---|
256 | 293 | _ti_clkctrl_clk_register(struct omap_clkctrl_provider *provider, |
---|
257 | 294 | struct device_node *node, struct clk_hw *clk_hw, |
---|
258 | 295 | u16 offset, u8 bit, const char * const *parents, |
---|
259 | | - int num_parents, const struct clk_ops *ops) |
---|
| 296 | + int num_parents, const struct clk_ops *ops, |
---|
| 297 | + const char *clkctrl_name) |
---|
260 | 298 | { |
---|
261 | 299 | struct clk_init_data init = { NULL }; |
---|
262 | 300 | struct clk *clk; |
---|
263 | 301 | struct omap_clkctrl_clk *clkctrl_clk; |
---|
264 | 302 | int ret = 0; |
---|
265 | 303 | |
---|
266 | | - init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d", node->parent->name, |
---|
267 | | - node->name, offset, bit); |
---|
| 304 | + init.name = clkctrl_get_clock_name(node, clkctrl_name, offset, bit, |
---|
| 305 | + ti_clk_get_features()->flags & |
---|
| 306 | + TI_CLK_CLKCTRL_COMPAT); |
---|
| 307 | + |
---|
268 | 308 | clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL); |
---|
269 | 309 | if (!init.name || !clkctrl_clk) { |
---|
270 | 310 | ret = -ENOMEM; |
---|
.. | .. |
---|
275 | 315 | init.parent_names = parents; |
---|
276 | 316 | init.num_parents = num_parents; |
---|
277 | 317 | init.ops = ops; |
---|
278 | | - init.flags = CLK_IS_BASIC; |
---|
| 318 | + init.flags = 0; |
---|
279 | 319 | |
---|
280 | 320 | clk = ti_clk_register(NULL, clk_hw, init.name); |
---|
281 | 321 | if (IS_ERR_OR_NULL(clk)) { |
---|
.. | .. |
---|
301 | 341 | _ti_clkctrl_setup_gate(struct omap_clkctrl_provider *provider, |
---|
302 | 342 | struct device_node *node, u16 offset, |
---|
303 | 343 | const struct omap_clkctrl_bit_data *data, |
---|
304 | | - void __iomem *reg) |
---|
| 344 | + void __iomem *reg, const char *clkctrl_name) |
---|
305 | 345 | { |
---|
306 | 346 | struct clk_hw_omap *clk_hw; |
---|
307 | 347 | |
---|
.. | .. |
---|
314 | 354 | |
---|
315 | 355 | if (_ti_clkctrl_clk_register(provider, node, &clk_hw->hw, offset, |
---|
316 | 356 | data->bit, data->parents, 1, |
---|
317 | | - &omap_gate_clk_ops)) |
---|
| 357 | + &omap_gate_clk_ops, clkctrl_name)) |
---|
318 | 358 | kfree(clk_hw); |
---|
319 | 359 | } |
---|
320 | 360 | |
---|
.. | .. |
---|
322 | 362 | _ti_clkctrl_setup_mux(struct omap_clkctrl_provider *provider, |
---|
323 | 363 | struct device_node *node, u16 offset, |
---|
324 | 364 | const struct omap_clkctrl_bit_data *data, |
---|
325 | | - void __iomem *reg) |
---|
| 365 | + void __iomem *reg, const char *clkctrl_name) |
---|
326 | 366 | { |
---|
327 | 367 | struct clk_omap_mux *mux; |
---|
328 | 368 | int num_parents = 0; |
---|
.. | .. |
---|
349 | 389 | |
---|
350 | 390 | if (_ti_clkctrl_clk_register(provider, node, &mux->hw, offset, |
---|
351 | 391 | data->bit, data->parents, num_parents, |
---|
352 | | - &ti_clk_mux_ops)) |
---|
| 392 | + &ti_clk_mux_ops, clkctrl_name)) |
---|
353 | 393 | kfree(mux); |
---|
354 | 394 | } |
---|
355 | 395 | |
---|
.. | .. |
---|
357 | 397 | _ti_clkctrl_setup_div(struct omap_clkctrl_provider *provider, |
---|
358 | 398 | struct device_node *node, u16 offset, |
---|
359 | 399 | const struct omap_clkctrl_bit_data *data, |
---|
360 | | - void __iomem *reg) |
---|
| 400 | + void __iomem *reg, const char *clkctrl_name) |
---|
361 | 401 | { |
---|
362 | 402 | struct clk_omap_divider *div; |
---|
363 | 403 | const struct omap_clkctrl_div_data *div_data = data->data; |
---|
.. | .. |
---|
376 | 416 | |
---|
377 | 417 | if (ti_clk_parse_divider_data((int *)div_data->dividers, 0, |
---|
378 | 418 | div_data->max_div, div_flags, |
---|
379 | | - &div->width, &div->table)) { |
---|
| 419 | + div)) { |
---|
380 | 420 | pr_err("%s: Data parsing for %pOF:%04x:%d failed\n", __func__, |
---|
381 | 421 | node, offset, data->bit); |
---|
382 | 422 | kfree(div); |
---|
.. | .. |
---|
385 | 425 | |
---|
386 | 426 | if (_ti_clkctrl_clk_register(provider, node, &div->hw, offset, |
---|
387 | 427 | data->bit, data->parents, 1, |
---|
388 | | - &ti_clk_divider_ops)) |
---|
| 428 | + &ti_clk_divider_ops, clkctrl_name)) |
---|
389 | 429 | kfree(div); |
---|
390 | 430 | } |
---|
391 | 431 | |
---|
.. | .. |
---|
393 | 433 | _ti_clkctrl_setup_subclks(struct omap_clkctrl_provider *provider, |
---|
394 | 434 | struct device_node *node, |
---|
395 | 435 | const struct omap_clkctrl_reg_data *data, |
---|
396 | | - void __iomem *reg) |
---|
| 436 | + void __iomem *reg, const char *clkctrl_name) |
---|
397 | 437 | { |
---|
398 | 438 | const struct omap_clkctrl_bit_data *bits = data->bit_data; |
---|
399 | 439 | |
---|
.. | .. |
---|
404 | 444 | switch (bits->type) { |
---|
405 | 445 | case TI_CLK_GATE: |
---|
406 | 446 | _ti_clkctrl_setup_gate(provider, node, data->offset, |
---|
407 | | - bits, reg); |
---|
| 447 | + bits, reg, clkctrl_name); |
---|
408 | 448 | break; |
---|
409 | 449 | |
---|
410 | 450 | case TI_CLK_DIVIDER: |
---|
411 | 451 | _ti_clkctrl_setup_div(provider, node, data->offset, |
---|
412 | | - bits, reg); |
---|
| 452 | + bits, reg, clkctrl_name); |
---|
413 | 453 | break; |
---|
414 | 454 | |
---|
415 | 455 | case TI_CLK_MUX: |
---|
416 | 456 | _ti_clkctrl_setup_mux(provider, node, data->offset, |
---|
417 | | - bits, reg); |
---|
| 457 | + bits, reg, clkctrl_name); |
---|
418 | 458 | break; |
---|
419 | 459 | |
---|
420 | 460 | default: |
---|
.. | .. |
---|
432 | 472 | of_clk_add_hw_provider(np, _ti_omap4_clkctrl_xlate, data); |
---|
433 | 473 | } |
---|
434 | 474 | |
---|
| 475 | +/* Get clock name based on compatible string for clkctrl */ |
---|
| 476 | +static 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 | + |
---|
435 | 500 | static void __init _ti_omap4_clkctrl_setup(struct device_node *node) |
---|
436 | 501 | { |
---|
437 | 502 | struct omap_clkctrl_provider *provider; |
---|
.. | .. |
---|
440 | 505 | struct clk_init_data init = { NULL }; |
---|
441 | 506 | struct clk_hw_omap *hw; |
---|
442 | 507 | struct clk *clk; |
---|
443 | | - struct omap_clkctrl_clk *clkctrl_clk; |
---|
| 508 | + struct omap_clkctrl_clk *clkctrl_clk = NULL; |
---|
444 | 509 | const __be32 *addrp; |
---|
| 510 | + bool legacy_naming; |
---|
| 511 | + char *clkctrl_name; |
---|
445 | 512 | u32 addr; |
---|
446 | 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; |
---|
447 | 520 | |
---|
448 | 521 | addrp = of_get_address(node, 0, NULL, NULL); |
---|
449 | 522 | addr = (u32)of_translate_address(node, addrp); |
---|
.. | .. |
---|
457 | 530 | data = omap5_clkctrl_data; |
---|
458 | 531 | #endif |
---|
459 | 532 | #ifdef CONFIG_SOC_DRA7XX |
---|
460 | | - if (of_machine_is_compatible("ti,dra7")) |
---|
461 | | - data = dra7_clkctrl_data; |
---|
| 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; |
---|
462 | 546 | #endif |
---|
463 | 547 | #ifdef CONFIG_SOC_AM33XX |
---|
464 | | - if (of_machine_is_compatible("ti,am33xx")) |
---|
465 | | - data = am3_clkctrl_data; |
---|
| 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 | + } |
---|
466 | 554 | #endif |
---|
467 | 555 | #ifdef CONFIG_SOC_AM43XX |
---|
468 | | - if (of_machine_is_compatible("ti,am4372")) |
---|
469 | | - data = am4_clkctrl_data; |
---|
470 | | - if (of_machine_is_compatible("ti,am438x")) |
---|
471 | | - data = am438x_clkctrl_data; |
---|
| 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 | + } |
---|
472 | 569 | #endif |
---|
473 | 570 | #ifdef CONFIG_SOC_TI81XX |
---|
474 | 571 | if (of_machine_is_compatible("ti,dm814")) |
---|
.. | .. |
---|
477 | 574 | if (of_machine_is_compatible("ti,dm816")) |
---|
478 | 575 | data = dm816_clkctrl_data; |
---|
479 | 576 | #endif |
---|
| 577 | + |
---|
| 578 | + if (ti_clk_get_features()->flags & TI_CLK_DEVICE_TYPE_GP) |
---|
| 579 | + soc_mask |= CLKF_SOC_NONSEC; |
---|
480 | 580 | |
---|
481 | 581 | while (data->addr) { |
---|
482 | 582 | if (addr == data->addr) |
---|
.. | .. |
---|
496 | 596 | |
---|
497 | 597 | provider->base = of_iomap(node, 0); |
---|
498 | 598 | |
---|
499 | | - provider->clkdm_name = kmalloc(strlen(node->parent->name) + 3, |
---|
500 | | - GFP_KERNEL); |
---|
501 | | - if (!provider->clkdm_name) { |
---|
502 | | - kfree(provider); |
---|
503 | | - return; |
---|
| 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; |
---|
504 | 609 | } |
---|
505 | 610 | |
---|
506 | 611 | /* |
---|
507 | | - * Create default clkdm name, replace _cm from end of parent node |
---|
508 | | - * name with _clkdm |
---|
| 612 | + * The code below can be removed when all clkctrl nodes use domain |
---|
| 613 | + * specific compatible proprerty and standard clock node naming |
---|
509 | 614 | */ |
---|
510 | | - strcpy(provider->clkdm_name, node->parent->name); |
---|
511 | | - provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0; |
---|
| 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 | + |
---|
512 | 641 | strcat(provider->clkdm_name, "clkdm"); |
---|
513 | 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 | + } |
---|
| 651 | +clkdm_found: |
---|
514 | 652 | INIT_LIST_HEAD(&provider->clocks); |
---|
515 | 653 | |
---|
516 | 654 | /* Generate clocks */ |
---|
517 | 655 | reg_data = data->regs; |
---|
518 | 656 | |
---|
519 | 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 | + |
---|
520 | 664 | hw = kzalloc(sizeof(*hw), GFP_KERNEL); |
---|
521 | 665 | if (!hw) |
---|
522 | 666 | return; |
---|
.. | .. |
---|
524 | 668 | hw->enable_reg.ptr = provider->base + reg_data->offset; |
---|
525 | 669 | |
---|
526 | 670 | _ti_clkctrl_setup_subclks(provider, node, reg_data, |
---|
527 | | - hw->enable_reg.ptr); |
---|
| 671 | + hw->enable_reg.ptr, clkctrl_name); |
---|
528 | 672 | |
---|
529 | 673 | if (reg_data->flags & CLKF_SW_SUP) |
---|
530 | 674 | hw->enable_bit = MODULEMODE_SWCTRL; |
---|
531 | 675 | if (reg_data->flags & CLKF_HW_SUP) |
---|
532 | 676 | hw->enable_bit = MODULEMODE_HWCTRL; |
---|
533 | 677 | if (reg_data->flags & CLKF_NO_IDLEST) |
---|
534 | | - hw->flags |= NO_IDLEST; |
---|
| 678 | + set_bit(NO_IDLEST, &hw->flags); |
---|
535 | 679 | |
---|
536 | 680 | if (reg_data->clkdm_name) |
---|
537 | 681 | hw->clkdm_name = reg_data->clkdm_name; |
---|
.. | .. |
---|
543 | 687 | init.flags = 0; |
---|
544 | 688 | if (reg_data->flags & CLKF_SET_RATE_PARENT) |
---|
545 | 689 | init.flags |= CLK_SET_RATE_PARENT; |
---|
546 | | - init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d", |
---|
547 | | - node->parent->name, node->name, |
---|
548 | | - reg_data->offset, 0); |
---|
| 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 | + |
---|
549 | 697 | clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL); |
---|
550 | | - if (!init.name || !clkctrl_clk) |
---|
| 698 | + if (!clkctrl_clk) |
---|
551 | 699 | goto cleanup; |
---|
552 | 700 | |
---|
553 | 701 | init.ops = &omap4_clkctrl_clk_ops; |
---|
554 | 702 | hw->hw.init = &init; |
---|
555 | 703 | |
---|
556 | | - clk = ti_clk_register(NULL, &hw->hw, init.name); |
---|
| 704 | + clk = ti_clk_register_omap_hw(NULL, &hw->hw, init.name); |
---|
557 | 705 | if (IS_ERR_OR_NULL(clk)) |
---|
558 | 706 | goto cleanup; |
---|
559 | 707 | |
---|
.. | .. |
---|
569 | 717 | if (ret == -EPROBE_DEFER) |
---|
570 | 718 | ti_clk_retry_init(node, provider, _clkctrl_add_provider); |
---|
571 | 719 | |
---|
| 720 | + kfree(clkctrl_name); |
---|
| 721 | + |
---|
572 | 722 | return; |
---|
573 | 723 | |
---|
574 | 724 | cleanup: |
---|
575 | 725 | kfree(hw); |
---|
576 | 726 | kfree(init.name); |
---|
| 727 | + kfree(clkctrl_name); |
---|
577 | 728 | kfree(clkctrl_clk); |
---|
578 | 729 | } |
---|
579 | 730 | CLK_OF_DECLARE(ti_omap4_clkctrl_clock, "ti,clkctrl", |
---|
580 | 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 | + */ |
---|
| 741 | +bool 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 | +} |
---|
| 761 | +EXPORT_SYMBOL_GPL(ti_clk_is_in_standby); |
---|