| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * omap_device implementation |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 9 | 10 | * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard |
|---|
| 10 | 11 | * Woodruff |
|---|
| 11 | 12 | * |
|---|
| 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 | 13 | * This code provides a consistent interface for OMAP device drivers |
|---|
| 17 | 14 | * to control power management and interconnect properties of their |
|---|
| 18 | 15 | * devices. |
|---|
| .. | .. |
|---|
| 20 | 17 | * In the medium- to long-term, this code should be implemented as a |
|---|
| 21 | 18 | * proper omap_bus/omap_device in Linux, no more platform_data func |
|---|
| 22 | 19 | * pointers |
|---|
| 23 | | - * |
|---|
| 24 | | - * |
|---|
| 25 | 20 | */ |
|---|
| 26 | 21 | #undef DEBUG |
|---|
| 27 | 22 | |
|---|
| .. | .. |
|---|
| 124 | 119 | |
|---|
| 125 | 120 | /** |
|---|
| 126 | 121 | * omap_device_build_from_dt - build an omap_device with multiple hwmods |
|---|
| 127 | | - * @pdev_name: name of the platform_device driver to use |
|---|
| 128 | | - * @pdev_id: this platform_device's connection ID |
|---|
| 129 | | - * @oh: ptr to the single omap_hwmod that backs this omap_device |
|---|
| 130 | | - * @pdata: platform_data ptr to associate with the platform_device |
|---|
| 131 | | - * @pdata_len: amount of memory pointed to by @pdata |
|---|
| 122 | + * @pdev: The platform device to update. |
|---|
| 132 | 123 | * |
|---|
| 133 | 124 | * Function for building an omap_device already registered from device-tree |
|---|
| 134 | 125 | * |
|---|
| .. | .. |
|---|
| 251 | 242 | if (pdev->dev.of_node) |
|---|
| 252 | 243 | omap_device_build_from_dt(pdev); |
|---|
| 253 | 244 | omap_auxdata_legacy_init(dev); |
|---|
| 254 | | - /* fall through */ |
|---|
| 245 | + fallthrough; |
|---|
| 255 | 246 | default: |
|---|
| 256 | 247 | od = to_omap_device(pdev); |
|---|
| 257 | 248 | if (od) |
|---|
| .. | .. |
|---|
| 299 | 290 | |
|---|
| 300 | 291 | /** |
|---|
| 301 | 292 | * omap_device_get_context_loss_count - get lost context count |
|---|
| 302 | | - * @od: struct omap_device * |
|---|
| 293 | + * @pdev: The platform device to update. |
|---|
| 303 | 294 | * |
|---|
| 304 | 295 | * Using the primary hwmod, query the context loss count for this |
|---|
| 305 | 296 | * device. |
|---|
| .. | .. |
|---|
| 328 | 319 | /** |
|---|
| 329 | 320 | * omap_device_alloc - allocate an omap_device |
|---|
| 330 | 321 | * @pdev: platform_device that will be included in this omap_device |
|---|
| 331 | | - * @oh: ptr to the single omap_hwmod that backs this omap_device |
|---|
| 332 | | - * @pdata: platform_data ptr to associate with the platform_device |
|---|
| 333 | | - * @pdata_len: amount of memory pointed to by @pdata |
|---|
| 322 | + * @ohs: ptr to the omap_hwmod for this omap_device |
|---|
| 323 | + * @oh_cnt: the size of the ohs list |
|---|
| 334 | 324 | * |
|---|
| 335 | 325 | * Convenience function for allocating an omap_device structure and filling |
|---|
| 336 | 326 | * hwmods, and resources. |
|---|
| .. | .. |
|---|
| 383 | 373 | od->pdev->archdata.od = NULL; |
|---|
| 384 | 374 | kfree(od->hwmods); |
|---|
| 385 | 375 | kfree(od); |
|---|
| 386 | | -} |
|---|
| 387 | | - |
|---|
| 388 | | -/** |
|---|
| 389 | | - * omap_device_copy_resources - Add legacy IO and IRQ resources |
|---|
| 390 | | - * @oh: interconnect target module |
|---|
| 391 | | - * @pdev: platform device to copy resources to |
|---|
| 392 | | - * |
|---|
| 393 | | - * We still have legacy DMA and smartreflex needing resources. |
|---|
| 394 | | - * Let's populate what they need until we can eventually just |
|---|
| 395 | | - * remove this function. Note that there should be no need to |
|---|
| 396 | | - * call this from omap_device_build_from_dt(), nor should there |
|---|
| 397 | | - * be any need to call it for other devices. |
|---|
| 398 | | - */ |
|---|
| 399 | | -static int |
|---|
| 400 | | -omap_device_copy_resources(struct omap_hwmod *oh, |
|---|
| 401 | | - struct platform_device *pdev) |
|---|
| 402 | | -{ |
|---|
| 403 | | - struct device_node *np, *child; |
|---|
| 404 | | - struct property *prop; |
|---|
| 405 | | - struct resource *res; |
|---|
| 406 | | - const char *name; |
|---|
| 407 | | - int error, irq = 0; |
|---|
| 408 | | - |
|---|
| 409 | | - if (!oh || !oh->od || !oh->od->pdev) |
|---|
| 410 | | - return -EINVAL; |
|---|
| 411 | | - |
|---|
| 412 | | - np = oh->od->pdev->dev.of_node; |
|---|
| 413 | | - if (!np) { |
|---|
| 414 | | - error = -ENODEV; |
|---|
| 415 | | - goto error; |
|---|
| 416 | | - } |
|---|
| 417 | | - |
|---|
| 418 | | - res = kcalloc(2, sizeof(*res), GFP_KERNEL); |
|---|
| 419 | | - if (!res) |
|---|
| 420 | | - return -ENOMEM; |
|---|
| 421 | | - |
|---|
| 422 | | - /* Do we have a dts range for the interconnect target module? */ |
|---|
| 423 | | - error = omap_hwmod_parse_module_range(oh, np, res); |
|---|
| 424 | | - |
|---|
| 425 | | - /* No ranges, rely on device reg entry */ |
|---|
| 426 | | - if (error) |
|---|
| 427 | | - error = of_address_to_resource(np, 0, res); |
|---|
| 428 | | - if (error) |
|---|
| 429 | | - goto free; |
|---|
| 430 | | - |
|---|
| 431 | | - /* SmartReflex needs first IO resource name to be "mpu" */ |
|---|
| 432 | | - res[0].name = "mpu"; |
|---|
| 433 | | - |
|---|
| 434 | | - /* |
|---|
| 435 | | - * We may have a configured "ti,sysc" interconnect target with a |
|---|
| 436 | | - * dts child with the interrupt. If so use the first child's |
|---|
| 437 | | - * first interrupt for "ti-hwmods" legacy support. |
|---|
| 438 | | - */ |
|---|
| 439 | | - of_property_for_each_string(np, "compatible", prop, name) |
|---|
| 440 | | - if (!strncmp("ti,sysc-", name, 8)) |
|---|
| 441 | | - break; |
|---|
| 442 | | - |
|---|
| 443 | | - child = of_get_next_available_child(np, NULL); |
|---|
| 444 | | - |
|---|
| 445 | | - if (name) |
|---|
| 446 | | - irq = irq_of_parse_and_map(child, 0); |
|---|
| 447 | | - if (!irq) |
|---|
| 448 | | - irq = irq_of_parse_and_map(np, 0); |
|---|
| 449 | | - if (!irq) { |
|---|
| 450 | | - error = -EINVAL; |
|---|
| 451 | | - goto free; |
|---|
| 452 | | - } |
|---|
| 453 | | - |
|---|
| 454 | | - /* Legacy DMA code needs interrupt name to be "0" */ |
|---|
| 455 | | - res[1].start = irq; |
|---|
| 456 | | - res[1].end = irq; |
|---|
| 457 | | - res[1].flags = IORESOURCE_IRQ; |
|---|
| 458 | | - res[1].name = "0"; |
|---|
| 459 | | - |
|---|
| 460 | | - error = platform_device_add_resources(pdev, res, 2); |
|---|
| 461 | | - |
|---|
| 462 | | -free: |
|---|
| 463 | | - kfree(res); |
|---|
| 464 | | - |
|---|
| 465 | | -error: |
|---|
| 466 | | - WARN(error, "%s: %s device %s failed: %i\n", |
|---|
| 467 | | - __func__, oh->name, dev_name(&pdev->dev), |
|---|
| 468 | | - error); |
|---|
| 469 | | - |
|---|
| 470 | | - return error; |
|---|
| 471 | | -} |
|---|
| 472 | | - |
|---|
| 473 | | -/** |
|---|
| 474 | | - * omap_device_build - build and register an omap_device with one omap_hwmod |
|---|
| 475 | | - * @pdev_name: name of the platform_device driver to use |
|---|
| 476 | | - * @pdev_id: this platform_device's connection ID |
|---|
| 477 | | - * @oh: ptr to the single omap_hwmod that backs this omap_device |
|---|
| 478 | | - * @pdata: platform_data ptr to associate with the platform_device |
|---|
| 479 | | - * @pdata_len: amount of memory pointed to by @pdata |
|---|
| 480 | | - * |
|---|
| 481 | | - * Convenience function for building and registering a single |
|---|
| 482 | | - * omap_device record, which in turn builds and registers a |
|---|
| 483 | | - * platform_device record. See omap_device_build_ss() for more |
|---|
| 484 | | - * information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise, |
|---|
| 485 | | - * passes along the return value of omap_device_build_ss(). |
|---|
| 486 | | - */ |
|---|
| 487 | | -struct platform_device __init *omap_device_build(const char *pdev_name, |
|---|
| 488 | | - int pdev_id, |
|---|
| 489 | | - struct omap_hwmod *oh, |
|---|
| 490 | | - void *pdata, int pdata_len) |
|---|
| 491 | | -{ |
|---|
| 492 | | - int ret = -ENOMEM; |
|---|
| 493 | | - struct platform_device *pdev; |
|---|
| 494 | | - struct omap_device *od; |
|---|
| 495 | | - |
|---|
| 496 | | - if (!oh || !pdev_name) |
|---|
| 497 | | - return ERR_PTR(-EINVAL); |
|---|
| 498 | | - |
|---|
| 499 | | - if (!pdata && pdata_len > 0) |
|---|
| 500 | | - return ERR_PTR(-EINVAL); |
|---|
| 501 | | - |
|---|
| 502 | | - if (strncmp(oh->name, "smartreflex", 11) && |
|---|
| 503 | | - strncmp(oh->name, "dma", 3)) { |
|---|
| 504 | | - pr_warn("%s need to update %s to probe with dt\na", |
|---|
| 505 | | - __func__, pdev_name); |
|---|
| 506 | | - ret = -ENODEV; |
|---|
| 507 | | - goto odbs_exit; |
|---|
| 508 | | - } |
|---|
| 509 | | - |
|---|
| 510 | | - pdev = platform_device_alloc(pdev_name, pdev_id); |
|---|
| 511 | | - if (!pdev) { |
|---|
| 512 | | - ret = -ENOMEM; |
|---|
| 513 | | - goto odbs_exit; |
|---|
| 514 | | - } |
|---|
| 515 | | - |
|---|
| 516 | | - /* Set the dev_name early to allow dev_xxx in omap_device_alloc */ |
|---|
| 517 | | - if (pdev->id != -1) |
|---|
| 518 | | - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); |
|---|
| 519 | | - else |
|---|
| 520 | | - dev_set_name(&pdev->dev, "%s", pdev->name); |
|---|
| 521 | | - |
|---|
| 522 | | - /* |
|---|
| 523 | | - * Must be called before omap_device_alloc() as oh->od |
|---|
| 524 | | - * only contains the currently registered omap_device |
|---|
| 525 | | - * and will get overwritten by omap_device_alloc(). |
|---|
| 526 | | - */ |
|---|
| 527 | | - ret = omap_device_copy_resources(oh, pdev); |
|---|
| 528 | | - if (ret) |
|---|
| 529 | | - goto odbs_exit1; |
|---|
| 530 | | - |
|---|
| 531 | | - od = omap_device_alloc(pdev, &oh, 1); |
|---|
| 532 | | - if (IS_ERR(od)) { |
|---|
| 533 | | - ret = PTR_ERR(od); |
|---|
| 534 | | - goto odbs_exit1; |
|---|
| 535 | | - } |
|---|
| 536 | | - |
|---|
| 537 | | - ret = platform_device_add_data(pdev, pdata, pdata_len); |
|---|
| 538 | | - if (ret) |
|---|
| 539 | | - goto odbs_exit2; |
|---|
| 540 | | - |
|---|
| 541 | | - ret = omap_device_register(pdev); |
|---|
| 542 | | - if (ret) |
|---|
| 543 | | - goto odbs_exit2; |
|---|
| 544 | | - |
|---|
| 545 | | - return pdev; |
|---|
| 546 | | - |
|---|
| 547 | | -odbs_exit2: |
|---|
| 548 | | - omap_device_delete(od); |
|---|
| 549 | | -odbs_exit1: |
|---|
| 550 | | - platform_device_put(pdev); |
|---|
| 551 | | -odbs_exit: |
|---|
| 552 | | - |
|---|
| 553 | | - pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret); |
|---|
| 554 | | - |
|---|
| 555 | | - return ERR_PTR(ret); |
|---|
| 556 | 376 | } |
|---|
| 557 | 377 | |
|---|
| 558 | 378 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 656 | 476 | |
|---|
| 657 | 477 | /** |
|---|
| 658 | 478 | * omap_device_register - register an omap_device with one omap_hwmod |
|---|
| 659 | | - * @od: struct omap_device * to register |
|---|
| 479 | + * @pdev: the platform device (omap_device) to register. |
|---|
| 660 | 480 | * |
|---|
| 661 | 481 | * Register the omap_device structure. This currently just calls |
|---|
| 662 | 482 | * platform_device_register() on the underlying platform_device. |
|---|
| .. | .. |
|---|
| 675 | 495 | |
|---|
| 676 | 496 | /** |
|---|
| 677 | 497 | * omap_device_enable - fully activate an omap_device |
|---|
| 678 | | - * @od: struct omap_device * to activate |
|---|
| 498 | + * @pdev: the platform device to activate |
|---|
| 679 | 499 | * |
|---|
| 680 | 500 | * Do whatever is necessary for the hwmods underlying omap_device @od |
|---|
| 681 | 501 | * to be accessible and ready to operate. This generally involves |
|---|
| .. | .. |
|---|
| 709 | 529 | |
|---|
| 710 | 530 | /** |
|---|
| 711 | 531 | * omap_device_idle - idle an omap_device |
|---|
| 712 | | - * @od: struct omap_device * to idle |
|---|
| 532 | + * @pdev: The platform_device (omap_device) to idle |
|---|
| 713 | 533 | * |
|---|
| 714 | 534 | * Idle omap_device @od. Device drivers call this function indirectly |
|---|
| 715 | 535 | * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not |
|---|