linux/drivers/ata/libahci_platform.c
<<
>>
Prefs
   1/*
   2 * AHCI SATA platform library
   3 *
   4 * Copyright 2004-2005  Red Hat, Inc.
   5 *   Jeff Garzik <jgarzik@pobox.com>
   6 * Copyright 2010  MontaVista Software, LLC.
   7 *   Anton Vorontsov <avorontsov@ru.mvista.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2, or (at your option)
  12 * any later version.
  13 */
  14
  15#include <linux/clk.h>
  16#include <linux/kernel.h>
  17#include <linux/gfp.h>
  18#include <linux/module.h>
  19#include <linux/pm.h>
  20#include <linux/interrupt.h>
  21#include <linux/device.h>
  22#include <linux/platform_device.h>
  23#include <linux/libata.h>
  24#include <linux/ahci_platform.h>
  25#include <linux/phy/phy.h>
  26#include <linux/pm_runtime.h>
  27#include <linux/of_platform.h>
  28#include "ahci.h"
  29
  30static void ahci_host_stop(struct ata_host *host);
  31
  32struct ata_port_operations ahci_platform_ops = {
  33        .inherits       = &ahci_ops,
  34        .host_stop      = ahci_host_stop,
  35};
  36EXPORT_SYMBOL_GPL(ahci_platform_ops);
  37
  38/**
  39 * ahci_platform_enable_phys - Enable PHYs
  40 * @hpriv: host private area to store config values
  41 *
  42 * This function enables all the PHYs found in hpriv->phys, if any.
  43 * If a PHY fails to be enabled, it disables all the PHYs already
  44 * enabled in reverse order and returns an error.
  45 *
  46 * RETURNS:
  47 * 0 on success otherwise a negative error code
  48 */
  49static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
  50{
  51        int rc, i;
  52
  53        for (i = 0; i < hpriv->nports; i++) {
  54                rc = phy_init(hpriv->phys[i]);
  55                if (rc)
  56                        goto disable_phys;
  57
  58                rc = phy_power_on(hpriv->phys[i]);
  59                if (rc) {
  60                        phy_exit(hpriv->phys[i]);
  61                        goto disable_phys;
  62                }
  63        }
  64
  65        return 0;
  66
  67disable_phys:
  68        while (--i >= 0) {
  69                phy_power_off(hpriv->phys[i]);
  70                phy_exit(hpriv->phys[i]);
  71        }
  72        return rc;
  73}
  74
  75/**
  76 * ahci_platform_disable_phys - Disable PHYs
  77 * @hpriv: host private area to store config values
  78 *
  79 * This function disables all PHYs found in hpriv->phys.
  80 */
  81static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
  82{
  83        int i;
  84
  85        for (i = 0; i < hpriv->nports; i++) {
  86                phy_power_off(hpriv->phys[i]);
  87                phy_exit(hpriv->phys[i]);
  88        }
  89}
  90
  91/**
  92 * ahci_platform_enable_clks - Enable platform clocks
  93 * @hpriv: host private area to store config values
  94 *
  95 * This function enables all the clks found in hpriv->clks, starting at
  96 * index 0. If any clk fails to enable it disables all the clks already
  97 * enabled in reverse order, and then returns an error.
  98 *
  99 * RETURNS:
 100 * 0 on success otherwise a negative error code
 101 */
 102int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
 103{
 104        int c, rc;
 105
 106        for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
 107                rc = clk_prepare_enable(hpriv->clks[c]);
 108                if (rc)
 109                        goto disable_unprepare_clk;
 110        }
 111        return 0;
 112
 113disable_unprepare_clk:
 114        while (--c >= 0)
 115                clk_disable_unprepare(hpriv->clks[c]);
 116        return rc;
 117}
 118EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
 119
 120/**
 121 * ahci_platform_disable_clks - Disable platform clocks
 122 * @hpriv: host private area to store config values
 123 *
 124 * This function disables all the clks found in hpriv->clks, in reverse
 125 * order of ahci_platform_enable_clks (starting at the end of the array).
 126 */
 127void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
 128{
 129        int c;
 130
 131        for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
 132                if (hpriv->clks[c])
 133                        clk_disable_unprepare(hpriv->clks[c]);
 134}
 135EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
 136
 137/**
 138 * ahci_platform_enable_regulators - Enable regulators
 139 * @hpriv: host private area to store config values
 140 *
 141 * This function enables all the regulators found in
 142 * hpriv->target_pwrs, if any.  If a regulator fails to be enabled, it
 143 * disables all the regulators already enabled in reverse order and
 144 * returns an error.
 145 *
 146 * RETURNS:
 147 * 0 on success otherwise a negative error code
 148 */
 149int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
 150{
 151        int rc, i;
 152
 153        for (i = 0; i < hpriv->nports; i++) {
 154                if (!hpriv->target_pwrs[i])
 155                        continue;
 156
 157                rc = regulator_enable(hpriv->target_pwrs[i]);
 158                if (rc)
 159                        goto disable_target_pwrs;
 160        }
 161
 162        return 0;
 163
 164disable_target_pwrs:
 165        while (--i >= 0)
 166                if (hpriv->target_pwrs[i])
 167                        regulator_disable(hpriv->target_pwrs[i]);
 168
 169        return rc;
 170}
 171EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
 172
 173/**
 174 * ahci_platform_disable_regulators - Disable regulators
 175 * @hpriv: host private area to store config values
 176 *
 177 * This function disables all regulators found in hpriv->target_pwrs.
 178 */
 179void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
 180{
 181        int i;
 182
 183        for (i = 0; i < hpriv->nports; i++) {
 184                if (!hpriv->target_pwrs[i])
 185                        continue;
 186                regulator_disable(hpriv->target_pwrs[i]);
 187        }
 188}
 189EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
 190/**
 191 * ahci_platform_enable_resources - Enable platform resources
 192 * @hpriv: host private area to store config values
 193 *
 194 * This function enables all ahci_platform managed resources in the
 195 * following order:
 196 * 1) Regulator
 197 * 2) Clocks (through ahci_platform_enable_clks)
 198 * 3) Phys
 199 *
 200 * If resource enabling fails at any point the previous enabled resources
 201 * are disabled in reverse order.
 202 *
 203 * RETURNS:
 204 * 0 on success otherwise a negative error code
 205 */
 206int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
 207{
 208        int rc;
 209
 210        rc = ahci_platform_enable_regulators(hpriv);
 211        if (rc)
 212                return rc;
 213
 214        rc = ahci_platform_enable_clks(hpriv);
 215        if (rc)
 216                goto disable_regulator;
 217
 218        rc = ahci_platform_enable_phys(hpriv);
 219        if (rc)
 220                goto disable_clks;
 221
 222        return 0;
 223
 224disable_clks:
 225        ahci_platform_disable_clks(hpriv);
 226
 227disable_regulator:
 228        ahci_platform_disable_regulators(hpriv);
 229
 230        return rc;
 231}
 232EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
 233
 234/**
 235 * ahci_platform_disable_resources - Disable platform resources
 236 * @hpriv: host private area to store config values
 237 *
 238 * This function disables all ahci_platform managed resources in the
 239 * following order:
 240 * 1) Phys
 241 * 2) Clocks (through ahci_platform_disable_clks)
 242 * 3) Regulator
 243 */
 244void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
 245{
 246        ahci_platform_disable_phys(hpriv);
 247
 248        ahci_platform_disable_clks(hpriv);
 249
 250        ahci_platform_disable_regulators(hpriv);
 251}
 252EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
 253
 254static void ahci_platform_put_resources(struct device *dev, void *res)
 255{
 256        struct ahci_host_priv *hpriv = res;
 257        int c;
 258
 259        if (hpriv->got_runtime_pm) {
 260                pm_runtime_put_sync(dev);
 261                pm_runtime_disable(dev);
 262        }
 263
 264        for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
 265                clk_put(hpriv->clks[c]);
 266        /*
 267         * The regulators are tied to child node device and not to the
 268         * SATA device itself. So we can't use devm for automatically
 269         * releasing them. We have to do it manually here.
 270         */
 271        for (c = 0; c < hpriv->nports; c++)
 272                if (hpriv->target_pwrs && hpriv->target_pwrs[c])
 273                        regulator_put(hpriv->target_pwrs[c]);
 274
 275        kfree(hpriv->target_pwrs);
 276}
 277
 278static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
 279                                struct device *dev, struct device_node *node)
 280{
 281        int rc;
 282
 283        hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
 284
 285        if (!IS_ERR(hpriv->phys[port]))
 286                return 0;
 287
 288        rc = PTR_ERR(hpriv->phys[port]);
 289        switch (rc) {
 290        case -ENOSYS:
 291                /* No PHY support. Check if PHY is required. */
 292                if (of_find_property(node, "phys", NULL)) {
 293                        dev_err(dev,
 294                                "couldn't get PHY in node %s: ENOSYS\n",
 295                                node->name);
 296                        break;
 297                }
 298        case -ENODEV:
 299                /* continue normally */
 300                hpriv->phys[port] = NULL;
 301                rc = 0;
 302                break;
 303
 304        default:
 305                dev_err(dev,
 306                        "couldn't get PHY in node %s: %d\n",
 307                        node->name, rc);
 308
 309                break;
 310        }
 311
 312        return rc;
 313}
 314
 315static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
 316                                struct device *dev)
 317{
 318        struct regulator *target_pwr;
 319        int rc = 0;
 320
 321        target_pwr = regulator_get_optional(dev, "target");
 322
 323        if (!IS_ERR(target_pwr))
 324                hpriv->target_pwrs[port] = target_pwr;
 325        else
 326                rc = PTR_ERR(target_pwr);
 327
 328        return rc;
 329}
 330
 331/**
 332 * ahci_platform_get_resources - Get platform resources
 333 * @pdev: platform device to get resources for
 334 *
 335 * This function allocates an ahci_host_priv struct, and gets the following
 336 * resources, storing a reference to them inside the returned struct:
 337 *
 338 * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
 339 * 2) regulator for controlling the targets power (optional)
 340 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
 341 *    or for non devicetree enabled platforms a single clock
 342 *      4) phys (optional)
 343 *
 344 * RETURNS:
 345 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
 346 */
 347struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
 348{
 349        struct device *dev = &pdev->dev;
 350        struct ahci_host_priv *hpriv;
 351        struct clk *clk;
 352        struct device_node *child;
 353        int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes;
 354        u32 mask_port_map = 0;
 355
 356        if (!devres_open_group(dev, NULL, GFP_KERNEL))
 357                return ERR_PTR(-ENOMEM);
 358
 359        hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
 360                             GFP_KERNEL);
 361        if (!hpriv)
 362                goto err_out;
 363
 364        devres_add(dev, hpriv);
 365
 366        hpriv->mmio = devm_ioremap_resource(dev,
 367                              platform_get_resource(pdev, IORESOURCE_MEM, 0));
 368        if (IS_ERR(hpriv->mmio)) {
 369                dev_err(dev, "no mmio space\n");
 370                rc = PTR_ERR(hpriv->mmio);
 371                goto err_out;
 372        }
 373
 374        for (i = 0; i < AHCI_MAX_CLKS; i++) {
 375                /*
 376                 * For now we must use clk_get(dev, NULL) for the first clock,
 377                 * because some platforms (da850, spear13xx) are not yet
 378                 * converted to use devicetree for clocks.  For new platforms
 379                 * this is equivalent to of_clk_get(dev->of_node, 0).
 380                 */
 381                if (i == 0)
 382                        clk = clk_get(dev, NULL);
 383                else
 384                        clk = of_clk_get(dev->of_node, i);
 385
 386                if (IS_ERR(clk)) {
 387                        rc = PTR_ERR(clk);
 388                        if (rc == -EPROBE_DEFER)
 389                                goto err_out;
 390                        break;
 391                }
 392                hpriv->clks[i] = clk;
 393        }
 394
 395        hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
 396
 397        /*
 398         * If no sub-node was found, we still need to set nports to
 399         * one in order to be able to use the
 400         * ahci_platform_[en|dis]able_[phys|regulators] functions.
 401         */
 402        if (!child_nodes)
 403                hpriv->nports = 1;
 404
 405        sz = hpriv->nports * sizeof(*hpriv->phys);
 406        hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL);
 407        if (!hpriv->phys) {
 408                rc = -ENOMEM;
 409                goto err_out;
 410        }
 411        sz = hpriv->nports * sizeof(*hpriv->target_pwrs);
 412        hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL);
 413        if (!hpriv->target_pwrs) {
 414                rc = -ENOMEM;
 415                goto err_out;
 416        }
 417
 418        if (child_nodes) {
 419                for_each_child_of_node(dev->of_node, child) {
 420                        u32 port;
 421                        struct platform_device *port_dev __maybe_unused;
 422
 423                        if (!of_device_is_available(child))
 424                                continue;
 425
 426                        if (of_property_read_u32(child, "reg", &port)) {
 427                                rc = -EINVAL;
 428                                goto err_out;
 429                        }
 430
 431                        if (port >= hpriv->nports) {
 432                                dev_warn(dev, "invalid port number %d\n", port);
 433                                continue;
 434                        }
 435                        mask_port_map |= BIT(port);
 436
 437#ifdef CONFIG_OF_ADDRESS
 438                        of_platform_device_create(child, NULL, NULL);
 439
 440                        port_dev = of_find_device_by_node(child);
 441
 442                        if (port_dev) {
 443                                rc = ahci_platform_get_regulator(hpriv, port,
 444                                                                &port_dev->dev);
 445                                if (rc == -EPROBE_DEFER)
 446                                        goto err_out;
 447                        }
 448#endif
 449
 450                        rc = ahci_platform_get_phy(hpriv, port, dev, child);
 451                        if (rc)
 452                                goto err_out;
 453
 454                        enabled_ports++;
 455                }
 456                if (!enabled_ports) {
 457                        dev_warn(dev, "No port enabled\n");
 458                        rc = -ENODEV;
 459                        goto err_out;
 460                }
 461
 462                if (!hpriv->mask_port_map)
 463                        hpriv->mask_port_map = mask_port_map;
 464        } else {
 465                /*
 466                 * If no sub-node was found, keep this for device tree
 467                 * compatibility
 468                 */
 469                rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
 470                if (rc)
 471                        goto err_out;
 472
 473                rc = ahci_platform_get_regulator(hpriv, 0, dev);
 474                if (rc == -EPROBE_DEFER)
 475                        goto err_out;
 476        }
 477        pm_runtime_enable(dev);
 478        pm_runtime_get_sync(dev);
 479        hpriv->got_runtime_pm = true;
 480
 481        devres_remove_group(dev, NULL);
 482        return hpriv;
 483
 484err_out:
 485        devres_release_group(dev, NULL);
 486        return ERR_PTR(rc);
 487}
 488EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
 489
 490/**
 491 * ahci_platform_init_host - Bring up an ahci-platform host
 492 * @pdev: platform device pointer for the host
 493 * @hpriv: ahci-host private data for the host
 494 * @pi_template: template for the ata_port_info to use
 495 * @sht: scsi_host_template to use when registering
 496 *
 497 * This function does all the usual steps needed to bring up an
 498 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
 499 * must be initialized / enabled before calling this.
 500 *
 501 * RETURNS:
 502 * 0 on success otherwise a negative error code
 503 */
 504int ahci_platform_init_host(struct platform_device *pdev,
 505                            struct ahci_host_priv *hpriv,
 506                            const struct ata_port_info *pi_template,
 507                            struct scsi_host_template *sht)
 508{
 509        struct device *dev = &pdev->dev;
 510        struct ata_port_info pi = *pi_template;
 511        const struct ata_port_info *ppi[] = { &pi, NULL };
 512        struct ata_host *host;
 513        int i, irq, n_ports, rc;
 514
 515        irq = platform_get_irq(pdev, 0);
 516        if (irq <= 0) {
 517                dev_err(dev, "no irq\n");
 518                return -EINVAL;
 519        }
 520
 521        hpriv->irq = irq;
 522
 523        /* prepare host */
 524        pi.private_data = (void *)(unsigned long)hpriv->flags;
 525
 526        ahci_save_initial_config(dev, hpriv);
 527
 528        if (hpriv->cap & HOST_CAP_NCQ)
 529                pi.flags |= ATA_FLAG_NCQ;
 530
 531        if (hpriv->cap & HOST_CAP_PMP)
 532                pi.flags |= ATA_FLAG_PMP;
 533
 534        ahci_set_em_messages(hpriv, &pi);
 535
 536        /* CAP.NP sometimes indicate the index of the last enabled
 537         * port, at other times, that of the last possible port, so
 538         * determining the maximum port number requires looking at
 539         * both CAP.NP and port_map.
 540         */
 541        n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
 542
 543        host = ata_host_alloc_pinfo(dev, ppi, n_ports);
 544        if (!host)
 545                return -ENOMEM;
 546
 547        host->private_data = hpriv;
 548
 549        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
 550                host->flags |= ATA_HOST_PARALLEL_SCAN;
 551        else
 552                dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
 553
 554        if (pi.flags & ATA_FLAG_EM)
 555                ahci_reset_em(host);
 556
 557        for (i = 0; i < host->n_ports; i++) {
 558                struct ata_port *ap = host->ports[i];
 559
 560                ata_port_desc(ap, "mmio %pR",
 561                              platform_get_resource(pdev, IORESOURCE_MEM, 0));
 562                ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
 563
 564                /* set enclosure management message type */
 565                if (ap->flags & ATA_FLAG_EM)
 566                        ap->em_message_type = hpriv->em_msg_type;
 567
 568                /* disabled/not-implemented port */
 569                if (!(hpriv->port_map & (1 << i)))
 570                        ap->ops = &ata_dummy_port_ops;
 571        }
 572
 573        if (hpriv->cap & HOST_CAP_64) {
 574                rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
 575                if (rc) {
 576                        rc = dma_coerce_mask_and_coherent(dev,
 577                                                          DMA_BIT_MASK(32));
 578                        if (rc) {
 579                                dev_err(dev, "Failed to enable 64-bit DMA.\n");
 580                                return rc;
 581                        }
 582                        dev_warn(dev, "Enable 32-bit DMA instead of 64-bit.\n");
 583                }
 584        }
 585
 586        rc = ahci_reset_controller(host);
 587        if (rc)
 588                return rc;
 589
 590        ahci_init_controller(host);
 591        ahci_print_info(host, "platform");
 592
 593        return ahci_host_activate(host, sht);
 594}
 595EXPORT_SYMBOL_GPL(ahci_platform_init_host);
 596
 597static void ahci_host_stop(struct ata_host *host)
 598{
 599        struct ahci_host_priv *hpriv = host->private_data;
 600
 601        ahci_platform_disable_resources(hpriv);
 602}
 603
 604#ifdef CONFIG_PM_SLEEP
 605/**
 606 * ahci_platform_suspend_host - Suspend an ahci-platform host
 607 * @dev: device pointer for the host
 608 *
 609 * This function does all the usual steps needed to suspend an
 610 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
 611 * must be disabled after calling this.
 612 *
 613 * RETURNS:
 614 * 0 on success otherwise a negative error code
 615 */
 616int ahci_platform_suspend_host(struct device *dev)
 617{
 618        struct ata_host *host = dev_get_drvdata(dev);
 619        struct ahci_host_priv *hpriv = host->private_data;
 620        void __iomem *mmio = hpriv->mmio;
 621        u32 ctl;
 622
 623        if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
 624                dev_err(dev, "firmware update required for suspend/resume\n");
 625                return -EIO;
 626        }
 627
 628        /*
 629         * AHCI spec rev1.1 section 8.3.3:
 630         * Software must disable interrupts prior to requesting a
 631         * transition of the HBA to D3 state.
 632         */
 633        ctl = readl(mmio + HOST_CTL);
 634        ctl &= ~HOST_IRQ_EN;
 635        writel(ctl, mmio + HOST_CTL);
 636        readl(mmio + HOST_CTL); /* flush */
 637
 638        return ata_host_suspend(host, PMSG_SUSPEND);
 639}
 640EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
 641
 642/**
 643 * ahci_platform_resume_host - Resume an ahci-platform host
 644 * @dev: device pointer for the host
 645 *
 646 * This function does all the usual steps needed to resume an ahci-platform
 647 * host, note any necessary resources (ie clks, phys, etc.)  must be
 648 * initialized / enabled before calling this.
 649 *
 650 * RETURNS:
 651 * 0 on success otherwise a negative error code
 652 */
 653int ahci_platform_resume_host(struct device *dev)
 654{
 655        struct ata_host *host = dev_get_drvdata(dev);
 656        int rc;
 657
 658        if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
 659                rc = ahci_reset_controller(host);
 660                if (rc)
 661                        return rc;
 662
 663                ahci_init_controller(host);
 664        }
 665
 666        ata_host_resume(host);
 667
 668        return 0;
 669}
 670EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
 671
 672/**
 673 * ahci_platform_suspend - Suspend an ahci-platform device
 674 * @dev: the platform device to suspend
 675 *
 676 * This function suspends the host associated with the device, followed by
 677 * disabling all the resources of the device.
 678 *
 679 * RETURNS:
 680 * 0 on success otherwise a negative error code
 681 */
 682int ahci_platform_suspend(struct device *dev)
 683{
 684        struct ata_host *host = dev_get_drvdata(dev);
 685        struct ahci_host_priv *hpriv = host->private_data;
 686        int rc;
 687
 688        rc = ahci_platform_suspend_host(dev);
 689        if (rc)
 690                return rc;
 691
 692        ahci_platform_disable_resources(hpriv);
 693
 694        return 0;
 695}
 696EXPORT_SYMBOL_GPL(ahci_platform_suspend);
 697
 698/**
 699 * ahci_platform_resume - Resume an ahci-platform device
 700 * @dev: the platform device to resume
 701 *
 702 * This function enables all the resources of the device followed by
 703 * resuming the host associated with the device.
 704 *
 705 * RETURNS:
 706 * 0 on success otherwise a negative error code
 707 */
 708int ahci_platform_resume(struct device *dev)
 709{
 710        struct ata_host *host = dev_get_drvdata(dev);
 711        struct ahci_host_priv *hpriv = host->private_data;
 712        int rc;
 713
 714        rc = ahci_platform_enable_resources(hpriv);
 715        if (rc)
 716                return rc;
 717
 718        rc = ahci_platform_resume_host(dev);
 719        if (rc)
 720                goto disable_resources;
 721
 722        /* We resumed so update PM runtime state */
 723        pm_runtime_disable(dev);
 724        pm_runtime_set_active(dev);
 725        pm_runtime_enable(dev);
 726
 727        return 0;
 728
 729disable_resources:
 730        ahci_platform_disable_resources(hpriv);
 731
 732        return rc;
 733}
 734EXPORT_SYMBOL_GPL(ahci_platform_resume);
 735#endif
 736
 737MODULE_DESCRIPTION("AHCI SATA platform library");
 738MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
 739MODULE_LICENSE("GPL");
 740