linux/arch/arm/plat-omap/omap_device.c
<<
>>
Prefs
   1/*
   2 * omap_device implementation
   3 *
   4 * Copyright (C) 2009-2010 Nokia Corporation
   5 * Paul Walmsley, Kevin Hilman
   6 *
   7 * Developed in collaboration with (alphabetical order): Benoit
   8 * Cousson, Thara Gopinath, 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/slab.h>
  83#include <linux/err.h>
  84#include <linux/io.h>
  85#include <linux/clk.h>
  86#include <linux/clkdev.h>
  87
  88#include <plat/omap_device.h>
  89#include <plat/omap_hwmod.h>
  90#include <plat/clock.h>
  91
  92/* These parameters are passed to _omap_device_{de,}activate() */
  93#define USE_WAKEUP_LAT                  0
  94#define IGNORE_WAKEUP_LAT               1
  95
  96/* Private functions */
  97
  98/**
  99 * _omap_device_activate - increase device readiness
 100 * @od: struct omap_device *
 101 * @ignore_lat: increase to latency target (0) or full readiness (1)?
 102 *
 103 * Increase readiness of omap_device @od (thus decreasing device
 104 * wakeup latency, but consuming more power).  If @ignore_lat is
 105 * IGNORE_WAKEUP_LAT, make the omap_device fully active.  Otherwise,
 106 * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
 107 * latency is greater than the requested maximum wakeup latency, step
 108 * backwards in the omap_device_pm_latency table to ensure the
 109 * device's maximum wakeup latency is less than or equal to the
 110 * requested maximum wakeup latency.  Returns 0.
 111 */
 112static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
 113{
 114        struct timespec a, b, c;
 115
 116        pr_debug("omap_device: %s: activating\n", od->pdev.name);
 117
 118        while (od->pm_lat_level > 0) {
 119                struct omap_device_pm_latency *odpl;
 120                unsigned long long act_lat = 0;
 121
 122                od->pm_lat_level--;
 123
 124                odpl = od->pm_lats + od->pm_lat_level;
 125
 126                if (!ignore_lat &&
 127                    (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
 128                        break;
 129
 130                read_persistent_clock(&a);
 131
 132                /* XXX check return code */
 133                odpl->activate_func(od);
 134
 135                read_persistent_clock(&b);
 136
 137                c = timespec_sub(b, a);
 138                act_lat = timespec_to_ns(&c);
 139
 140                pr_debug("omap_device: %s: pm_lat %d: activate: elapsed time "
 141                         "%llu nsec\n", od->pdev.name, od->pm_lat_level,
 142                         act_lat);
 143
 144                if (act_lat > odpl->activate_lat) {
 145                        odpl->activate_lat_worst = act_lat;
 146                        if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 147                                odpl->activate_lat = act_lat;
 148                                pr_warning("omap_device: %s.%d: new worst case "
 149                                           "activate latency %d: %llu\n",
 150                                           od->pdev.name, od->pdev.id,
 151                                           od->pm_lat_level, act_lat);
 152                        } else
 153                                pr_warning("omap_device: %s.%d: activate "
 154                                           "latency %d higher than exptected. "
 155                                           "(%llu > %d)\n",
 156                                           od->pdev.name, od->pdev.id,
 157                                           od->pm_lat_level, act_lat,
 158                                           odpl->activate_lat);
 159                }
 160
 161                od->dev_wakeup_lat -= odpl->activate_lat;
 162        }
 163
 164        return 0;
 165}
 166
 167/**
 168 * _omap_device_deactivate - decrease device readiness
 169 * @od: struct omap_device *
 170 * @ignore_lat: decrease to latency target (0) or full inactivity (1)?
 171 *
 172 * Decrease readiness of omap_device @od (thus increasing device
 173 * wakeup latency, but conserving power).  If @ignore_lat is
 174 * IGNORE_WAKEUP_LAT, make the omap_device fully inactive.  Otherwise,
 175 * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
 176 * latency is less than the requested maximum wakeup latency, step
 177 * forwards in the omap_device_pm_latency table to ensure the device's
 178 * maximum wakeup latency is less than or equal to the requested
 179 * maximum wakeup latency.  Returns 0.
 180 */
 181static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
 182{
 183        struct timespec a, b, c;
 184
 185        pr_debug("omap_device: %s: deactivating\n", od->pdev.name);
 186
 187        while (od->pm_lat_level < od->pm_lats_cnt) {
 188                struct omap_device_pm_latency *odpl;
 189                unsigned long long deact_lat = 0;
 190
 191                odpl = od->pm_lats + od->pm_lat_level;
 192
 193                if (!ignore_lat &&
 194                    ((od->dev_wakeup_lat + odpl->activate_lat) >
 195                     od->_dev_wakeup_lat_limit))
 196                        break;
 197
 198                read_persistent_clock(&a);
 199
 200                /* XXX check return code */
 201                odpl->deactivate_func(od);
 202
 203                read_persistent_clock(&b);
 204
 205                c = timespec_sub(b, a);
 206                deact_lat = timespec_to_ns(&c);
 207
 208                pr_debug("omap_device: %s: pm_lat %d: deactivate: elapsed time "
 209                         "%llu nsec\n", od->pdev.name, od->pm_lat_level,
 210                         deact_lat);
 211
 212                if (deact_lat > odpl->deactivate_lat) {
 213                        odpl->deactivate_lat_worst = deact_lat;
 214                        if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
 215                                odpl->deactivate_lat = deact_lat;
 216                                pr_warning("omap_device: %s.%d: new worst case "
 217                                           "deactivate latency %d: %llu\n",
 218                                           od->pdev.name, od->pdev.id,
 219                                           od->pm_lat_level, deact_lat);
 220                        } else
 221                                pr_warning("omap_device: %s.%d: deactivate "
 222                                           "latency %d higher than exptected. "
 223                                           "(%llu > %d)\n",
 224                                           od->pdev.name, od->pdev.id,
 225                                           od->pm_lat_level, deact_lat,
 226                                           odpl->deactivate_lat);
 227                }
 228
 229
 230                od->dev_wakeup_lat += odpl->activate_lat;
 231
 232                od->pm_lat_level++;
 233        }
 234
 235        return 0;
 236}
 237
 238static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
 239{
 240        return container_of(pdev, struct omap_device, pdev);
 241}
 242
 243/**
 244 * _add_optional_clock_clkdev - Add clkdev entry for hwmod optional clocks
 245 * @od: struct omap_device *od
 246 *
 247 * For every optional clock present per hwmod per omap_device, this function
 248 * adds an entry in the clkdev table of the form <dev-id=dev_name, con-id=role>
 249 * if it does not exist already.
 250 *
 251 * The function is called from inside omap_device_build_ss(), after
 252 * omap_device_register.
 253 *
 254 * This allows drivers to get a pointer to its optional clocks based on its role
 255 * by calling clk_get(<dev*>, <role>).
 256 *
 257 * No return value.
 258 */
 259static void _add_optional_clock_clkdev(struct omap_device *od,
 260                                      struct omap_hwmod *oh)
 261{
 262        int i;
 263
 264        for (i = 0; i < oh->opt_clks_cnt; i++) {
 265                struct omap_hwmod_opt_clk *oc;
 266                struct clk *r;
 267                struct clk_lookup *l;
 268
 269                oc = &oh->opt_clks[i];
 270
 271                if (!oc->_clk)
 272                        continue;
 273
 274                r = clk_get_sys(dev_name(&od->pdev.dev), oc->role);
 275                if (!IS_ERR(r))
 276                        continue; /* clkdev entry exists */
 277
 278                r = omap_clk_get_by_name((char *)oc->clk);
 279                if (IS_ERR(r)) {
 280                        pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n",
 281                               dev_name(&od->pdev.dev), oc->clk);
 282                        continue;
 283                }
 284
 285                l = clkdev_alloc(r, oc->role, dev_name(&od->pdev.dev));
 286                if (!l) {
 287                        pr_err("omap_device: %s: clkdev_alloc for %s failed\n",
 288                               dev_name(&od->pdev.dev), oc->role);
 289                        return;
 290                }
 291                clkdev_add(l);
 292        }
 293}
 294
 295
 296/* Public functions for use by core code */
 297
 298/**
 299 * omap_device_get_context_loss_count - get lost context count
 300 * @od: struct omap_device *
 301 *
 302 * Using the primary hwmod, query the context loss count for this
 303 * device.
 304 *
 305 * Callers should consider context for this device lost any time this
 306 * function returns a value different than the value the caller got
 307 * the last time it called this function.
 308 *
 309 * If any hwmods exist for the omap_device assoiated with @pdev,
 310 * return the context loss counter for that hwmod, otherwise return
 311 * zero.
 312 */
 313u32 omap_device_get_context_loss_count(struct platform_device *pdev)
 314{
 315        struct omap_device *od;
 316        u32 ret = 0;
 317
 318        od = _find_by_pdev(pdev);
 319
 320        if (od->hwmods_cnt)
 321                ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
 322
 323        return ret;
 324}
 325
 326/**
 327 * omap_device_count_resources - count number of struct resource entries needed
 328 * @od: struct omap_device *
 329 *
 330 * Count the number of struct resource entries needed for this
 331 * omap_device @od.  Used by omap_device_build_ss() to determine how
 332 * much memory to allocate before calling
 333 * omap_device_fill_resources().  Returns the count.
 334 */
 335int omap_device_count_resources(struct omap_device *od)
 336{
 337        int c = 0;
 338        int i;
 339
 340        for (i = 0; i < od->hwmods_cnt; i++)
 341                c += omap_hwmod_count_resources(od->hwmods[i]);
 342
 343        pr_debug("omap_device: %s: counted %d total resources across %d "
 344                 "hwmods\n", od->pdev.name, c, od->hwmods_cnt);
 345
 346        return c;
 347}
 348
 349/**
 350 * omap_device_fill_resources - fill in array of struct resource
 351 * @od: struct omap_device *
 352 * @res: pointer to an array of struct resource to be filled in
 353 *
 354 * Populate one or more empty struct resource pointed to by @res with
 355 * the resource data for this omap_device @od.  Used by
 356 * omap_device_build_ss() after calling omap_device_count_resources().
 357 * Ideally this function would not be needed at all.  If omap_device
 358 * replaces platform_device, then we can specify our own
 359 * get_resource()/ get_irq()/etc functions that use the underlying
 360 * omap_hwmod information.  Or if platform_device is extended to use
 361 * subarchitecture-specific function pointers, the various
 362 * platform_device functions can simply call omap_device internal
 363 * functions to get device resources.  Hacking around the existing
 364 * platform_device code wastes memory.  Returns 0.
 365 */
 366int omap_device_fill_resources(struct omap_device *od, struct resource *res)
 367{
 368        int c = 0;
 369        int i, r;
 370
 371        for (i = 0; i < od->hwmods_cnt; i++) {
 372                r = omap_hwmod_fill_resources(od->hwmods[i], res);
 373                res += r;
 374                c += r;
 375        }
 376
 377        return 0;
 378}
 379
 380/**
 381 * omap_device_build - build and register an omap_device with one omap_hwmod
 382 * @pdev_name: name of the platform_device driver to use
 383 * @pdev_id: this platform_device's connection ID
 384 * @oh: ptr to the single omap_hwmod that backs this omap_device
 385 * @pdata: platform_data ptr to associate with the platform_device
 386 * @pdata_len: amount of memory pointed to by @pdata
 387 * @pm_lats: pointer to a omap_device_pm_latency array for this device
 388 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
 389 * @is_early_device: should the device be registered as an early device or not
 390 *
 391 * Convenience function for building and registering a single
 392 * omap_device record, which in turn builds and registers a
 393 * platform_device record.  See omap_device_build_ss() for more
 394 * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
 395 * passes along the return value of omap_device_build_ss().
 396 */
 397struct omap_device *omap_device_build(const char *pdev_name, int pdev_id,
 398                                      struct omap_hwmod *oh, void *pdata,
 399                                      int pdata_len,
 400                                      struct omap_device_pm_latency *pm_lats,
 401                                      int pm_lats_cnt, int is_early_device)
 402{
 403        struct omap_hwmod *ohs[] = { oh };
 404
 405        if (!oh)
 406                return ERR_PTR(-EINVAL);
 407
 408        return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
 409                                    pdata_len, pm_lats, pm_lats_cnt,
 410                                    is_early_device);
 411}
 412
 413/**
 414 * omap_device_build_ss - build and register an omap_device with multiple hwmods
 415 * @pdev_name: name of the platform_device driver to use
 416 * @pdev_id: this platform_device's connection ID
 417 * @oh: ptr to the single omap_hwmod that backs this omap_device
 418 * @pdata: platform_data ptr to associate with the platform_device
 419 * @pdata_len: amount of memory pointed to by @pdata
 420 * @pm_lats: pointer to a omap_device_pm_latency array for this device
 421 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
 422 * @is_early_device: should the device be registered as an early device or not
 423 *
 424 * Convenience function for building and registering an omap_device
 425 * subsystem record.  Subsystem records consist of multiple
 426 * omap_hwmods.  This function in turn builds and registers a
 427 * platform_device record.  Returns an ERR_PTR() on error, or passes
 428 * along the return value of omap_device_register().
 429 */
 430struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
 431                                         struct omap_hwmod **ohs, int oh_cnt,
 432                                         void *pdata, int pdata_len,
 433                                         struct omap_device_pm_latency *pm_lats,
 434                                         int pm_lats_cnt, int is_early_device)
 435{
 436        int ret = -ENOMEM;
 437        struct omap_device *od;
 438        char *pdev_name2;
 439        struct resource *res = NULL;
 440        int i, res_count;
 441        struct omap_hwmod **hwmods;
 442
 443        if (!ohs || oh_cnt == 0 || !pdev_name)
 444                return ERR_PTR(-EINVAL);
 445
 446        if (!pdata && pdata_len > 0)
 447                return ERR_PTR(-EINVAL);
 448
 449        pr_debug("omap_device: %s: building with %d hwmods\n", pdev_name,
 450                 oh_cnt);
 451
 452        od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
 453        if (!od)
 454                return ERR_PTR(-ENOMEM);
 455
 456        od->hwmods_cnt = oh_cnt;
 457
 458        hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt,
 459                         GFP_KERNEL);
 460        if (!hwmods)
 461                goto odbs_exit1;
 462
 463        memcpy(hwmods, ohs, sizeof(struct omap_hwmod *) * oh_cnt);
 464        od->hwmods = hwmods;
 465
 466        pdev_name2 = kzalloc(strlen(pdev_name) + 1, GFP_KERNEL);
 467        if (!pdev_name2)
 468                goto odbs_exit2;
 469        strcpy(pdev_name2, pdev_name);
 470
 471        od->pdev.name = pdev_name2;
 472        od->pdev.id = pdev_id;
 473
 474        res_count = omap_device_count_resources(od);
 475        if (res_count > 0) {
 476                res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
 477                if (!res)
 478                        goto odbs_exit3;
 479        }
 480        omap_device_fill_resources(od, res);
 481
 482        od->pdev.num_resources = res_count;
 483        od->pdev.resource = res;
 484
 485        ret = platform_device_add_data(&od->pdev, pdata, pdata_len);
 486        if (ret)
 487                goto odbs_exit4;
 488
 489        od->pm_lats = pm_lats;
 490        od->pm_lats_cnt = pm_lats_cnt;
 491
 492        if (is_early_device)
 493                ret = omap_early_device_register(od);
 494        else
 495                ret = omap_device_register(od);
 496
 497        for (i = 0; i < oh_cnt; i++) {
 498                hwmods[i]->od = od;
 499                _add_optional_clock_clkdev(od, hwmods[i]);
 500        }
 501
 502        if (ret)
 503                goto odbs_exit4;
 504
 505        return od;
 506
 507odbs_exit4:
 508        kfree(res);
 509odbs_exit3:
 510        kfree(pdev_name2);
 511odbs_exit2:
 512        kfree(hwmods);
 513odbs_exit1:
 514        kfree(od);
 515
 516        pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
 517
 518        return ERR_PTR(ret);
 519}
 520
 521/**
 522 * omap_early_device_register - register an omap_device as an early platform
 523 * device.
 524 * @od: struct omap_device * to register
 525 *
 526 * Register the omap_device structure.  This currently just calls
 527 * platform_early_add_device() on the underlying platform_device.
 528 * Returns 0 by default.
 529 */
 530int omap_early_device_register(struct omap_device *od)
 531{
 532        struct platform_device *devices[1];
 533
 534        devices[0] = &(od->pdev);
 535        early_platform_add_devices(devices, 1);
 536        return 0;
 537}
 538
 539/**
 540 * omap_device_register - register an omap_device with one omap_hwmod
 541 * @od: struct omap_device * to register
 542 *
 543 * Register the omap_device structure.  This currently just calls
 544 * platform_device_register() on the underlying platform_device.
 545 * Returns the return value of platform_device_register().
 546 */
 547int omap_device_register(struct omap_device *od)
 548{
 549        pr_debug("omap_device: %s: registering\n", od->pdev.name);
 550
 551        od->pdev.dev.parent = &omap_device_parent;
 552        return platform_device_register(&od->pdev);
 553}
 554
 555
 556/* Public functions for use by device drivers through struct platform_data */
 557
 558/**
 559 * omap_device_enable - fully activate an omap_device
 560 * @od: struct omap_device * to activate
 561 *
 562 * Do whatever is necessary for the hwmods underlying omap_device @od
 563 * to be accessible and ready to operate.  This generally involves
 564 * enabling clocks, setting SYSCONFIG registers; and in the future may
 565 * involve remuxing pins.  Device drivers should call this function
 566 * (through platform_data function pointers) where they would normally
 567 * enable clocks, etc.  Returns -EINVAL if called when the omap_device
 568 * is already enabled, or passes along the return value of
 569 * _omap_device_activate().
 570 */
 571int omap_device_enable(struct platform_device *pdev)
 572{
 573        int ret;
 574        struct omap_device *od;
 575
 576        od = _find_by_pdev(pdev);
 577
 578        if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
 579                WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
 580                     od->pdev.name, od->pdev.id, __func__, od->_state);
 581                return -EINVAL;
 582        }
 583
 584        /* Enable everything if we're enabling this device from scratch */
 585        if (od->_state == OMAP_DEVICE_STATE_UNKNOWN)
 586                od->pm_lat_level = od->pm_lats_cnt;
 587
 588        ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT);
 589
 590        od->dev_wakeup_lat = 0;
 591        od->_dev_wakeup_lat_limit = UINT_MAX;
 592        od->_state = OMAP_DEVICE_STATE_ENABLED;
 593
 594        return ret;
 595}
 596
 597/**
 598 * omap_device_idle - idle an omap_device
 599 * @od: struct omap_device * to idle
 600 *
 601 * Idle omap_device @od by calling as many .deactivate_func() entries
 602 * in the omap_device's pm_lats table as is possible without exceeding
 603 * the device's maximum wakeup latency limit, pm_lat_limit.  Device
 604 * drivers should call this function (through platform_data function
 605 * pointers) where they would normally disable clocks after operations
 606 * complete, etc..  Returns -EINVAL if the omap_device is not
 607 * currently enabled, or passes along the return value of
 608 * _omap_device_deactivate().
 609 */
 610int omap_device_idle(struct platform_device *pdev)
 611{
 612        int ret;
 613        struct omap_device *od;
 614
 615        od = _find_by_pdev(pdev);
 616
 617        if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
 618                WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
 619                     od->pdev.name, od->pdev.id, __func__, od->_state);
 620                return -EINVAL;
 621        }
 622
 623        ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
 624
 625        od->_state = OMAP_DEVICE_STATE_IDLE;
 626
 627        return ret;
 628}
 629
 630/**
 631 * omap_device_shutdown - shut down an omap_device
 632 * @od: struct omap_device * to shut down
 633 *
 634 * Shut down omap_device @od by calling all .deactivate_func() entries
 635 * in the omap_device's pm_lats table and then shutting down all of
 636 * the underlying omap_hwmods.  Used when a device is being "removed"
 637 * or a device driver is being unloaded.  Returns -EINVAL if the
 638 * omap_device is not currently enabled or idle, or passes along the
 639 * return value of _omap_device_deactivate().
 640 */
 641int omap_device_shutdown(struct platform_device *pdev)
 642{
 643        int ret, i;
 644        struct omap_device *od;
 645
 646        od = _find_by_pdev(pdev);
 647
 648        if (od->_state != OMAP_DEVICE_STATE_ENABLED &&
 649            od->_state != OMAP_DEVICE_STATE_IDLE) {
 650                WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
 651                     od->pdev.name, od->pdev.id, __func__, od->_state);
 652                return -EINVAL;
 653        }
 654
 655        ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
 656
 657        for (i = 0; i < od->hwmods_cnt; i++)
 658                omap_hwmod_shutdown(od->hwmods[i]);
 659
 660        od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
 661
 662        return ret;
 663}
 664
 665/**
 666 * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim
 667 * @od: struct omap_device *
 668 *
 669 * When a device's maximum wakeup latency limit changes, call some of
 670 * the .activate_func or .deactivate_func function pointers in the
 671 * omap_device's pm_lats array to ensure that the device's maximum
 672 * wakeup latency is less than or equal to the new latency limit.
 673 * Intended to be called by OMAP PM code whenever a device's maximum
 674 * wakeup latency limit changes (e.g., via
 675 * omap_pm_set_dev_wakeup_lat()).  Returns 0 if nothing needs to be
 676 * done (e.g., if the omap_device is not currently idle, or if the
 677 * wakeup latency is already current with the new limit) or passes
 678 * along the return value of _omap_device_deactivate() or
 679 * _omap_device_activate().
 680 */
 681int omap_device_align_pm_lat(struct platform_device *pdev,
 682                             u32 new_wakeup_lat_limit)
 683{
 684        int ret = -EINVAL;
 685        struct omap_device *od;
 686
 687        od = _find_by_pdev(pdev);
 688
 689        if (new_wakeup_lat_limit == od->dev_wakeup_lat)
 690                return 0;
 691
 692        od->_dev_wakeup_lat_limit = new_wakeup_lat_limit;
 693
 694        if (od->_state != OMAP_DEVICE_STATE_IDLE)
 695                return 0;
 696        else if (new_wakeup_lat_limit > od->dev_wakeup_lat)
 697                ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
 698        else if (new_wakeup_lat_limit < od->dev_wakeup_lat)
 699                ret = _omap_device_activate(od, USE_WAKEUP_LAT);
 700
 701        return ret;
 702}
 703
 704/**
 705 * omap_device_get_pwrdm - return the powerdomain * associated with @od
 706 * @od: struct omap_device *
 707 *
 708 * Return the powerdomain associated with the first underlying
 709 * omap_hwmod for this omap_device.  Intended for use by core OMAP PM
 710 * code.  Returns NULL on error or a struct powerdomain * upon
 711 * success.
 712 */
 713struct powerdomain *omap_device_get_pwrdm(struct omap_device *od)
 714{
 715        /*
 716         * XXX Assumes that all omap_hwmod powerdomains are identical.
 717         * This may not necessarily be true.  There should be a sanity
 718         * check in here to WARN() if any difference appears.
 719         */
 720        if (!od->hwmods_cnt)
 721                return NULL;
 722
 723        return omap_hwmod_get_pwrdm(od->hwmods[0]);
 724}
 725
 726/**
 727 * omap_device_get_mpu_rt_va - return the MPU's virtual addr for the hwmod base
 728 * @od: struct omap_device *
 729 *
 730 * Return the MPU's virtual address for the base of the hwmod, from
 731 * the ioremap() that the hwmod code does.  Only valid if there is one
 732 * hwmod associated with this device.  Returns NULL if there are zero
 733 * or more than one hwmods associated with this omap_device;
 734 * otherwise, passes along the return value from
 735 * omap_hwmod_get_mpu_rt_va().
 736 */
 737void __iomem *omap_device_get_rt_va(struct omap_device *od)
 738{
 739        if (od->hwmods_cnt != 1)
 740                return NULL;
 741
 742        return omap_hwmod_get_mpu_rt_va(od->hwmods[0]);
 743}
 744
 745/*
 746 * Public functions intended for use in omap_device_pm_latency
 747 * .activate_func and .deactivate_func function pointers
 748 */
 749
 750/**
 751 * omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
 752 * @od: struct omap_device *od
 753 *
 754 * Enable all underlying hwmods.  Returns 0.
 755 */
 756int omap_device_enable_hwmods(struct omap_device *od)
 757{
 758        int i;
 759
 760        for (i = 0; i < od->hwmods_cnt; i++)
 761                omap_hwmod_enable(od->hwmods[i]);
 762
 763        /* XXX pass along return value here? */
 764        return 0;
 765}
 766
 767/**
 768 * omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
 769 * @od: struct omap_device *od
 770 *
 771 * Idle all underlying hwmods.  Returns 0.
 772 */
 773int omap_device_idle_hwmods(struct omap_device *od)
 774{
 775        int i;
 776
 777        for (i = 0; i < od->hwmods_cnt; i++)
 778                omap_hwmod_idle(od->hwmods[i]);
 779
 780        /* XXX pass along return value here? */
 781        return 0;
 782}
 783
 784/**
 785 * omap_device_disable_clocks - disable all main and interface clocks
 786 * @od: struct omap_device *od
 787 *
 788 * Disable the main functional clock and interface clock for all of the
 789 * omap_hwmods associated with the omap_device.  Returns 0.
 790 */
 791int omap_device_disable_clocks(struct omap_device *od)
 792{
 793        int i;
 794
 795        for (i = 0; i < od->hwmods_cnt; i++)
 796                omap_hwmod_disable_clocks(od->hwmods[i]);
 797
 798        /* XXX pass along return value here? */
 799        return 0;
 800}
 801
 802/**
 803 * omap_device_enable_clocks - enable all main and interface clocks
 804 * @od: struct omap_device *od
 805 *
 806 * Enable the main functional clock and interface clock for all of the
 807 * omap_hwmods associated with the omap_device.  Returns 0.
 808 */
 809int omap_device_enable_clocks(struct omap_device *od)
 810{
 811        int i;
 812
 813        for (i = 0; i < od->hwmods_cnt; i++)
 814                omap_hwmod_enable_clocks(od->hwmods[i]);
 815
 816        /* XXX pass along return value here? */
 817        return 0;
 818}
 819
 820struct device omap_device_parent = {
 821        .init_name      = "omap",
 822        .parent         = &platform_bus,
 823};
 824
 825static int __init omap_device_init(void)
 826{
 827        return device_register(&omap_device_parent);
 828}
 829core_initcall(omap_device_init);
 830