linux/arch/arm/plat-omap/omap_device.c
<<
>>
Prefs
   1/*
   2 * omap_device implementation
   3 *
   4 * Copyright (C) 2009 Nokia Corporation
   5 * Paul Walmsley
   6 *
   7 * Developed in collaboration with (alphabetical order): Benoit
   8 * Cousson, Kevin Hilman, Tony Lindgren, Rajendra Nayak, Vikram
   9 * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
  10 * Woodruff
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 * This code provides a consistent interface for OMAP device drivers
  17 * to control power management and interconnect properties of their
  18 * devices.
  19 *
  20 * In the medium- to long-term, this code should either be
  21 * a) implemented via arch-specific pointers in platform_data
  22 * or
  23 * b) implemented as a proper omap_bus/omap_device in Linux, no more
  24 *    platform_data func pointers
  25 *
  26 *
  27 * Guidelines for usage by driver authors:
  28 *
  29 * 1. These functions are intended to be used by device drivers via
  30 * function pointers in struct platform_data.  As an example,
  31 * omap_device_enable() should be passed to the driver as
  32 *
  33 * struct foo_driver_platform_data {
  34 * ...
  35 *      int (*device_enable)(struct platform_device *pdev);
  36 * ...
  37 * }
  38 *
  39 * Note that the generic "device_enable" name is used, rather than
  40 * "omap_device_enable".  This is so other architectures can pass in their
  41 * own enable/disable functions here.
  42 *
  43 * This should be populated during device setup:
  44 *
  45 * ...
  46 * pdata->device_enable = omap_device_enable;
  47 * ...
  48 *
  49 * 2. Drivers should first check to ensure the function pointer is not null
  50 * before calling it, as in:
  51 *
  52 * if (pdata->device_enable)
  53 *     pdata->device_enable(pdev);
  54 *
  55 * This allows other architectures that don't use similar device_enable()/
  56 * device_shutdown() functions to execute normally.
  57 *
  58 * ...
  59 *
  60 * Suggested usage by device drivers:
  61 *
  62 * During device initialization:
  63 * device_enable()
  64 *
  65 * During device idle:
  66 * (save remaining device context if necessary)
  67 * device_idle();
  68 *
  69 * During device resume:
  70 * device_enable();
  71 * (restore context if necessary)
  72 *
  73 * During device shutdown:
  74 * device_shutdown()
  75 * (device must be reinitialized at this point to use it again)
  76 *
  77 */
  78#undef DEBUG
  79
  80#include <linux/kernel.h>
  81#include <linux/platform_device.h>
  82#include <linux/err.h>
  83#include <linux/io.h>
  84
  85#include <mach/omap_device.h>
  86#include <mach/omap_hwmod.h>
  87
  88/* These parameters are passed to _omap_device_{de,}activate() */
  89#define USE_WAKEUP_LAT                  0
  90#define IGNORE_WAKEUP_LAT               1
  91
  92/* XXX this should be moved into a separate file */
  93#if defined(CONFIG_ARCH_OMAP2420)
  94# define OMAP_32KSYNCT_BASE             0x48004000
  95#elif defined(CONFIG_ARCH_OMAP2430)
  96# define OMAP_32KSYNCT_BASE             0x49020000
  97#elif defined(CONFIG_ARCH_OMAP3430)
  98# define OMAP_32KSYNCT_BASE             0x48320000
  99#else
 100# error Unknown OMAP device
 101#endif
 102
 103/* Private functions */
 104
 105/**
 106 * _read_32ksynct - read the OMAP 32K sync timer
 107 *
 108 * Returns the current value of the 32KiHz synchronization counter.
 109 * XXX this should be generalized to simply read the system clocksource.
 110 * XXX this should be moved to a separate synctimer32k.c file
 111 */
 112static u32 _read_32ksynct(void)
 113{
 114        if (!cpu_class_is_omap2())
 115                BUG();
 116
 117        return __raw_readl(OMAP2_IO_ADDRESS(OMAP_32KSYNCT_BASE + 0x010));
 118}
 119
 120/**
 121 * _omap_device_activate - increase device readiness
 122 * @od: struct omap_device *
 123 * @ignore_lat: increase to latency target (0) or full readiness (1)?
 124 *
 125 * Increase readiness of omap_device @od (thus decreasing device
 126 * wakeup latency, but consuming more power).  If @ignore_lat is
 127 * IGNORE_WAKEUP_LAT, make the omap_device fully active.  Otherwise,
 128 * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
 129 * latency is greater than the requested maximum wakeup latency, step
 130 * backwards in the omap_device_pm_latency table to ensure the
 131 * device's maximum wakeup latency is less than or equal to the
 132 * requested maximum wakeup latency.  Returns 0.
 133 */
 134static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
 135{
 136        u32 a, b;
 137
 138        pr_debug("omap_device: %s: activating\n", od->pdev.name);
 139
 140        while (od->pm_lat_level > 0) {
 141                struct omap_device_pm_latency *odpl;
 142                int act_lat = 0;
 143
 144                od->pm_lat_level--;
 145
 146                odpl = od->pm_lats + od->pm_lat_level;
 147
 148                if (!ignore_lat &&
 149                    (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
 150                        break;
 151
 152                a = _read_32ksynct();
 153
 154                /* XXX check return code */
 155                odpl->activate_func(od);
 156
 157                b = _read_32ksynct();
 158
 159                act_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
 160
 161                pr_debug("omap_device: %s: pm_lat %d: activate: elapsed time "
 162                         "%d usec\n", od->pdev.name, od->pm_lat_level, act_lat);
 163
 164                WARN(act_lat > odpl->activate_lat, "omap_device: %s.%d: "
 165                     "activate step %d took longer than expected (%d > %d)\n",
 166                     od->pdev.name, od->pdev.id, od->pm_lat_level,
 167                     act_lat, odpl->activate_lat);
 168
 169                od->dev_wakeup_lat -= odpl->activate_lat;
 170        }
 171
 172        return 0;
 173}
 174
 175/**
 176 * _omap_device_deactivate - decrease device readiness
 177 * @od: struct omap_device *
 178 * @ignore_lat: decrease to latency target (0) or full inactivity (1)?
 179 *
 180 * Decrease readiness of omap_device @od (thus increasing device
 181 * wakeup latency, but conserving power).  If @ignore_lat is
 182 * IGNORE_WAKEUP_LAT, make the omap_device fully inactive.  Otherwise,
 183 * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
 184 * latency is less than the requested maximum wakeup latency, step
 185 * forwards in the omap_device_pm_latency table to ensure the device's
 186 * maximum wakeup latency is less than or equal to the requested
 187 * maximum wakeup latency.  Returns 0.
 188 */
 189static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
 190{
 191        u32 a, b;
 192
 193        pr_debug("omap_device: %s: deactivating\n", od->pdev.name);
 194
 195        while (od->pm_lat_level < od->pm_lats_cnt) {
 196                struct omap_device_pm_latency *odpl;
 197                int deact_lat = 0;
 198
 199                odpl = od->pm_lats + od->pm_lat_level;
 200
 201                if (!ignore_lat &&
 202                    ((od->dev_wakeup_lat + odpl->activate_lat) >
 203                     od->_dev_wakeup_lat_limit))
 204                        break;
 205
 206                a = _read_32ksynct();
 207
 208                /* XXX check return code */
 209                odpl->deactivate_func(od);
 210
 211                b = _read_32ksynct();
 212
 213                deact_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
 214
 215                pr_debug("omap_device: %s: pm_lat %d: deactivate: elapsed time "
 216                         "%d usec\n", od->pdev.name, od->pm_lat_level,
 217                         deact_lat);
 218
 219                WARN(deact_lat > odpl->deactivate_lat, "omap_device: %s.%d: "
 220                     "deactivate step %d took longer than expected (%d > %d)\n",
 221                     od->pdev.name, od->pdev.id, od->pm_lat_level,
 222                     deact_lat, odpl->deactivate_lat);
 223
 224                od->dev_wakeup_lat += odpl->activate_lat;
 225
 226                od->pm_lat_level++;
 227        }
 228
 229        return 0;
 230}
 231
 232static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
 233{
 234        return container_of(pdev, struct omap_device, pdev);
 235}
 236
 237
 238/* Public functions for use by core code */
 239
 240/**
 241 * omap_device_count_resources - count number of struct resource entries needed
 242 * @od: struct omap_device *
 243 *
 244 * Count the number of struct resource entries needed for this
 245 * omap_device @od.  Used by omap_device_build_ss() to determine how
 246 * much memory to allocate before calling
 247 * omap_device_fill_resources().  Returns the count.
 248 */
 249int omap_device_count_resources(struct omap_device *od)
 250{
 251        struct omap_hwmod *oh;
 252        int c = 0;
 253        int i;
 254
 255        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 256                c += omap_hwmod_count_resources(oh);
 257
 258        pr_debug("omap_device: %s: counted %d total resources across %d "
 259                 "hwmods\n", od->pdev.name, c, od->hwmods_cnt);
 260
 261        return c;
 262}
 263
 264/**
 265 * omap_device_fill_resources - fill in array of struct resource
 266 * @od: struct omap_device *
 267 * @res: pointer to an array of struct resource to be filled in
 268 *
 269 * Populate one or more empty struct resource pointed to by @res with
 270 * the resource data for this omap_device @od.  Used by
 271 * omap_device_build_ss() after calling omap_device_count_resources().
 272 * Ideally this function would not be needed at all.  If omap_device
 273 * replaces platform_device, then we can specify our own
 274 * get_resource()/ get_irq()/etc functions that use the underlying
 275 * omap_hwmod information.  Or if platform_device is extended to use
 276 * subarchitecture-specific function pointers, the various
 277 * platform_device functions can simply call omap_device internal
 278 * functions to get device resources.  Hacking around the existing
 279 * platform_device code wastes memory.  Returns 0.
 280 */
 281int omap_device_fill_resources(struct omap_device *od, struct resource *res)
 282{
 283        struct omap_hwmod *oh;
 284        int c = 0;
 285        int i, r;
 286
 287        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++) {
 288                r = omap_hwmod_fill_resources(oh, res);
 289                res += r;
 290                c += r;
 291        }
 292
 293        return 0;
 294}
 295
 296/**
 297 * omap_device_build - build and register an omap_device with one omap_hwmod
 298 * @pdev_name: name of the platform_device driver to use
 299 * @pdev_id: this platform_device's connection ID
 300 * @oh: ptr to the single omap_hwmod that backs this omap_device
 301 * @pdata: platform_data ptr to associate with the platform_device
 302 * @pdata_len: amount of memory pointed to by @pdata
 303 * @pm_lats: pointer to a omap_device_pm_latency array for this device
 304 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
 305 *
 306 * Convenience function for building and registering a single
 307 * omap_device record, which in turn builds and registers a
 308 * platform_device record.  See omap_device_build_ss() for more
 309 * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
 310 * passes along the return value of omap_device_build_ss().
 311 */
 312struct omap_device *omap_device_build(const char *pdev_name, int pdev_id,
 313                                      struct omap_hwmod *oh, void *pdata,
 314                                      int pdata_len,
 315                                      struct omap_device_pm_latency *pm_lats,
 316                                      int pm_lats_cnt)
 317{
 318        struct omap_hwmod *ohs[] = { oh };
 319
 320        if (!oh)
 321                return ERR_PTR(-EINVAL);
 322
 323        return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
 324                                    pdata_len, pm_lats, pm_lats_cnt);
 325}
 326
 327/**
 328 * omap_device_build_ss - build and register an omap_device with multiple hwmods
 329 * @pdev_name: name of the platform_device driver to use
 330 * @pdev_id: this platform_device's connection ID
 331 * @oh: ptr to the single omap_hwmod that backs this omap_device
 332 * @pdata: platform_data ptr to associate with the platform_device
 333 * @pdata_len: amount of memory pointed to by @pdata
 334 * @pm_lats: pointer to a omap_device_pm_latency array for this device
 335 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
 336 *
 337 * Convenience function for building and registering an omap_device
 338 * subsystem record.  Subsystem records consist of multiple
 339 * omap_hwmods.  This function in turn builds and registers a
 340 * platform_device record.  Returns an ERR_PTR() on error, or passes
 341 * along the return value of omap_device_register().
 342 */
 343struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
 344                                         struct omap_hwmod **ohs, int oh_cnt,
 345                                         void *pdata, int pdata_len,
 346                                         struct omap_device_pm_latency *pm_lats,
 347                                         int pm_lats_cnt)
 348{
 349        int ret = -ENOMEM;
 350        struct omap_device *od;
 351        char *pdev_name2;
 352        struct resource *res = NULL;
 353        int res_count;
 354        struct omap_hwmod **hwmods;
 355
 356        if (!ohs || oh_cnt == 0 || !pdev_name)
 357                return ERR_PTR(-EINVAL);
 358
 359        if (!pdata && pdata_len > 0)
 360                return ERR_PTR(-EINVAL);
 361
 362        pr_debug("omap_device: %s: building with %d hwmods\n", pdev_name,
 363                 oh_cnt);
 364
 365        od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
 366        if (!od)
 367                return ERR_PTR(-ENOMEM);
 368
 369        od->hwmods_cnt = oh_cnt;
 370
 371        hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt,
 372                         GFP_KERNEL);
 373        if (!hwmods)
 374                goto odbs_exit1;
 375
 376        memcpy(hwmods, ohs, sizeof(struct omap_hwmod *) * oh_cnt);
 377        od->hwmods = hwmods;
 378
 379        pdev_name2 = kzalloc(strlen(pdev_name) + 1, GFP_KERNEL);
 380        if (!pdev_name2)
 381                goto odbs_exit2;
 382        strcpy(pdev_name2, pdev_name);
 383
 384        od->pdev.name = pdev_name2;
 385        od->pdev.id = pdev_id;
 386
 387        res_count = omap_device_count_resources(od);
 388        if (res_count > 0) {
 389                res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
 390                if (!res)
 391                        goto odbs_exit3;
 392        }
 393        omap_device_fill_resources(od, res);
 394
 395        od->pdev.num_resources = res_count;
 396        od->pdev.resource = res;
 397
 398        platform_device_add_data(&od->pdev, pdata, pdata_len);
 399
 400        od->pm_lats = pm_lats;
 401        od->pm_lats_cnt = pm_lats_cnt;
 402
 403        ret = omap_device_register(od);
 404        if (ret)
 405                goto odbs_exit4;
 406
 407        return od;
 408
 409odbs_exit4:
 410        kfree(res);
 411odbs_exit3:
 412        kfree(pdev_name2);
 413odbs_exit2:
 414        kfree(hwmods);
 415odbs_exit1:
 416        kfree(od);
 417
 418        pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
 419
 420        return ERR_PTR(ret);
 421}
 422
 423/**
 424 * omap_device_register - register an omap_device with one omap_hwmod
 425 * @od: struct omap_device * to register
 426 *
 427 * Register the omap_device structure.  This currently just calls
 428 * platform_device_register() on the underlying platform_device.
 429 * Returns the return value of platform_device_register().
 430 */
 431int omap_device_register(struct omap_device *od)
 432{
 433        pr_debug("omap_device: %s: registering\n", od->pdev.name);
 434
 435        return platform_device_register(&od->pdev);
 436}
 437
 438
 439/* Public functions for use by device drivers through struct platform_data */
 440
 441/**
 442 * omap_device_enable - fully activate an omap_device
 443 * @od: struct omap_device * to activate
 444 *
 445 * Do whatever is necessary for the hwmods underlying omap_device @od
 446 * to be accessible and ready to operate.  This generally involves
 447 * enabling clocks, setting SYSCONFIG registers; and in the future may
 448 * involve remuxing pins.  Device drivers should call this function
 449 * (through platform_data function pointers) where they would normally
 450 * enable clocks, etc.  Returns -EINVAL if called when the omap_device
 451 * is already enabled, or passes along the return value of
 452 * _omap_device_activate().
 453 */
 454int omap_device_enable(struct platform_device *pdev)
 455{
 456        int ret;
 457        struct omap_device *od;
 458
 459        od = _find_by_pdev(pdev);
 460
 461        if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
 462                WARN(1, "omap_device: %s.%d: omap_device_enable() called from "
 463                     "invalid state\n", od->pdev.name, od->pdev.id);
 464                return -EINVAL;
 465        }
 466
 467        /* Enable everything if we're enabling this device from scratch */
 468        if (od->_state == OMAP_DEVICE_STATE_UNKNOWN)
 469                od->pm_lat_level = od->pm_lats_cnt;
 470
 471        ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT);
 472
 473        od->dev_wakeup_lat = 0;
 474        od->_dev_wakeup_lat_limit = INT_MAX;
 475        od->_state = OMAP_DEVICE_STATE_ENABLED;
 476
 477        return ret;
 478}
 479
 480/**
 481 * omap_device_idle - idle an omap_device
 482 * @od: struct omap_device * to idle
 483 *
 484 * Idle omap_device @od by calling as many .deactivate_func() entries
 485 * in the omap_device's pm_lats table as is possible without exceeding
 486 * the device's maximum wakeup latency limit, pm_lat_limit.  Device
 487 * drivers should call this function (through platform_data function
 488 * pointers) where they would normally disable clocks after operations
 489 * complete, etc..  Returns -EINVAL if the omap_device is not
 490 * currently enabled, or passes along the return value of
 491 * _omap_device_deactivate().
 492 */
 493int omap_device_idle(struct platform_device *pdev)
 494{
 495        int ret;
 496        struct omap_device *od;
 497
 498        od = _find_by_pdev(pdev);
 499
 500        if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
 501                WARN(1, "omap_device: %s.%d: omap_device_idle() called from "
 502                     "invalid state\n", od->pdev.name, od->pdev.id);
 503                return -EINVAL;
 504        }
 505
 506        ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
 507
 508        od->_state = OMAP_DEVICE_STATE_IDLE;
 509
 510        return ret;
 511}
 512
 513/**
 514 * omap_device_shutdown - shut down an omap_device
 515 * @od: struct omap_device * to shut down
 516 *
 517 * Shut down omap_device @od by calling all .deactivate_func() entries
 518 * in the omap_device's pm_lats table and then shutting down all of
 519 * the underlying omap_hwmods.  Used when a device is being "removed"
 520 * or a device driver is being unloaded.  Returns -EINVAL if the
 521 * omap_device is not currently enabled or idle, or passes along the
 522 * return value of _omap_device_deactivate().
 523 */
 524int omap_device_shutdown(struct platform_device *pdev)
 525{
 526        int ret, i;
 527        struct omap_device *od;
 528        struct omap_hwmod *oh;
 529
 530        od = _find_by_pdev(pdev);
 531
 532        if (od->_state != OMAP_DEVICE_STATE_ENABLED &&
 533            od->_state != OMAP_DEVICE_STATE_IDLE) {
 534                WARN(1, "omap_device: %s.%d: omap_device_shutdown() called "
 535                     "from invalid state\n", od->pdev.name, od->pdev.id);
 536                return -EINVAL;
 537        }
 538
 539        ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
 540
 541        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 542                omap_hwmod_shutdown(oh);
 543
 544        od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
 545
 546        return ret;
 547}
 548
 549/**
 550 * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim
 551 * @od: struct omap_device *
 552 *
 553 * When a device's maximum wakeup latency limit changes, call some of
 554 * the .activate_func or .deactivate_func function pointers in the
 555 * omap_device's pm_lats array to ensure that the device's maximum
 556 * wakeup latency is less than or equal to the new latency limit.
 557 * Intended to be called by OMAP PM code whenever a device's maximum
 558 * wakeup latency limit changes (e.g., via
 559 * omap_pm_set_dev_wakeup_lat()).  Returns 0 if nothing needs to be
 560 * done (e.g., if the omap_device is not currently idle, or if the
 561 * wakeup latency is already current with the new limit) or passes
 562 * along the return value of _omap_device_deactivate() or
 563 * _omap_device_activate().
 564 */
 565int omap_device_align_pm_lat(struct platform_device *pdev,
 566                             u32 new_wakeup_lat_limit)
 567{
 568        int ret = -EINVAL;
 569        struct omap_device *od;
 570
 571        od = _find_by_pdev(pdev);
 572
 573        if (new_wakeup_lat_limit == od->dev_wakeup_lat)
 574                return 0;
 575
 576        od->_dev_wakeup_lat_limit = new_wakeup_lat_limit;
 577
 578        if (od->_state != OMAP_DEVICE_STATE_IDLE)
 579                return 0;
 580        else if (new_wakeup_lat_limit > od->dev_wakeup_lat)
 581                ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
 582        else if (new_wakeup_lat_limit < od->dev_wakeup_lat)
 583                ret = _omap_device_activate(od, USE_WAKEUP_LAT);
 584
 585        return ret;
 586}
 587
 588/**
 589 * omap_device_get_pwrdm - return the powerdomain * associated with @od
 590 * @od: struct omap_device *
 591 *
 592 * Return the powerdomain associated with the first underlying
 593 * omap_hwmod for this omap_device.  Intended for use by core OMAP PM
 594 * code.  Returns NULL on error or a struct powerdomain * upon
 595 * success.
 596 */
 597struct powerdomain *omap_device_get_pwrdm(struct omap_device *od)
 598{
 599        /*
 600         * XXX Assumes that all omap_hwmod powerdomains are identical.
 601         * This may not necessarily be true.  There should be a sanity
 602         * check in here to WARN() if any difference appears.
 603         */
 604        if (!od->hwmods_cnt)
 605                return NULL;
 606
 607        return omap_hwmod_get_pwrdm(od->hwmods[0]);
 608}
 609
 610/*
 611 * Public functions intended for use in omap_device_pm_latency
 612 * .activate_func and .deactivate_func function pointers
 613 */
 614
 615/**
 616 * omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
 617 * @od: struct omap_device *od
 618 *
 619 * Enable all underlying hwmods.  Returns 0.
 620 */
 621int omap_device_enable_hwmods(struct omap_device *od)
 622{
 623        struct omap_hwmod *oh;
 624        int i;
 625
 626        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 627                omap_hwmod_enable(oh);
 628
 629        /* XXX pass along return value here? */
 630        return 0;
 631}
 632
 633/**
 634 * omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
 635 * @od: struct omap_device *od
 636 *
 637 * Idle all underlying hwmods.  Returns 0.
 638 */
 639int omap_device_idle_hwmods(struct omap_device *od)
 640{
 641        struct omap_hwmod *oh;
 642        int i;
 643
 644        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 645                omap_hwmod_idle(oh);
 646
 647        /* XXX pass along return value here? */
 648        return 0;
 649}
 650
 651/**
 652 * omap_device_disable_clocks - disable all main and interface clocks
 653 * @od: struct omap_device *od
 654 *
 655 * Disable the main functional clock and interface clock for all of the
 656 * omap_hwmods associated with the omap_device.  Returns 0.
 657 */
 658int omap_device_disable_clocks(struct omap_device *od)
 659{
 660        struct omap_hwmod *oh;
 661        int i;
 662
 663        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 664                omap_hwmod_disable_clocks(oh);
 665
 666        /* XXX pass along return value here? */
 667        return 0;
 668}
 669
 670/**
 671 * omap_device_enable_clocks - enable all main and interface clocks
 672 * @od: struct omap_device *od
 673 *
 674 * Enable the main functional clock and interface clock for all of the
 675 * omap_hwmods associated with the omap_device.  Returns 0.
 676 */
 677int omap_device_enable_clocks(struct omap_device *od)
 678{
 679        struct omap_hwmod *oh;
 680        int i;
 681
 682        for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
 683                omap_hwmod_enable_clocks(oh);
 684
 685        /* XXX pass along return value here? */
 686        return 0;
 687}
 688