linux/drivers/base/power/clock_ops.c
<<
>>
Prefs
   1/*
   2 * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
   3 *
   4 * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
   5 *
   6 * This file is released under the GPLv2.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/io.h>
  13#include <linux/pm.h>
  14#include <linux/pm_clock.h>
  15#include <linux/clk.h>
  16#include <linux/slab.h>
  17#include <linux/err.h>
  18
  19#ifdef CONFIG_PM
  20
  21enum pce_status {
  22        PCE_STATUS_NONE = 0,
  23        PCE_STATUS_ACQUIRED,
  24        PCE_STATUS_ENABLED,
  25        PCE_STATUS_ERROR,
  26};
  27
  28struct pm_clock_entry {
  29        struct list_head node;
  30        char *con_id;
  31        struct clk *clk;
  32        enum pce_status status;
  33};
  34
  35/**
  36 * pm_clk_acquire - Acquire a device clock.
  37 * @dev: Device whose clock is to be acquired.
  38 * @ce: PM clock entry corresponding to the clock.
  39 */
  40static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
  41{
  42        ce->clk = clk_get(dev, ce->con_id);
  43        if (IS_ERR(ce->clk)) {
  44                ce->status = PCE_STATUS_ERROR;
  45        } else {
  46                ce->status = PCE_STATUS_ACQUIRED;
  47                dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
  48        }
  49}
  50
  51/**
  52 * pm_clk_add - Start using a device clock for power management.
  53 * @dev: Device whose clock is going to be used for power management.
  54 * @con_id: Connection ID of the clock.
  55 *
  56 * Add the clock represented by @con_id to the list of clocks used for
  57 * the power management of @dev.
  58 */
  59int pm_clk_add(struct device *dev, const char *con_id)
  60{
  61        struct pm_subsys_data *psd = dev_to_psd(dev);
  62        struct pm_clock_entry *ce;
  63
  64        if (!psd)
  65                return -EINVAL;
  66
  67        ce = kzalloc(sizeof(*ce), GFP_KERNEL);
  68        if (!ce) {
  69                dev_err(dev, "Not enough memory for clock entry.\n");
  70                return -ENOMEM;
  71        }
  72
  73        if (con_id) {
  74                ce->con_id = kstrdup(con_id, GFP_KERNEL);
  75                if (!ce->con_id) {
  76                        dev_err(dev,
  77                                "Not enough memory for clock connection ID.\n");
  78                        kfree(ce);
  79                        return -ENOMEM;
  80                }
  81        }
  82
  83        pm_clk_acquire(dev, ce);
  84
  85        spin_lock_irq(&psd->lock);
  86        list_add_tail(&ce->node, &psd->clock_list);
  87        spin_unlock_irq(&psd->lock);
  88        return 0;
  89}
  90
  91/**
  92 * __pm_clk_remove - Destroy PM clock entry.
  93 * @ce: PM clock entry to destroy.
  94 */
  95static void __pm_clk_remove(struct pm_clock_entry *ce)
  96{
  97        if (!ce)
  98                return;
  99
 100        if (ce->status < PCE_STATUS_ERROR) {
 101                if (ce->status == PCE_STATUS_ENABLED)
 102                        clk_disable_unprepare(ce->clk);
 103
 104                if (ce->status >= PCE_STATUS_ACQUIRED)
 105                        clk_put(ce->clk);
 106        }
 107
 108        kfree(ce->con_id);
 109        kfree(ce);
 110}
 111
 112/**
 113 * pm_clk_remove - Stop using a device clock for power management.
 114 * @dev: Device whose clock should not be used for PM any more.
 115 * @con_id: Connection ID of the clock.
 116 *
 117 * Remove the clock represented by @con_id from the list of clocks used for
 118 * the power management of @dev.
 119 */
 120void pm_clk_remove(struct device *dev, const char *con_id)
 121{
 122        struct pm_subsys_data *psd = dev_to_psd(dev);
 123        struct pm_clock_entry *ce;
 124
 125        if (!psd)
 126                return;
 127
 128        spin_lock_irq(&psd->lock);
 129
 130        list_for_each_entry(ce, &psd->clock_list, node) {
 131                if (!con_id && !ce->con_id)
 132                        goto remove;
 133                else if (!con_id || !ce->con_id)
 134                        continue;
 135                else if (!strcmp(con_id, ce->con_id))
 136                        goto remove;
 137        }
 138
 139        spin_unlock_irq(&psd->lock);
 140        return;
 141
 142 remove:
 143        list_del(&ce->node);
 144        spin_unlock_irq(&psd->lock);
 145
 146        __pm_clk_remove(ce);
 147}
 148
 149/**
 150 * pm_clk_init - Initialize a device's list of power management clocks.
 151 * @dev: Device to initialize the list of PM clocks for.
 152 *
 153 * Initialize the lock and clock_list members of the device's pm_subsys_data
 154 * object.
 155 */
 156void pm_clk_init(struct device *dev)
 157{
 158        struct pm_subsys_data *psd = dev_to_psd(dev);
 159        if (psd)
 160                INIT_LIST_HEAD(&psd->clock_list);
 161}
 162
 163/**
 164 * pm_clk_create - Create and initialize a device's list of PM clocks.
 165 * @dev: Device to create and initialize the list of PM clocks for.
 166 *
 167 * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
 168 * members and make the @dev's power.subsys_data field point to it.
 169 */
 170int pm_clk_create(struct device *dev)
 171{
 172        return dev_pm_get_subsys_data(dev);
 173}
 174
 175/**
 176 * pm_clk_destroy - Destroy a device's list of power management clocks.
 177 * @dev: Device to destroy the list of PM clocks for.
 178 *
 179 * Clear the @dev's power.subsys_data field, remove the list of clock entries
 180 * from the struct pm_subsys_data object pointed to by it before and free
 181 * that object.
 182 */
 183void pm_clk_destroy(struct device *dev)
 184{
 185        struct pm_subsys_data *psd = dev_to_psd(dev);
 186        struct pm_clock_entry *ce, *c;
 187        struct list_head list;
 188
 189        if (!psd)
 190                return;
 191
 192        INIT_LIST_HEAD(&list);
 193
 194        spin_lock_irq(&psd->lock);
 195
 196        list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
 197                list_move(&ce->node, &list);
 198
 199        spin_unlock_irq(&psd->lock);
 200
 201        dev_pm_put_subsys_data(dev);
 202
 203        list_for_each_entry_safe_reverse(ce, c, &list, node) {
 204                list_del(&ce->node);
 205                __pm_clk_remove(ce);
 206        }
 207}
 208
 209#endif /* CONFIG_PM */
 210
 211#ifdef CONFIG_PM_RUNTIME
 212
 213/**
 214 * pm_clk_suspend - Disable clocks in a device's PM clock list.
 215 * @dev: Device to disable the clocks for.
 216 */
 217int pm_clk_suspend(struct device *dev)
 218{
 219        struct pm_subsys_data *psd = dev_to_psd(dev);
 220        struct pm_clock_entry *ce;
 221        unsigned long flags;
 222
 223        dev_dbg(dev, "%s()\n", __func__);
 224
 225        if (!psd)
 226                return 0;
 227
 228        spin_lock_irqsave(&psd->lock, flags);
 229
 230        list_for_each_entry_reverse(ce, &psd->clock_list, node) {
 231                if (ce->status < PCE_STATUS_ERROR) {
 232                        if (ce->status == PCE_STATUS_ENABLED)
 233                                clk_disable(ce->clk);
 234                        ce->status = PCE_STATUS_ACQUIRED;
 235                }
 236        }
 237
 238        spin_unlock_irqrestore(&psd->lock, flags);
 239
 240        return 0;
 241}
 242
 243/**
 244 * pm_clk_resume - Enable clocks in a device's PM clock list.
 245 * @dev: Device to enable the clocks for.
 246 */
 247int pm_clk_resume(struct device *dev)
 248{
 249        struct pm_subsys_data *psd = dev_to_psd(dev);
 250        struct pm_clock_entry *ce;
 251        unsigned long flags;
 252
 253        dev_dbg(dev, "%s()\n", __func__);
 254
 255        if (!psd)
 256                return 0;
 257
 258        spin_lock_irqsave(&psd->lock, flags);
 259
 260        list_for_each_entry(ce, &psd->clock_list, node) {
 261                if (ce->status < PCE_STATUS_ERROR) {
 262                        clk_enable(ce->clk);
 263                        ce->status = PCE_STATUS_ENABLED;
 264                }
 265        }
 266
 267        spin_unlock_irqrestore(&psd->lock, flags);
 268
 269        return 0;
 270}
 271
 272/**
 273 * pm_clk_notify - Notify routine for device addition and removal.
 274 * @nb: Notifier block object this function is a member of.
 275 * @action: Operation being carried out by the caller.
 276 * @data: Device the routine is being run for.
 277 *
 278 * For this function to work, @nb must be a member of an object of type
 279 * struct pm_clk_notifier_block containing all of the requisite data.
 280 * Specifically, the pm_domain member of that object is copied to the device's
 281 * pm_domain field and its con_ids member is used to populate the device's list
 282 * of PM clocks, depending on @action.
 283 *
 284 * If the device's pm_domain field is already populated with a value different
 285 * from the one stored in the struct pm_clk_notifier_block object, the function
 286 * does nothing.
 287 */
 288static int pm_clk_notify(struct notifier_block *nb,
 289                                 unsigned long action, void *data)
 290{
 291        struct pm_clk_notifier_block *clknb;
 292        struct device *dev = data;
 293        char **con_id;
 294        int error;
 295
 296        dev_dbg(dev, "%s() %ld\n", __func__, action);
 297
 298        clknb = container_of(nb, struct pm_clk_notifier_block, nb);
 299
 300        switch (action) {
 301        case BUS_NOTIFY_ADD_DEVICE:
 302                if (dev->pm_domain)
 303                        break;
 304
 305                error = pm_clk_create(dev);
 306                if (error)
 307                        break;
 308
 309                dev->pm_domain = clknb->pm_domain;
 310                if (clknb->con_ids[0]) {
 311                        for (con_id = clknb->con_ids; *con_id; con_id++)
 312                                pm_clk_add(dev, *con_id);
 313                } else {
 314                        pm_clk_add(dev, NULL);
 315                }
 316
 317                break;
 318        case BUS_NOTIFY_DEL_DEVICE:
 319                if (dev->pm_domain != clknb->pm_domain)
 320                        break;
 321
 322                dev->pm_domain = NULL;
 323                pm_clk_destroy(dev);
 324                break;
 325        }
 326
 327        return 0;
 328}
 329
 330#else /* !CONFIG_PM_RUNTIME */
 331
 332#ifdef CONFIG_PM
 333
 334/**
 335 * pm_clk_suspend - Disable clocks in a device's PM clock list.
 336 * @dev: Device to disable the clocks for.
 337 */
 338int pm_clk_suspend(struct device *dev)
 339{
 340        struct pm_subsys_data *psd = dev_to_psd(dev);
 341        struct pm_clock_entry *ce;
 342        unsigned long flags;
 343
 344        dev_dbg(dev, "%s()\n", __func__);
 345
 346        /* If there is no driver, the clocks are already disabled. */
 347        if (!psd || !dev->driver)
 348                return 0;
 349
 350        spin_lock_irqsave(&psd->lock, flags);
 351
 352        list_for_each_entry_reverse(ce, &psd->clock_list, node)
 353                clk_disable(ce->clk);
 354
 355        spin_unlock_irqrestore(&psd->lock, flags);
 356
 357        return 0;
 358}
 359
 360/**
 361 * pm_clk_resume - Enable clocks in a device's PM clock list.
 362 * @dev: Device to enable the clocks for.
 363 */
 364int pm_clk_resume(struct device *dev)
 365{
 366        struct pm_subsys_data *psd = dev_to_psd(dev);
 367        struct pm_clock_entry *ce;
 368        unsigned long flags;
 369
 370        dev_dbg(dev, "%s()\n", __func__);
 371
 372        /* If there is no driver, the clocks should remain disabled. */
 373        if (!psd || !dev->driver)
 374                return 0;
 375
 376        spin_lock_irqsave(&psd->lock, flags);
 377
 378        list_for_each_entry(ce, &psd->clock_list, node)
 379                clk_enable(ce->clk);
 380
 381        spin_unlock_irqrestore(&psd->lock, flags);
 382
 383        return 0;
 384}
 385
 386#endif /* CONFIG_PM */
 387
 388/**
 389 * enable_clock - Enable a device clock.
 390 * @dev: Device whose clock is to be enabled.
 391 * @con_id: Connection ID of the clock.
 392 */
 393static void enable_clock(struct device *dev, const char *con_id)
 394{
 395        struct clk *clk;
 396
 397        clk = clk_get(dev, con_id);
 398        if (!IS_ERR(clk)) {
 399                clk_prepare_enable(clk);
 400                clk_put(clk);
 401                dev_info(dev, "Runtime PM disabled, clock forced on.\n");
 402        }
 403}
 404
 405/**
 406 * disable_clock - Disable a device clock.
 407 * @dev: Device whose clock is to be disabled.
 408 * @con_id: Connection ID of the clock.
 409 */
 410static void disable_clock(struct device *dev, const char *con_id)
 411{
 412        struct clk *clk;
 413
 414        clk = clk_get(dev, con_id);
 415        if (!IS_ERR(clk)) {
 416                clk_disable_unprepare(clk);
 417                clk_put(clk);
 418                dev_info(dev, "Runtime PM disabled, clock forced off.\n");
 419        }
 420}
 421
 422/**
 423 * pm_clk_notify - Notify routine for device addition and removal.
 424 * @nb: Notifier block object this function is a member of.
 425 * @action: Operation being carried out by the caller.
 426 * @data: Device the routine is being run for.
 427 *
 428 * For this function to work, @nb must be a member of an object of type
 429 * struct pm_clk_notifier_block containing all of the requisite data.
 430 * Specifically, the con_ids member of that object is used to enable or disable
 431 * the device's clocks, depending on @action.
 432 */
 433static int pm_clk_notify(struct notifier_block *nb,
 434                                 unsigned long action, void *data)
 435{
 436        struct pm_clk_notifier_block *clknb;
 437        struct device *dev = data;
 438        char **con_id;
 439
 440        dev_dbg(dev, "%s() %ld\n", __func__, action);
 441
 442        clknb = container_of(nb, struct pm_clk_notifier_block, nb);
 443
 444        switch (action) {
 445        case BUS_NOTIFY_BIND_DRIVER:
 446                if (clknb->con_ids[0]) {
 447                        for (con_id = clknb->con_ids; *con_id; con_id++)
 448                                enable_clock(dev, *con_id);
 449                } else {
 450                        enable_clock(dev, NULL);
 451                }
 452                break;
 453        case BUS_NOTIFY_UNBOUND_DRIVER:
 454                if (clknb->con_ids[0]) {
 455                        for (con_id = clknb->con_ids; *con_id; con_id++)
 456                                disable_clock(dev, *con_id);
 457                } else {
 458                        disable_clock(dev, NULL);
 459                }
 460                break;
 461        }
 462
 463        return 0;
 464}
 465
 466#endif /* !CONFIG_PM_RUNTIME */
 467
 468/**
 469 * pm_clk_add_notifier - Add bus type notifier for power management clocks.
 470 * @bus: Bus type to add the notifier to.
 471 * @clknb: Notifier to be added to the given bus type.
 472 *
 473 * The nb member of @clknb is not expected to be initialized and its
 474 * notifier_call member will be replaced with pm_clk_notify().  However,
 475 * the remaining members of @clknb should be populated prior to calling this
 476 * routine.
 477 */
 478void pm_clk_add_notifier(struct bus_type *bus,
 479                                 struct pm_clk_notifier_block *clknb)
 480{
 481        if (!bus || !clknb)
 482                return;
 483
 484        clknb->nb.notifier_call = pm_clk_notify;
 485        bus_register_notifier(bus, &clknb->nb);
 486}
 487