root/drivers/base/power/clock_ops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __pm_clk_enable
  2. pm_clk_acquire
  3. __pm_clk_add
  4. pm_clk_add
  5. pm_clk_add_clk
  6. of_pm_clk_add_clk
  7. of_pm_clk_add_clks
  8. __pm_clk_remove
  9. pm_clk_remove
  10. pm_clk_remove_clk
  11. pm_clk_init
  12. pm_clk_create
  13. pm_clk_destroy
  14. pm_clk_suspend
  15. pm_clk_resume
  16. pm_clk_notify
  17. pm_clk_runtime_suspend
  18. pm_clk_runtime_resume
  19. enable_clock
  20. disable_clock
  21. pm_clk_notify
  22. pm_clk_add_notifier

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
   4  *
   5  * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/device.h>
  10 #include <linux/io.h>
  11 #include <linux/pm.h>
  12 #include <linux/pm_clock.h>
  13 #include <linux/clk.h>
  14 #include <linux/clkdev.h>
  15 #include <linux/of_clk.h>
  16 #include <linux/slab.h>
  17 #include <linux/err.h>
  18 #include <linux/pm_domain.h>
  19 #include <linux/pm_runtime.h>
  20 
  21 #ifdef CONFIG_PM_CLK
  22 
  23 enum pce_status {
  24         PCE_STATUS_NONE = 0,
  25         PCE_STATUS_ACQUIRED,
  26         PCE_STATUS_ENABLED,
  27         PCE_STATUS_ERROR,
  28 };
  29 
  30 struct pm_clock_entry {
  31         struct list_head node;
  32         char *con_id;
  33         struct clk *clk;
  34         enum pce_status status;
  35 };
  36 
  37 /**
  38  * pm_clk_enable - Enable a clock, reporting any errors
  39  * @dev: The device for the given clock
  40  * @ce: PM clock entry corresponding to the clock.
  41  */
  42 static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
  43 {
  44         int ret;
  45 
  46         if (ce->status < PCE_STATUS_ERROR) {
  47                 ret = clk_enable(ce->clk);
  48                 if (!ret)
  49                         ce->status = PCE_STATUS_ENABLED;
  50                 else
  51                         dev_err(dev, "%s: failed to enable clk %p, error %d\n",
  52                                 __func__, ce->clk, ret);
  53         }
  54 }
  55 
  56 /**
  57  * pm_clk_acquire - Acquire a device clock.
  58  * @dev: Device whose clock is to be acquired.
  59  * @ce: PM clock entry corresponding to the clock.
  60  */
  61 static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
  62 {
  63         if (!ce->clk)
  64                 ce->clk = clk_get(dev, ce->con_id);
  65         if (IS_ERR(ce->clk)) {
  66                 ce->status = PCE_STATUS_ERROR;
  67         } else {
  68                 if (clk_prepare(ce->clk)) {
  69                         ce->status = PCE_STATUS_ERROR;
  70                         dev_err(dev, "clk_prepare() failed\n");
  71                 } else {
  72                         ce->status = PCE_STATUS_ACQUIRED;
  73                         dev_dbg(dev,
  74                                 "Clock %pC con_id %s managed by runtime PM.\n",
  75                                 ce->clk, ce->con_id);
  76                 }
  77         }
  78 }
  79 
  80 static int __pm_clk_add(struct device *dev, const char *con_id,
  81                         struct clk *clk)
  82 {
  83         struct pm_subsys_data *psd = dev_to_psd(dev);
  84         struct pm_clock_entry *ce;
  85 
  86         if (!psd)
  87                 return -EINVAL;
  88 
  89         ce = kzalloc(sizeof(*ce), GFP_KERNEL);
  90         if (!ce)
  91                 return -ENOMEM;
  92 
  93         if (con_id) {
  94                 ce->con_id = kstrdup(con_id, GFP_KERNEL);
  95                 if (!ce->con_id) {
  96                         kfree(ce);
  97                         return -ENOMEM;
  98                 }
  99         } else {
 100                 if (IS_ERR(clk)) {
 101                         kfree(ce);
 102                         return -ENOENT;
 103                 }
 104                 ce->clk = clk;
 105         }
 106 
 107         pm_clk_acquire(dev, ce);
 108 
 109         spin_lock_irq(&psd->lock);
 110         list_add_tail(&ce->node, &psd->clock_list);
 111         spin_unlock_irq(&psd->lock);
 112         return 0;
 113 }
 114 
 115 /**
 116  * pm_clk_add - Start using a device clock for power management.
 117  * @dev: Device whose clock is going to be used for power management.
 118  * @con_id: Connection ID of the clock.
 119  *
 120  * Add the clock represented by @con_id to the list of clocks used for
 121  * the power management of @dev.
 122  */
 123 int pm_clk_add(struct device *dev, const char *con_id)
 124 {
 125         return __pm_clk_add(dev, con_id, NULL);
 126 }
 127 EXPORT_SYMBOL_GPL(pm_clk_add);
 128 
 129 /**
 130  * pm_clk_add_clk - Start using a device clock for power management.
 131  * @dev: Device whose clock is going to be used for power management.
 132  * @clk: Clock pointer
 133  *
 134  * Add the clock to the list of clocks used for the power management of @dev.
 135  * The power-management code will take control of the clock reference, so
 136  * callers should not call clk_put() on @clk after this function sucessfully
 137  * returned.
 138  */
 139 int pm_clk_add_clk(struct device *dev, struct clk *clk)
 140 {
 141         return __pm_clk_add(dev, NULL, clk);
 142 }
 143 EXPORT_SYMBOL_GPL(pm_clk_add_clk);
 144 
 145 
 146 /**
 147  * of_pm_clk_add_clk - Start using a device clock for power management.
 148  * @dev: Device whose clock is going to be used for power management.
 149  * @name: Name of clock that is going to be used for power management.
 150  *
 151  * Add the clock described in the 'clocks' device-tree node that matches
 152  * with the 'name' provided, to the list of clocks used for the power
 153  * management of @dev. On success, returns 0. Returns a negative error
 154  * code if the clock is not found or cannot be added.
 155  */
 156 int of_pm_clk_add_clk(struct device *dev, const char *name)
 157 {
 158         struct clk *clk;
 159         int ret;
 160 
 161         if (!dev || !dev->of_node || !name)
 162                 return -EINVAL;
 163 
 164         clk = of_clk_get_by_name(dev->of_node, name);
 165         if (IS_ERR(clk))
 166                 return PTR_ERR(clk);
 167 
 168         ret = pm_clk_add_clk(dev, clk);
 169         if (ret) {
 170                 clk_put(clk);
 171                 return ret;
 172         }
 173 
 174         return 0;
 175 }
 176 EXPORT_SYMBOL_GPL(of_pm_clk_add_clk);
 177 
 178 /**
 179  * of_pm_clk_add_clks - Start using device clock(s) for power management.
 180  * @dev: Device whose clock(s) is going to be used for power management.
 181  *
 182  * Add a series of clocks described in the 'clocks' device-tree node for
 183  * a device to the list of clocks used for the power management of @dev.
 184  * On success, returns the number of clocks added. Returns a negative
 185  * error code if there are no clocks in the device node for the device
 186  * or if adding a clock fails.
 187  */
 188 int of_pm_clk_add_clks(struct device *dev)
 189 {
 190         struct clk **clks;
 191         int i, count;
 192         int ret;
 193 
 194         if (!dev || !dev->of_node)
 195                 return -EINVAL;
 196 
 197         count = of_clk_get_parent_count(dev->of_node);
 198         if (count <= 0)
 199                 return -ENODEV;
 200 
 201         clks = kcalloc(count, sizeof(*clks), GFP_KERNEL);
 202         if (!clks)
 203                 return -ENOMEM;
 204 
 205         for (i = 0; i < count; i++) {
 206                 clks[i] = of_clk_get(dev->of_node, i);
 207                 if (IS_ERR(clks[i])) {
 208                         ret = PTR_ERR(clks[i]);
 209                         goto error;
 210                 }
 211 
 212                 ret = pm_clk_add_clk(dev, clks[i]);
 213                 if (ret) {
 214                         clk_put(clks[i]);
 215                         goto error;
 216                 }
 217         }
 218 
 219         kfree(clks);
 220 
 221         return i;
 222 
 223 error:
 224         while (i--)
 225                 pm_clk_remove_clk(dev, clks[i]);
 226 
 227         kfree(clks);
 228 
 229         return ret;
 230 }
 231 EXPORT_SYMBOL_GPL(of_pm_clk_add_clks);
 232 
 233 /**
 234  * __pm_clk_remove - Destroy PM clock entry.
 235  * @ce: PM clock entry to destroy.
 236  */
 237 static void __pm_clk_remove(struct pm_clock_entry *ce)
 238 {
 239         if (!ce)
 240                 return;
 241 
 242         if (ce->status < PCE_STATUS_ERROR) {
 243                 if (ce->status == PCE_STATUS_ENABLED)
 244                         clk_disable(ce->clk);
 245 
 246                 if (ce->status >= PCE_STATUS_ACQUIRED) {
 247                         clk_unprepare(ce->clk);
 248                         clk_put(ce->clk);
 249                 }
 250         }
 251 
 252         kfree(ce->con_id);
 253         kfree(ce);
 254 }
 255 
 256 /**
 257  * pm_clk_remove - Stop using a device clock for power management.
 258  * @dev: Device whose clock should not be used for PM any more.
 259  * @con_id: Connection ID of the clock.
 260  *
 261  * Remove the clock represented by @con_id from the list of clocks used for
 262  * the power management of @dev.
 263  */
 264 void pm_clk_remove(struct device *dev, const char *con_id)
 265 {
 266         struct pm_subsys_data *psd = dev_to_psd(dev);
 267         struct pm_clock_entry *ce;
 268 
 269         if (!psd)
 270                 return;
 271 
 272         spin_lock_irq(&psd->lock);
 273 
 274         list_for_each_entry(ce, &psd->clock_list, node) {
 275                 if (!con_id && !ce->con_id)
 276                         goto remove;
 277                 else if (!con_id || !ce->con_id)
 278                         continue;
 279                 else if (!strcmp(con_id, ce->con_id))
 280                         goto remove;
 281         }
 282 
 283         spin_unlock_irq(&psd->lock);
 284         return;
 285 
 286  remove:
 287         list_del(&ce->node);
 288         spin_unlock_irq(&psd->lock);
 289 
 290         __pm_clk_remove(ce);
 291 }
 292 EXPORT_SYMBOL_GPL(pm_clk_remove);
 293 
 294 /**
 295  * pm_clk_remove_clk - Stop using a device clock for power management.
 296  * @dev: Device whose clock should not be used for PM any more.
 297  * @clk: Clock pointer
 298  *
 299  * Remove the clock pointed to by @clk from the list of clocks used for
 300  * the power management of @dev.
 301  */
 302 void pm_clk_remove_clk(struct device *dev, struct clk *clk)
 303 {
 304         struct pm_subsys_data *psd = dev_to_psd(dev);
 305         struct pm_clock_entry *ce;
 306 
 307         if (!psd || !clk)
 308                 return;
 309 
 310         spin_lock_irq(&psd->lock);
 311 
 312         list_for_each_entry(ce, &psd->clock_list, node) {
 313                 if (clk == ce->clk)
 314                         goto remove;
 315         }
 316 
 317         spin_unlock_irq(&psd->lock);
 318         return;
 319 
 320  remove:
 321         list_del(&ce->node);
 322         spin_unlock_irq(&psd->lock);
 323 
 324         __pm_clk_remove(ce);
 325 }
 326 EXPORT_SYMBOL_GPL(pm_clk_remove_clk);
 327 
 328 /**
 329  * pm_clk_init - Initialize a device's list of power management clocks.
 330  * @dev: Device to initialize the list of PM clocks for.
 331  *
 332  * Initialize the lock and clock_list members of the device's pm_subsys_data
 333  * object.
 334  */
 335 void pm_clk_init(struct device *dev)
 336 {
 337         struct pm_subsys_data *psd = dev_to_psd(dev);
 338         if (psd)
 339                 INIT_LIST_HEAD(&psd->clock_list);
 340 }
 341 EXPORT_SYMBOL_GPL(pm_clk_init);
 342 
 343 /**
 344  * pm_clk_create - Create and initialize a device's list of PM clocks.
 345  * @dev: Device to create and initialize the list of PM clocks for.
 346  *
 347  * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
 348  * members and make the @dev's power.subsys_data field point to it.
 349  */
 350 int pm_clk_create(struct device *dev)
 351 {
 352         return dev_pm_get_subsys_data(dev);
 353 }
 354 EXPORT_SYMBOL_GPL(pm_clk_create);
 355 
 356 /**
 357  * pm_clk_destroy - Destroy a device's list of power management clocks.
 358  * @dev: Device to destroy the list of PM clocks for.
 359  *
 360  * Clear the @dev's power.subsys_data field, remove the list of clock entries
 361  * from the struct pm_subsys_data object pointed to by it before and free
 362  * that object.
 363  */
 364 void pm_clk_destroy(struct device *dev)
 365 {
 366         struct pm_subsys_data *psd = dev_to_psd(dev);
 367         struct pm_clock_entry *ce, *c;
 368         struct list_head list;
 369 
 370         if (!psd)
 371                 return;
 372 
 373         INIT_LIST_HEAD(&list);
 374 
 375         spin_lock_irq(&psd->lock);
 376 
 377         list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
 378                 list_move(&ce->node, &list);
 379 
 380         spin_unlock_irq(&psd->lock);
 381 
 382         dev_pm_put_subsys_data(dev);
 383 
 384         list_for_each_entry_safe_reverse(ce, c, &list, node) {
 385                 list_del(&ce->node);
 386                 __pm_clk_remove(ce);
 387         }
 388 }
 389 EXPORT_SYMBOL_GPL(pm_clk_destroy);
 390 
 391 /**
 392  * pm_clk_suspend - Disable clocks in a device's PM clock list.
 393  * @dev: Device to disable the clocks for.
 394  */
 395 int pm_clk_suspend(struct device *dev)
 396 {
 397         struct pm_subsys_data *psd = dev_to_psd(dev);
 398         struct pm_clock_entry *ce;
 399         unsigned long flags;
 400 
 401         dev_dbg(dev, "%s()\n", __func__);
 402 
 403         if (!psd)
 404                 return 0;
 405 
 406         spin_lock_irqsave(&psd->lock, flags);
 407 
 408         list_for_each_entry_reverse(ce, &psd->clock_list, node) {
 409                 if (ce->status < PCE_STATUS_ERROR) {
 410                         if (ce->status == PCE_STATUS_ENABLED)
 411                                 clk_disable(ce->clk);
 412                         ce->status = PCE_STATUS_ACQUIRED;
 413                 }
 414         }
 415 
 416         spin_unlock_irqrestore(&psd->lock, flags);
 417 
 418         return 0;
 419 }
 420 EXPORT_SYMBOL_GPL(pm_clk_suspend);
 421 
 422 /**
 423  * pm_clk_resume - Enable clocks in a device's PM clock list.
 424  * @dev: Device to enable the clocks for.
 425  */
 426 int pm_clk_resume(struct device *dev)
 427 {
 428         struct pm_subsys_data *psd = dev_to_psd(dev);
 429         struct pm_clock_entry *ce;
 430         unsigned long flags;
 431 
 432         dev_dbg(dev, "%s()\n", __func__);
 433 
 434         if (!psd)
 435                 return 0;
 436 
 437         spin_lock_irqsave(&psd->lock, flags);
 438 
 439         list_for_each_entry(ce, &psd->clock_list, node)
 440                 __pm_clk_enable(dev, ce);
 441 
 442         spin_unlock_irqrestore(&psd->lock, flags);
 443 
 444         return 0;
 445 }
 446 EXPORT_SYMBOL_GPL(pm_clk_resume);
 447 
 448 /**
 449  * pm_clk_notify - Notify routine for device addition and removal.
 450  * @nb: Notifier block object this function is a member of.
 451  * @action: Operation being carried out by the caller.
 452  * @data: Device the routine is being run for.
 453  *
 454  * For this function to work, @nb must be a member of an object of type
 455  * struct pm_clk_notifier_block containing all of the requisite data.
 456  * Specifically, the pm_domain member of that object is copied to the device's
 457  * pm_domain field and its con_ids member is used to populate the device's list
 458  * of PM clocks, depending on @action.
 459  *
 460  * If the device's pm_domain field is already populated with a value different
 461  * from the one stored in the struct pm_clk_notifier_block object, the function
 462  * does nothing.
 463  */
 464 static int pm_clk_notify(struct notifier_block *nb,
 465                                  unsigned long action, void *data)
 466 {
 467         struct pm_clk_notifier_block *clknb;
 468         struct device *dev = data;
 469         char **con_id;
 470         int error;
 471 
 472         dev_dbg(dev, "%s() %ld\n", __func__, action);
 473 
 474         clknb = container_of(nb, struct pm_clk_notifier_block, nb);
 475 
 476         switch (action) {
 477         case BUS_NOTIFY_ADD_DEVICE:
 478                 if (dev->pm_domain)
 479                         break;
 480 
 481                 error = pm_clk_create(dev);
 482                 if (error)
 483                         break;
 484 
 485                 dev_pm_domain_set(dev, clknb->pm_domain);
 486                 if (clknb->con_ids[0]) {
 487                         for (con_id = clknb->con_ids; *con_id; con_id++)
 488                                 pm_clk_add(dev, *con_id);
 489                 } else {
 490                         pm_clk_add(dev, NULL);
 491                 }
 492 
 493                 break;
 494         case BUS_NOTIFY_DEL_DEVICE:
 495                 if (dev->pm_domain != clknb->pm_domain)
 496                         break;
 497 
 498                 dev_pm_domain_set(dev, NULL);
 499                 pm_clk_destroy(dev);
 500                 break;
 501         }
 502 
 503         return 0;
 504 }
 505 
 506 int pm_clk_runtime_suspend(struct device *dev)
 507 {
 508         int ret;
 509 
 510         dev_dbg(dev, "%s\n", __func__);
 511 
 512         ret = pm_generic_runtime_suspend(dev);
 513         if (ret) {
 514                 dev_err(dev, "failed to suspend device\n");
 515                 return ret;
 516         }
 517 
 518         ret = pm_clk_suspend(dev);
 519         if (ret) {
 520                 dev_err(dev, "failed to suspend clock\n");
 521                 pm_generic_runtime_resume(dev);
 522                 return ret;
 523         }
 524 
 525         return 0;
 526 }
 527 EXPORT_SYMBOL_GPL(pm_clk_runtime_suspend);
 528 
 529 int pm_clk_runtime_resume(struct device *dev)
 530 {
 531         int ret;
 532 
 533         dev_dbg(dev, "%s\n", __func__);
 534 
 535         ret = pm_clk_resume(dev);
 536         if (ret) {
 537                 dev_err(dev, "failed to resume clock\n");
 538                 return ret;
 539         }
 540 
 541         return pm_generic_runtime_resume(dev);
 542 }
 543 EXPORT_SYMBOL_GPL(pm_clk_runtime_resume);
 544 
 545 #else /* !CONFIG_PM_CLK */
 546 
 547 /**
 548  * enable_clock - Enable a device clock.
 549  * @dev: Device whose clock is to be enabled.
 550  * @con_id: Connection ID of the clock.
 551  */
 552 static void enable_clock(struct device *dev, const char *con_id)
 553 {
 554         struct clk *clk;
 555 
 556         clk = clk_get(dev, con_id);
 557         if (!IS_ERR(clk)) {
 558                 clk_prepare_enable(clk);
 559                 clk_put(clk);
 560                 dev_info(dev, "Runtime PM disabled, clock forced on.\n");
 561         }
 562 }
 563 
 564 /**
 565  * disable_clock - Disable a device clock.
 566  * @dev: Device whose clock is to be disabled.
 567  * @con_id: Connection ID of the clock.
 568  */
 569 static void disable_clock(struct device *dev, const char *con_id)
 570 {
 571         struct clk *clk;
 572 
 573         clk = clk_get(dev, con_id);
 574         if (!IS_ERR(clk)) {
 575                 clk_disable_unprepare(clk);
 576                 clk_put(clk);
 577                 dev_info(dev, "Runtime PM disabled, clock forced off.\n");
 578         }
 579 }
 580 
 581 /**
 582  * pm_clk_notify - Notify routine for device addition and removal.
 583  * @nb: Notifier block object this function is a member of.
 584  * @action: Operation being carried out by the caller.
 585  * @data: Device the routine is being run for.
 586  *
 587  * For this function to work, @nb must be a member of an object of type
 588  * struct pm_clk_notifier_block containing all of the requisite data.
 589  * Specifically, the con_ids member of that object is used to enable or disable
 590  * the device's clocks, depending on @action.
 591  */
 592 static int pm_clk_notify(struct notifier_block *nb,
 593                                  unsigned long action, void *data)
 594 {
 595         struct pm_clk_notifier_block *clknb;
 596         struct device *dev = data;
 597         char **con_id;
 598 
 599         dev_dbg(dev, "%s() %ld\n", __func__, action);
 600 
 601         clknb = container_of(nb, struct pm_clk_notifier_block, nb);
 602 
 603         switch (action) {
 604         case BUS_NOTIFY_BIND_DRIVER:
 605                 if (clknb->con_ids[0]) {
 606                         for (con_id = clknb->con_ids; *con_id; con_id++)
 607                                 enable_clock(dev, *con_id);
 608                 } else {
 609                         enable_clock(dev, NULL);
 610                 }
 611                 break;
 612         case BUS_NOTIFY_DRIVER_NOT_BOUND:
 613         case BUS_NOTIFY_UNBOUND_DRIVER:
 614                 if (clknb->con_ids[0]) {
 615                         for (con_id = clknb->con_ids; *con_id; con_id++)
 616                                 disable_clock(dev, *con_id);
 617                 } else {
 618                         disable_clock(dev, NULL);
 619                 }
 620                 break;
 621         }
 622 
 623         return 0;
 624 }
 625 
 626 #endif /* !CONFIG_PM_CLK */
 627 
 628 /**
 629  * pm_clk_add_notifier - Add bus type notifier for power management clocks.
 630  * @bus: Bus type to add the notifier to.
 631  * @clknb: Notifier to be added to the given bus type.
 632  *
 633  * The nb member of @clknb is not expected to be initialized and its
 634  * notifier_call member will be replaced with pm_clk_notify().  However,
 635  * the remaining members of @clknb should be populated prior to calling this
 636  * routine.
 637  */
 638 void pm_clk_add_notifier(struct bus_type *bus,
 639                                  struct pm_clk_notifier_block *clknb)
 640 {
 641         if (!bus || !clknb)
 642                 return;
 643 
 644         clknb->nb.notifier_call = pm_clk_notify;
 645         bus_register_notifier(bus, &clknb->nb);
 646 }
 647 EXPORT_SYMBOL_GPL(pm_clk_add_notifier);

/* [<][>][^][v][top][bottom][index][help] */