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