root/arch/arm/mach-omap2/omap_device.c

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

DEFINITIONS

This source file includes following definitions.
  1. _add_clkdev
  2. _add_hwmod_clocks_clkdev
  3. omap_device_build_from_dt
  4. _omap_device_notifier_call
  5. _omap_device_enable_hwmods
  6. _omap_device_idle_hwmods
  7. omap_device_get_context_loss_count
  8. omap_device_alloc
  9. omap_device_delete
  10. omap_device_copy_resources
  11. omap_device_build
  12. _od_runtime_suspend
  13. _od_runtime_resume
  14. _od_fail_runtime_suspend
  15. _od_fail_runtime_resume
  16. _od_suspend_noirq
  17. _od_resume_noirq
  18. omap_device_register
  19. omap_device_enable
  20. omap_device_idle
  21. omap_device_assert_hardreset
  22. omap_device_deassert_hardreset
  23. omap_device_get_by_hwmod_name
  24. omap_device_init
  25. omap_device_late_idle
  26. omap_device_late_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * omap_device implementation
   4  *
   5  * Copyright (C) 2009-2010 Nokia Corporation
   6  * Paul Walmsley, Kevin Hilman
   7  *
   8  * Developed in collaboration with (alphabetical order): Benoit
   9  * Cousson, Thara Gopinath, Tony Lindgren, Rajendra Nayak, Vikram
  10  * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
  11  * Woodruff
  12  *
  13  * This code provides a consistent interface for OMAP device drivers
  14  * to control power management and interconnect properties of their
  15  * devices.
  16  *
  17  * In the medium- to long-term, this code should be implemented as a
  18  * proper omap_bus/omap_device in Linux, no more platform_data func
  19  * pointers
  20  */
  21 #undef DEBUG
  22 
  23 #include <linux/kernel.h>
  24 #include <linux/platform_device.h>
  25 #include <linux/slab.h>
  26 #include <linux/err.h>
  27 #include <linux/io.h>
  28 #include <linux/clk.h>
  29 #include <linux/clkdev.h>
  30 #include <linux/pm_domain.h>
  31 #include <linux/pm_runtime.h>
  32 #include <linux/of.h>
  33 #include <linux/of_address.h>
  34 #include <linux/of_irq.h>
  35 #include <linux/notifier.h>
  36 
  37 #include "common.h"
  38 #include "soc.h"
  39 #include "omap_device.h"
  40 #include "omap_hwmod.h"
  41 
  42 /* Private functions */
  43 
  44 static void _add_clkdev(struct omap_device *od, const char *clk_alias,
  45                        const char *clk_name)
  46 {
  47         struct clk *r;
  48         int rc;
  49 
  50         if (!clk_alias || !clk_name)
  51                 return;
  52 
  53         dev_dbg(&od->pdev->dev, "Creating %s -> %s\n", clk_alias, clk_name);
  54 
  55         r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
  56         if (!IS_ERR(r)) {
  57                 dev_dbg(&od->pdev->dev,
  58                          "alias %s already exists\n", clk_alias);
  59                 clk_put(r);
  60                 return;
  61         }
  62 
  63         r = clk_get_sys(NULL, clk_name);
  64 
  65         if (IS_ERR(r)) {
  66                 struct of_phandle_args clkspec;
  67 
  68                 clkspec.np = of_find_node_by_name(NULL, clk_name);
  69 
  70                 r = of_clk_get_from_provider(&clkspec);
  71 
  72                 rc = clk_register_clkdev(r, clk_alias,
  73                                          dev_name(&od->pdev->dev));
  74         } else {
  75                 rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev),
  76                                    clk_name, NULL);
  77         }
  78 
  79         if (rc) {
  80                 if (rc == -ENODEV || rc == -ENOMEM)
  81                         dev_err(&od->pdev->dev,
  82                                 "clkdev_alloc for %s failed\n", clk_alias);
  83                 else
  84                         dev_err(&od->pdev->dev,
  85                                 "clk_get for %s failed\n", clk_name);
  86         }
  87 }
  88 
  89 /**
  90  * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
  91  * and main clock
  92  * @od: struct omap_device *od
  93  * @oh: struct omap_hwmod *oh
  94  *
  95  * For the main clock and every optional clock present per hwmod per
  96  * omap_device, this function adds an entry in the clkdev table of the
  97  * form <dev-id=dev_name, con-id=role> if it does not exist already.
  98  *
  99  * The function is called from inside omap_device_build_ss(), after
 100  * omap_device_register.
 101  *
 102  * This allows drivers to get a pointer to its optional clocks based on its role
 103  * by calling clk_get(<dev*>, <role>).
 104  * In the case of the main clock, a "fck" alias is used.
 105  *
 106  * No return value.
 107  */
 108 static void _add_hwmod_clocks_clkdev(struct omap_device *od,
 109                                      struct omap_hwmod *oh)
 110 {
 111         int i;
 112 
 113         _add_clkdev(od, "fck", oh->main_clk);
 114 
 115         for (i = 0; i < oh->opt_clks_cnt; i++)
 116                 _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
 117 }
 118 
 119 
 120 /**
 121  * omap_device_build_from_dt - build an omap_device with multiple hwmods
 122  * @pdev_name: name of the platform_device driver to use
 123  * @pdev_id: this platform_device's connection ID
 124  * @oh: ptr to the single omap_hwmod that backs this omap_device
 125  * @pdata: platform_data ptr to associate with the platform_device
 126  * @pdata_len: amount of memory pointed to by @pdata
 127  *
 128  * Function for building an omap_device already registered from device-tree
 129  *
 130  * Returns 0 or PTR_ERR() on error.
 131  */
 132 static int omap_device_build_from_dt(struct platform_device *pdev)
 133 {
 134         struct omap_hwmod **hwmods;
 135         struct omap_device *od;
 136         struct omap_hwmod *oh;
 137         struct device_node *node = pdev->dev.of_node;
 138         struct resource res;
 139         const char *oh_name;
 140         int oh_cnt, i, ret = 0;
 141         bool device_active = false, skip_pm_domain = false;
 142 
 143         oh_cnt = of_property_count_strings(node, "ti,hwmods");
 144         if (oh_cnt <= 0) {
 145                 dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
 146                 return -ENODEV;
 147         }
 148 
 149         /* SDMA still needs special handling for omap_device_build() */
 150         ret = of_property_read_string_index(node, "ti,hwmods", 0, &oh_name);
 151         if (!ret && (!strncmp("dma_system", oh_name, 10) ||
 152                      !strncmp("dma", oh_name, 3)))
 153                 skip_pm_domain = true;
 154 
 155         /* Use ti-sysc driver instead of omap_device? */
 156         if (!skip_pm_domain &&
 157             !omap_hwmod_parse_module_range(NULL, node, &res))
 158                 return -ENODEV;
 159 
 160         hwmods = kcalloc(oh_cnt, sizeof(struct omap_hwmod *), GFP_KERNEL);
 161         if (!hwmods) {
 162                 ret = -ENOMEM;
 163                 goto odbfd_exit;
 164         }
 165 
 166         for (i = 0; i < oh_cnt; i++) {
 167                 of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
 168                 oh = omap_hwmod_lookup(oh_name);
 169                 if (!oh) {
 170                         dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
 171                                 oh_name);
 172                         ret = -EINVAL;
 173                         goto odbfd_exit1;
 174                 }
 175                 hwmods[i] = oh;
 176                 if (oh->flags & HWMOD_INIT_NO_IDLE)
 177                         device_active = true;
 178         }
 179 
 180         od = omap_device_alloc(pdev, hwmods, oh_cnt);
 181         if (IS_ERR(od)) {
 182                 dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
 183                         oh_name);
 184                 ret = PTR_ERR(od);
 185                 goto odbfd_exit1;
 186         }
 187 
 188         /* Fix up missing resource names */
 189         for (i = 0; i < pdev->num_resources; i++) {
 190                 struct resource *r = &pdev->resource[i];
 191 
 192                 if (r->name == NULL)
 193                         r->name = dev_name(&pdev->dev);
 194         }
 195 
 196         if (!skip_pm_domain) {
 197                 dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
 198                 if (device_active) {
 199                         omap_device_enable(pdev);
 200                         pm_runtime_set_active(&pdev->dev);
 201                 }
 202         }
 203 
 204 odbfd_exit1:
 205         kfree(hwmods);
 206 odbfd_exit:
 207         /* if data/we are at fault.. load up a fail handler */
 208         if (ret)
 209                 dev_pm_domain_set(&pdev->dev, &omap_device_fail_pm_domain);
 210 
 211         return ret;
 212 }
 213 
 214 static int _omap_device_notifier_call(struct notifier_block *nb,
 215                                       unsigned long event, void *dev)
 216 {
 217         struct platform_device *pdev = to_platform_device(dev);
 218         struct omap_device *od;
 219         int err;
 220 
 221         switch (event) {
 222         case BUS_NOTIFY_REMOVED_DEVICE:
 223                 if (pdev->archdata.od)
 224                         omap_device_delete(pdev->archdata.od);
 225                 break;
 226         case BUS_NOTIFY_UNBOUND_DRIVER:
 227                 od = to_omap_device(pdev);
 228                 if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
 229                         dev_info(dev, "enabled after unload, idling\n");
 230                         err = omap_device_idle(pdev);
 231                         if (err)
 232                                 dev_err(dev, "failed to idle\n");
 233                 }
 234                 break;
 235         case BUS_NOTIFY_BIND_DRIVER:
 236                 od = to_omap_device(pdev);
 237                 if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) &&
 238                     pm_runtime_status_suspended(dev)) {
 239                         od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
 240                         pm_runtime_set_active(dev);
 241                 }
 242                 break;
 243         case BUS_NOTIFY_ADD_DEVICE:
 244                 if (pdev->dev.of_node)
 245                         omap_device_build_from_dt(pdev);
 246                 omap_auxdata_legacy_init(dev);
 247                 /* fall through */
 248         default:
 249                 od = to_omap_device(pdev);
 250                 if (od)
 251                         od->_driver_status = event;
 252         }
 253 
 254         return NOTIFY_DONE;
 255 }
 256 
 257 /**
 258  * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
 259  * @od: struct omap_device *od
 260  *
 261  * Enable all underlying hwmods.  Returns 0.
 262  */
 263 static int _omap_device_enable_hwmods(struct omap_device *od)
 264 {
 265         int ret = 0;
 266         int i;
 267 
 268         for (i = 0; i < od->hwmods_cnt; i++)
 269                 ret |= omap_hwmod_enable(od->hwmods[i]);
 270 
 271         return ret;
 272 }
 273 
 274 /**
 275  * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
 276  * @od: struct omap_device *od
 277  *
 278  * Idle all underlying hwmods.  Returns 0.
 279  */
 280 static int _omap_device_idle_hwmods(struct omap_device *od)
 281 {
 282         int ret = 0;
 283         int i;
 284 
 285         for (i = 0; i < od->hwmods_cnt; i++)
 286                 ret |= omap_hwmod_idle(od->hwmods[i]);
 287 
 288         return ret;
 289 }
 290 
 291 /* Public functions for use by core code */
 292 
 293 /**
 294  * omap_device_get_context_loss_count - get lost context count
 295  * @od: struct omap_device *
 296  *
 297  * Using the primary hwmod, query the context loss count for this
 298  * device.
 299  *
 300  * Callers should consider context for this device lost any time this
 301  * function returns a value different than the value the caller got
 302  * the last time it called this function.
 303  *
 304  * If any hwmods exist for the omap_device associated with @pdev,
 305  * return the context loss counter for that hwmod, otherwise return
 306  * zero.
 307  */
 308 int omap_device_get_context_loss_count(struct platform_device *pdev)
 309 {
 310         struct omap_device *od;
 311         u32 ret = 0;
 312 
 313         od = to_omap_device(pdev);
 314 
 315         if (od->hwmods_cnt)
 316                 ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
 317 
 318         return ret;
 319 }
 320 
 321 /**
 322  * omap_device_alloc - allocate an omap_device
 323  * @pdev: platform_device that will be included in this omap_device
 324  * @oh: ptr to the single omap_hwmod that backs this omap_device
 325  * @pdata: platform_data ptr to associate with the platform_device
 326  * @pdata_len: amount of memory pointed to by @pdata
 327  *
 328  * Convenience function for allocating an omap_device structure and filling
 329  * hwmods, and resources.
 330  *
 331  * Returns an struct omap_device pointer or ERR_PTR() on error;
 332  */
 333 struct omap_device *omap_device_alloc(struct platform_device *pdev,
 334                                         struct omap_hwmod **ohs, int oh_cnt)
 335 {
 336         int ret = -ENOMEM;
 337         struct omap_device *od;
 338         int i;
 339         struct omap_hwmod **hwmods;
 340 
 341         od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
 342         if (!od) {
 343                 ret = -ENOMEM;
 344                 goto oda_exit1;
 345         }
 346         od->hwmods_cnt = oh_cnt;
 347 
 348         hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
 349         if (!hwmods)
 350                 goto oda_exit2;
 351 
 352         od->hwmods = hwmods;
 353         od->pdev = pdev;
 354         pdev->archdata.od = od;
 355 
 356         for (i = 0; i < oh_cnt; i++) {
 357                 hwmods[i]->od = od;
 358                 _add_hwmod_clocks_clkdev(od, hwmods[i]);
 359         }
 360 
 361         return od;
 362 
 363 oda_exit2:
 364         kfree(od);
 365 oda_exit1:
 366         dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret);
 367 
 368         return ERR_PTR(ret);
 369 }
 370 
 371 void omap_device_delete(struct omap_device *od)
 372 {
 373         if (!od)
 374                 return;
 375 
 376         od->pdev->archdata.od = NULL;
 377         kfree(od->hwmods);
 378         kfree(od);
 379 }
 380 
 381 /**
 382  * omap_device_copy_resources - Add legacy IO and IRQ resources
 383  * @oh: interconnect target module
 384  * @pdev: platform device to copy resources to
 385  *
 386  * We still have legacy DMA and smartreflex needing resources.
 387  * Let's populate what they need until we can eventually just
 388  * remove this function. Note that there should be no need to
 389  * call this from omap_device_build_from_dt(), nor should there
 390  * be any need to call it for other devices.
 391  */
 392 static int
 393 omap_device_copy_resources(struct omap_hwmod *oh,
 394                            struct platform_device *pdev)
 395 {
 396         struct device_node *np, *child;
 397         struct property *prop;
 398         struct resource *res;
 399         const char *name;
 400         int error, irq = 0;
 401 
 402         if (!oh || !oh->od || !oh->od->pdev)
 403                 return -EINVAL;
 404 
 405         np = oh->od->pdev->dev.of_node;
 406         if (!np) {
 407                 error = -ENODEV;
 408                 goto error;
 409         }
 410 
 411         res = kcalloc(2, sizeof(*res), GFP_KERNEL);
 412         if (!res)
 413                 return -ENOMEM;
 414 
 415         /* Do we have a dts range for the interconnect target module? */
 416         error = omap_hwmod_parse_module_range(oh, np, res);
 417 
 418         /* No ranges, rely on device reg entry */
 419         if (error)
 420                 error = of_address_to_resource(np, 0, res);
 421         if (error)
 422                 goto free;
 423 
 424         /* SmartReflex needs first IO resource name to be "mpu" */
 425         res[0].name = "mpu";
 426 
 427         /*
 428          * We may have a configured "ti,sysc" interconnect target with a
 429          * dts child with the interrupt. If so use the first child's
 430          * first interrupt for "ti-hwmods" legacy support.
 431          */
 432         of_property_for_each_string(np, "compatible", prop, name)
 433                 if (!strncmp("ti,sysc-", name, 8))
 434                         break;
 435 
 436         child = of_get_next_available_child(np, NULL);
 437 
 438         if (name)
 439                 irq = irq_of_parse_and_map(child, 0);
 440         if (!irq)
 441                 irq = irq_of_parse_and_map(np, 0);
 442         if (!irq) {
 443                 error = -EINVAL;
 444                 goto free;
 445         }
 446 
 447         /* Legacy DMA code needs interrupt name to be "0" */
 448         res[1].start = irq;
 449         res[1].end = irq;
 450         res[1].flags = IORESOURCE_IRQ;
 451         res[1].name = "0";
 452 
 453         error = platform_device_add_resources(pdev, res, 2);
 454 
 455 free:
 456         kfree(res);
 457 
 458 error:
 459         WARN(error, "%s: %s device %s failed: %i\n",
 460              __func__, oh->name, dev_name(&pdev->dev),
 461              error);
 462 
 463         return error;
 464 }
 465 
 466 /**
 467  * omap_device_build - build and register an omap_device with one omap_hwmod
 468  * @pdev_name: name of the platform_device driver to use
 469  * @pdev_id: this platform_device's connection ID
 470  * @oh: ptr to the single omap_hwmod that backs this omap_device
 471  * @pdata: platform_data ptr to associate with the platform_device
 472  * @pdata_len: amount of memory pointed to by @pdata
 473  *
 474  * Convenience function for building and registering a single
 475  * omap_device record, which in turn builds and registers a
 476  * platform_device record.  See omap_device_build_ss() for more
 477  * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
 478  * passes along the return value of omap_device_build_ss().
 479  */
 480 struct platform_device __init *omap_device_build(const char *pdev_name,
 481                                                  int pdev_id,
 482                                                  struct omap_hwmod *oh,
 483                                                  void *pdata, int pdata_len)
 484 {
 485         int ret = -ENOMEM;
 486         struct platform_device *pdev;
 487         struct omap_device *od;
 488 
 489         if (!oh || !pdev_name)
 490                 return ERR_PTR(-EINVAL);
 491 
 492         if (!pdata && pdata_len > 0)
 493                 return ERR_PTR(-EINVAL);
 494 
 495         if (strncmp(oh->name, "smartreflex", 11) &&
 496             strncmp(oh->name, "dma", 3)) {
 497                 pr_warn("%s need to update %s to probe with dt\na",
 498                         __func__, pdev_name);
 499                 ret = -ENODEV;
 500                 goto odbs_exit;
 501         }
 502 
 503         pdev = platform_device_alloc(pdev_name, pdev_id);
 504         if (!pdev) {
 505                 ret = -ENOMEM;
 506                 goto odbs_exit;
 507         }
 508 
 509         /* Set the dev_name early to allow dev_xxx in omap_device_alloc */
 510         if (pdev->id != -1)
 511                 dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
 512         else
 513                 dev_set_name(&pdev->dev, "%s", pdev->name);
 514 
 515         /*
 516          * Must be called before omap_device_alloc() as oh->od
 517          * only contains the currently registered omap_device
 518          * and will get overwritten by omap_device_alloc().
 519          */
 520         ret = omap_device_copy_resources(oh, pdev);
 521         if (ret)
 522                 goto odbs_exit1;
 523 
 524         od = omap_device_alloc(pdev, &oh, 1);
 525         if (IS_ERR(od)) {
 526                 ret = PTR_ERR(od);
 527                 goto odbs_exit1;
 528         }
 529 
 530         ret = platform_device_add_data(pdev, pdata, pdata_len);
 531         if (ret)
 532                 goto odbs_exit2;
 533 
 534         ret = omap_device_register(pdev);
 535         if (ret)
 536                 goto odbs_exit2;
 537 
 538         return pdev;
 539 
 540 odbs_exit2:
 541         omap_device_delete(od);
 542 odbs_exit1:
 543         platform_device_put(pdev);
 544 odbs_exit:
 545 
 546         pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
 547 
 548         return ERR_PTR(ret);
 549 }
 550 
 551 #ifdef CONFIG_PM
 552 static int _od_runtime_suspend(struct device *dev)
 553 {
 554         struct platform_device *pdev = to_platform_device(dev);
 555         int ret;
 556 
 557         ret = pm_generic_runtime_suspend(dev);
 558         if (ret)
 559                 return ret;
 560 
 561         return omap_device_idle(pdev);
 562 }
 563 
 564 static int _od_runtime_resume(struct device *dev)
 565 {
 566         struct platform_device *pdev = to_platform_device(dev);
 567         int ret;
 568 
 569         ret = omap_device_enable(pdev);
 570         if (ret) {
 571                 dev_err(dev, "use pm_runtime_put_sync_suspend() in driver?\n");
 572                 return ret;
 573         }
 574 
 575         return pm_generic_runtime_resume(dev);
 576 }
 577 
 578 static int _od_fail_runtime_suspend(struct device *dev)
 579 {
 580         dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
 581         return -ENODEV;
 582 }
 583 
 584 static int _od_fail_runtime_resume(struct device *dev)
 585 {
 586         dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
 587         return -ENODEV;
 588 }
 589 
 590 #endif
 591 
 592 #ifdef CONFIG_SUSPEND
 593 static int _od_suspend_noirq(struct device *dev)
 594 {
 595         struct platform_device *pdev = to_platform_device(dev);
 596         struct omap_device *od = to_omap_device(pdev);
 597         int ret;
 598 
 599         /* Don't attempt late suspend on a driver that is not bound */
 600         if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
 601                 return 0;
 602 
 603         ret = pm_generic_suspend_noirq(dev);
 604 
 605         if (!ret && !pm_runtime_status_suspended(dev)) {
 606                 if (pm_generic_runtime_suspend(dev) == 0) {
 607                         omap_device_idle(pdev);
 608                         od->flags |= OMAP_DEVICE_SUSPENDED;
 609                 }
 610         }
 611 
 612         return ret;
 613 }
 614 
 615 static int _od_resume_noirq(struct device *dev)
 616 {
 617         struct platform_device *pdev = to_platform_device(dev);
 618         struct omap_device *od = to_omap_device(pdev);
 619 
 620         if (od->flags & OMAP_DEVICE_SUSPENDED) {
 621                 od->flags &= ~OMAP_DEVICE_SUSPENDED;
 622                 omap_device_enable(pdev);
 623                 pm_generic_runtime_resume(dev);
 624         }
 625 
 626         return pm_generic_resume_noirq(dev);
 627 }
 628 #else
 629 #define _od_suspend_noirq NULL
 630 #define _od_resume_noirq NULL
 631 #endif
 632 
 633 struct dev_pm_domain omap_device_fail_pm_domain = {
 634         .ops = {
 635                 SET_RUNTIME_PM_OPS(_od_fail_runtime_suspend,
 636                                    _od_fail_runtime_resume, NULL)
 637         }
 638 };
 639 
 640 struct dev_pm_domain omap_device_pm_domain = {
 641         .ops = {
 642                 SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
 643                                    NULL)
 644                 USE_PLATFORM_PM_SLEEP_OPS
 645                 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
 646                                               _od_resume_noirq)
 647         }
 648 };
 649 
 650 /**
 651  * omap_device_register - register an omap_device with one omap_hwmod
 652  * @od: struct omap_device * to register
 653  *
 654  * Register the omap_device structure.  This currently just calls
 655  * platform_device_register() on the underlying platform_device.
 656  * Returns the return value of platform_device_register().
 657  */
 658 int omap_device_register(struct platform_device *pdev)
 659 {
 660         pr_debug("omap_device: %s: registering\n", pdev->name);
 661 
 662         dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
 663         return platform_device_add(pdev);
 664 }
 665 
 666 
 667 /* Public functions for use by device drivers through struct platform_data */
 668 
 669 /**
 670  * omap_device_enable - fully activate an omap_device
 671  * @od: struct omap_device * to activate
 672  *
 673  * Do whatever is necessary for the hwmods underlying omap_device @od
 674  * to be accessible and ready to operate.  This generally involves
 675  * enabling clocks, setting SYSCONFIG registers; and in the future may
 676  * involve remuxing pins.  Device drivers should call this function
 677  * indirectly via pm_runtime_get*().  Returns -EINVAL if called when
 678  * the omap_device is already enabled, or passes along the return
 679  * value of _omap_device_enable_hwmods().
 680  */
 681 int omap_device_enable(struct platform_device *pdev)
 682 {
 683         int ret;
 684         struct omap_device *od;
 685 
 686         od = to_omap_device(pdev);
 687 
 688         if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
 689                 dev_warn(&pdev->dev,
 690                          "omap_device: %s() called from invalid state %d\n",
 691                          __func__, od->_state);
 692                 return -EINVAL;
 693         }
 694 
 695         ret = _omap_device_enable_hwmods(od);
 696 
 697         if (ret == 0)
 698                 od->_state = OMAP_DEVICE_STATE_ENABLED;
 699 
 700         return ret;
 701 }
 702 
 703 /**
 704  * omap_device_idle - idle an omap_device
 705  * @od: struct omap_device * to idle
 706  *
 707  * Idle omap_device @od.  Device drivers call this function indirectly
 708  * via pm_runtime_put*().  Returns -EINVAL if the omap_device is not
 709  * currently enabled, or passes along the return value of
 710  * _omap_device_idle_hwmods().
 711  */
 712 int omap_device_idle(struct platform_device *pdev)
 713 {
 714         int ret;
 715         struct omap_device *od;
 716 
 717         od = to_omap_device(pdev);
 718 
 719         if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
 720                 dev_warn(&pdev->dev,
 721                          "omap_device: %s() called from invalid state %d\n",
 722                          __func__, od->_state);
 723                 return -EINVAL;
 724         }
 725 
 726         ret = _omap_device_idle_hwmods(od);
 727 
 728         if (ret == 0)
 729                 od->_state = OMAP_DEVICE_STATE_IDLE;
 730 
 731         return ret;
 732 }
 733 
 734 /**
 735  * omap_device_assert_hardreset - set a device's hardreset line
 736  * @pdev: struct platform_device * to reset
 737  * @name: const char * name of the reset line
 738  *
 739  * Set the hardreset line identified by @name on the IP blocks
 740  * associated with the hwmods backing the platform_device @pdev.  All
 741  * of the hwmods associated with @pdev must have the same hardreset
 742  * line linked to them for this to work.  Passes along the return value
 743  * of omap_hwmod_assert_hardreset() in the event of any failure, or
 744  * returns 0 upon success.
 745  */
 746 int omap_device_assert_hardreset(struct platform_device *pdev, const char *name)
 747 {
 748         struct omap_device *od = to_omap_device(pdev);
 749         int ret = 0;
 750         int i;
 751 
 752         for (i = 0; i < od->hwmods_cnt; i++) {
 753                 ret = omap_hwmod_assert_hardreset(od->hwmods[i], name);
 754                 if (ret)
 755                         break;
 756         }
 757 
 758         return ret;
 759 }
 760 
 761 /**
 762  * omap_device_deassert_hardreset - release a device's hardreset line
 763  * @pdev: struct platform_device * to reset
 764  * @name: const char * name of the reset line
 765  *
 766  * Release the hardreset line identified by @name on the IP blocks
 767  * associated with the hwmods backing the platform_device @pdev.  All
 768  * of the hwmods associated with @pdev must have the same hardreset
 769  * line linked to them for this to work.  Passes along the return
 770  * value of omap_hwmod_deassert_hardreset() in the event of any
 771  * failure, or returns 0 upon success.
 772  */
 773 int omap_device_deassert_hardreset(struct platform_device *pdev,
 774                                    const char *name)
 775 {
 776         struct omap_device *od = to_omap_device(pdev);
 777         int ret = 0;
 778         int i;
 779 
 780         for (i = 0; i < od->hwmods_cnt; i++) {
 781                 ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
 782                 if (ret)
 783                         break;
 784         }
 785 
 786         return ret;
 787 }
 788 
 789 /**
 790  * omap_device_get_by_hwmod_name() - convert a hwmod name to
 791  * device pointer.
 792  * @oh_name: name of the hwmod device
 793  *
 794  * Returns back a struct device * pointer associated with a hwmod
 795  * device represented by a hwmod_name
 796  */
 797 struct device *omap_device_get_by_hwmod_name(const char *oh_name)
 798 {
 799         struct omap_hwmod *oh;
 800 
 801         if (!oh_name) {
 802                 WARN(1, "%s: no hwmod name!\n", __func__);
 803                 return ERR_PTR(-EINVAL);
 804         }
 805 
 806         oh = omap_hwmod_lookup(oh_name);
 807         if (!oh) {
 808                 WARN(1, "%s: no hwmod for %s\n", __func__,
 809                         oh_name);
 810                 return ERR_PTR(-ENODEV);
 811         }
 812         if (!oh->od) {
 813                 WARN(1, "%s: no omap_device for %s\n", __func__,
 814                         oh_name);
 815                 return ERR_PTR(-ENODEV);
 816         }
 817 
 818         return &oh->od->pdev->dev;
 819 }
 820 
 821 static struct notifier_block platform_nb = {
 822         .notifier_call = _omap_device_notifier_call,
 823 };
 824 
 825 static int __init omap_device_init(void)
 826 {
 827         bus_register_notifier(&platform_bus_type, &platform_nb);
 828         return 0;
 829 }
 830 omap_postcore_initcall(omap_device_init);
 831 
 832 /**
 833  * omap_device_late_idle - idle devices without drivers
 834  * @dev: struct device * associated with omap_device
 835  * @data: unused
 836  *
 837  * Check the driver bound status of this device, and idle it
 838  * if there is no driver attached.
 839  */
 840 static int __init omap_device_late_idle(struct device *dev, void *data)
 841 {
 842         struct platform_device *pdev = to_platform_device(dev);
 843         struct omap_device *od = to_omap_device(pdev);
 844         int i;
 845 
 846         if (!od)
 847                 return 0;
 848 
 849         /*
 850          * If omap_device state is enabled, but has no driver bound,
 851          * idle it.
 852          */
 853 
 854         /*
 855          * Some devices (like memory controllers) are always kept
 856          * enabled, and should not be idled even with no drivers.
 857          */
 858         for (i = 0; i < od->hwmods_cnt; i++)
 859                 if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
 860                         return 0;
 861 
 862         if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER &&
 863             od->_driver_status != BUS_NOTIFY_BIND_DRIVER) {
 864                 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
 865                         dev_warn(dev, "%s: enabled but no driver.  Idling\n",
 866                                  __func__);
 867                         omap_device_idle(pdev);
 868                 }
 869         }
 870 
 871         return 0;
 872 }
 873 
 874 static int __init omap_device_late_init(void)
 875 {
 876         bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
 877 
 878         return 0;
 879 }
 880 omap_late_initcall_sync(omap_device_late_init);

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