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                /* fall through */
 299        case -ENODEV:
 300                /* continue normally */
 301                hpriv->phys[port] = NULL;
 302                rc = 0;
 303                break;
 304
 305        default:
 306                dev_err(dev,
 307                        "couldn't get PHY in node %s: %d\n",
 308                        node->name, rc);
 309
 310                break;
 311        }
 312
 313        return rc;
 314}
 315
 316static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
 317                                struct device *dev)
 318{
 319        struct regulator *target_pwr;
 320        int rc = 0;
 321
 322        target_pwr = regulator_get_optional(dev, "target");
 323
 324        if (!IS_ERR(target_pwr))
 325                hpriv->target_pwrs[port] = target_pwr;
 326        else
 327                rc = PTR_ERR(target_pwr);
 328
 329        return rc;
 330}
 331
 332/**
 333 * ahci_platform_get_resources - Get platform resources
 334 * @pdev: platform device to get resources for
 335 *
 336 * This function allocates an ahci_host_priv struct, and gets the following
 337 * resources, storing a reference to them inside the returned struct:
 338 *
 339 * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
 340 * 2) regulator for controlling the targets power (optional)
 341 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
 342 *    or for non devicetree enabled platforms a single clock
 343 * 4) phys (optional)
 344 *
 345 * RETURNS:
 346 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
 347 */
 348struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
 349{
 350        struct device *dev = &pdev->dev;
 351        struct ahci_host_priv *hpriv;
 352        struct clk *clk;
 353        struct device_node *child;
 354        int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes;
 355        u32 mask_port_map = 0;
 356
 357        if (!devres_open_group(dev, NULL, GFP_KERNEL))
 358                return ERR_PTR(-ENOMEM);
 359
 360        hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
 361                             GFP_KERNEL);
 362        if (!hpriv)
 363                goto err_out;
 364
 365        devres_add(dev, hpriv);
 366
 367        hpriv->mmio = devm_ioremap_resource(dev,
 368                              platform_get_resource(pdev, IORESOURCE_MEM, 0));
 369        if (IS_ERR(hpriv->mmio)) {
 370                dev_err(dev, "no mmio space\n");
 371                rc = PTR_ERR(hpriv->mmio);
 372                goto err_out;
 373        }
 374
 375        for (i = 0; i < AHCI_MAX_CLKS; i++) {
 376                /*
 377                 * For now we must use clk_get(dev, NULL) for the first clock,
 378                 * because some platforms (da850, spear13xx) are not yet
 379                 * converted to use devicetree for clocks.  For new platforms
 380                 * this is equivalent to of_clk_get(dev->of_node, 0).
 381                 */
 382                if (i == 0)
 383                        clk = clk_get(dev, NULL);
 384                else
 385                        clk = of_clk_get(dev->of_node, i);
 386
 387                if (IS_ERR(clk)) {
 388                        rc = PTR_ERR(clk);
 389                        if (rc == -EPROBE_DEFER)
 390                                goto err_out;
 391                        break;
 392                }
 393                hpriv->clks[i] = clk;
 394        }
 395
 396        hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
 397
 398        /*
 399         * If no sub-node was found, we still need to set nports to
 400         * one in order to be able to use the
 401         * ahci_platform_[en|dis]able_[phys|regulators] functions.
 402         */
 403        if (!child_nodes)
 404                hpriv->nports = 1;
 405
 406        sz = hpriv->nports * sizeof(*hpriv->phys);
 407        hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL);
 408        if (!hpriv->phys) {
 409                rc = -ENOMEM;
 410                goto err_out;
 411        }
 412        sz = hpriv->nports * sizeof(*hpriv->target_pwrs);
 413        hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL);
 414        if (!hpriv->target_pwrs) {
 415                rc = -ENOMEM;
 416                goto err_out;
 417        }
 418
 419        if (child_nodes) {
 420                for_each_child_of_node(dev->of_node, child) {
 421                        u32 port;
 422                        struct platform_device *port_dev __maybe_unused;
 423
 424                        if (!of_device_is_available(child))
 425                                continue;
 426
 427                        if (of_property_read_u32(child, "reg", &port)) {
 428                                rc = -EINVAL;
 429                                goto err_out;
 430                        }
 431
 432                        if (port >= hpriv->nports) {
 433                                dev_warn(dev, "invalid port number %d\n", port);
 434                                continue;
 435                        }
 436                        mask_port_map |= BIT(port);
 437
 438#ifdef CONFIG_OF_ADDRESS
 439                        of_platform_device_create(child, NULL, NULL);
 440
 441                        port_dev = of_find_device_by_node(child);
 442
 443                        if (port_dev) {
 444                                rc = ahci_platform_get_regulator(hpriv, port,
 445                                                                &port_dev->dev);
 446                                if (rc == -EPROBE_DEFER)
 447                                        goto err_out;
 448                        }
 449#endif
 450
 451                        rc = ahci_platform_get_phy(hpriv, port, dev, child);
 452                        if (rc)
 453                                goto err_out;
 454
 455                        enabled_ports++;
 456                }
 457                if (!enabled_ports) {
 458                        dev_warn(dev, "No port enabled\n");
 459                        rc = -ENODEV;
 460                        goto err_out;
 461                }
 462
 463                if (!hpriv->mask_port_map)
 464                        hpriv->mask_port_map = mask_port_map;
 465        } else {
 466                /*
 467                 * If no sub-node was found, keep this for device tree
 468                 * compatibility
 469                 */
 470                rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
 471                if (rc)
 472                        goto err_out;
 473
 474                rc = ahci_platform_get_regulator(hpriv, 0, dev);
 475                if (rc == -EPROBE_DEFER)
 476                        goto err_out;
 477        }
 478        pm_runtime_enable(dev);
 479        pm_runtime_get_sync(dev);
 480        hpriv->got_runtime_pm = true;
 481
 482        devres_remove_group(dev, NULL);
 483        return hpriv;
 484
 485err_out:
 486        devres_release_group(dev, NULL);
 487        return ERR_PTR(rc);
 488}
 489EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
 490
 491/**
 492 * ahci_platform_init_host - Bring up an ahci-platform host
 493 * @pdev: platform device pointer for the host
 494 * @hpriv: ahci-host private data for the host
 495 * @pi_template: template for the ata_port_info to use
 496 * @sht: scsi_host_template to use when registering
 497 *
 498 * This function does all the usual steps needed to bring up an
 499 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
 500 * must be initialized / enabled before calling this.
 501 *
 502 * RETURNS:
 503 * 0 on success otherwise a negative error code
 504 */
 505int ahci_platform_init_host(struct platform_device *pdev,
 506                            struct ahci_host_priv *hpriv,
 507                            const struct ata_port_info *pi_template,
 508                            struct scsi_host_template *sht)
 509{
 510        struct device *dev = &pdev->dev;
 511        struct ata_port_info pi = *pi_template;
 512        const struct ata_port_info *ppi[] = { &pi, NULL };
 513        struct ata_host *host;
 514        int i, irq, n_ports, rc;
 515
 516        irq = platform_get_irq(pdev, 0);
 517        if (irq <= 0) {
 518                if (irq != -EPROBE_DEFER)
 519                        dev_err(dev, "no irq\n");
 520                return irq;
 521        }
 522
 523        hpriv->irq = irq;
 524
 525        /* prepare host */
 526        pi.private_data = (void *)(unsigned long)hpriv->flags;
 527
 528        ahci_save_initial_config(dev, hpriv);
 529
 530        if (hpriv->cap & HOST_CAP_NCQ)
 531                pi.flags |= ATA_FLAG_NCQ;
 532
 533        if (hpriv->cap & HOST_CAP_PMP)
 534                pi.flags |= ATA_FLAG_PMP;
 535
 536        ahci_set_em_messages(hpriv, &pi);
 537
 538        /* CAP.NP sometimes indicate the index of the last enabled
 539         * port, at other times, that of the last possible port, so
 540         * determining the maximum port number requires looking at
 541         * both CAP.NP and port_map.
 542         */
 543        n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
 544
 545        host = ata_host_alloc_pinfo(dev, ppi, n_ports);
 546        if (!host)
 547                return -ENOMEM;
 548
 549        host->private_data = hpriv;
 550
 551        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
 552                host->flags |= ATA_HOST_PARALLEL_SCAN;
 553        else
 554                dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
 555
 556        if (pi.flags & ATA_FLAG_EM)
 557                ahci_reset_em(host);
 558
 559        for (i = 0; i < host->n_ports; i++) {
 560                struct ata_port *ap = host->ports[i];
 561
 562                ata_port_desc(ap, "mmio %pR",
 563                              platform_get_resource(pdev, IORESOURCE_MEM, 0));
 564                ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
 565
 566                /* set enclosure management message type */
 567                if (ap->flags & ATA_FLAG_EM)
 568                        ap->em_message_type = hpriv->em_msg_type;
 569
 570                /* disabled/not-implemented port */
 571                if (!(hpriv->port_map & (1 << i)))
 572                        ap->ops = &ata_dummy_port_ops;
 573        }
 574
 575        if (hpriv->cap & HOST_CAP_64) {
 576                rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
 577                if (rc) {
 578                        rc = dma_coerce_mask_and_coherent(dev,
 579                                                          DMA_BIT_MASK(32));
 580                        if (rc) {
 581                                dev_err(dev, "Failed to enable 64-bit DMA.\n");
 582                                return rc;
 583                        }
 584                        dev_warn(dev, "Enable 32-bit DMA instead of 64-bit.\n");
 585                }
 586        }
 587
 588        rc = ahci_reset_controller(host);
 589        if (rc)
 590                return rc;
 591
 592        ahci_init_controller(host);
 593        ahci_print_info(host, "platform");
 594
 595        return ahci_host_activate(host, sht);
 596}
 597EXPORT_SYMBOL_GPL(ahci_platform_init_host);
 598
 599static void ahci_host_stop(struct ata_host *host)
 600{
 601        struct ahci_host_priv *hpriv = host->private_data;
 602
 603        ahci_platform_disable_resources(hpriv);
 604}
 605
 606/**
 607 * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports
 608 * @dev: platform device pointer for the host
 609 *
 610 * This function is called during system shutdown and performs the minimal
 611 * deconfiguration required to ensure that an ahci_platform host cannot
 612 * corrupt or otherwise interfere with a new kernel being started with kexec.
 613 */
 614void ahci_platform_shutdown(struct platform_device *pdev)
 615{
 616        struct ata_host *host = platform_get_drvdata(pdev);
 617        struct ahci_host_priv *hpriv = host->private_data;
 618        void __iomem *mmio = hpriv->mmio;
 619        int i;
 620
 621        for (i = 0; i < host->n_ports; i++) {
 622                struct ata_port *ap = host->ports[i];
 623
 624                /* Disable port interrupts */
 625                if (ap->ops->freeze)
 626                        ap->ops->freeze(ap);
 627
 628                /* Stop the port DMA engines */
 629                if (ap->ops->port_stop)
 630                        ap->ops->port_stop(ap);
 631        }
 632
 633        /* Disable and clear host interrupts */
 634        writel(readl(mmio + HOST_CTL) & ~HOST_IRQ_EN, mmio + HOST_CTL);
 635        readl(mmio + HOST_CTL); /* flush */
 636        writel(GENMASK(host->n_ports, 0), mmio + HOST_IRQ_STAT);
 637}
 638EXPORT_SYMBOL_GPL(ahci_platform_shutdown);
 639
 640#ifdef CONFIG_PM_SLEEP
 641/**
 642 * ahci_platform_suspend_host - Suspend an ahci-platform host
 643 * @dev: device pointer for the host
 644 *
 645 * This function does all the usual steps needed to suspend an
 646 * ahci-platform host, note any necessary resources (ie clks, phys, etc.)
 647 * must be disabled after calling this.
 648 *
 649 * RETURNS:
 650 * 0 on success otherwise a negative error code
 651 */
 652int ahci_platform_suspend_host(struct device *dev)
 653{
 654        struct ata_host *host = dev_get_drvdata(dev);
 655        struct ahci_host_priv *hpriv = host->private_data;
 656        void __iomem *mmio = hpriv->mmio;
 657        u32 ctl;
 658
 659        if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
 660                dev_err(dev, "firmware update required for suspend/resume\n");
 661                return -EIO;
 662        }
 663
 664        /*
 665         * AHCI spec rev1.1 section 8.3.3:
 666         * Software must disable interrupts prior to requesting a
 667         * transition of the HBA to D3 state.
 668         */
 669        ctl = readl(mmio + HOST_CTL);
 670        ctl &= ~HOST_IRQ_EN;
 671        writel(ctl, mmio + HOST_CTL);
 672        readl(mmio + HOST_CTL); /* flush */
 673
 674        return ata_host_suspend(host, PMSG_SUSPEND);
 675}
 676EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
 677
 678/**
 679 * ahci_platform_resume_host - Resume an ahci-platform host
 680 * @dev: device pointer for the host
 681 *
 682 * This function does all the usual steps needed to resume an ahci-platform
 683 * host, note any necessary resources (ie clks, phys, etc.)  must be
 684 * initialized / enabled before calling this.
 685 *
 686 * RETURNS:
 687 * 0 on success otherwise a negative error code
 688 */
 689int ahci_platform_resume_host(struct device *dev)
 690{
 691        struct ata_host *host = dev_get_drvdata(dev);
 692        int rc;
 693
 694        if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
 695                rc = ahci_reset_controller(host);
 696                if (rc)
 697                        return rc;
 698
 699                ahci_init_controller(host);
 700        }
 701
 702        ata_host_resume(host);
 703
 704        return 0;
 705}
 706EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
 707
 708/**
 709 * ahci_platform_suspend - Suspend an ahci-platform device
 710 * @dev: the platform device to suspend
 711 *
 712 * This function suspends the host associated with the device, followed by
 713 * disabling all the resources of the device.
 714 *
 715 * RETURNS:
 716 * 0 on success otherwise a negative error code
 717 */
 718int ahci_platform_suspend(struct device *dev)
 719{
 720        struct ata_host *host = dev_get_drvdata(dev);
 721        struct ahci_host_priv *hpriv = host->private_data;
 722        int rc;
 723
 724        rc = ahci_platform_suspend_host(dev);
 725        if (rc)
 726                return rc;
 727
 728        ahci_platform_disable_resources(hpriv);
 729
 730        return 0;
 731}
 732EXPORT_SYMBOL_GPL(ahci_platform_suspend);
 733
 734/**
 735 * ahci_platform_resume - Resume an ahci-platform device
 736 * @dev: the platform device to resume
 737 *
 738 * This function enables all the resources of the device followed by
 739 * resuming the host associated with the device.
 740 *
 741 * RETURNS:
 742 * 0 on success otherwise a negative error code
 743 */
 744int ahci_platform_resume(struct device *dev)
 745{
 746        struct ata_host *host = dev_get_drvdata(dev);
 747        struct ahci_host_priv *hpriv = host->private_data;
 748        int rc;
 749
 750        rc = ahci_platform_enable_resources(hpriv);
 751        if (rc)
 752                return rc;
 753
 754        rc = ahci_platform_resume_host(dev);
 755        if (rc)
 756                goto disable_resources;
 757
 758        /* We resumed so update PM runtime state */
 759        pm_runtime_disable(dev);
 760        pm_runtime_set_active(dev);
 761        pm_runtime_enable(dev);
 762
 763        return 0;
 764
 765disable_resources:
 766        ahci_platform_disable_resources(hpriv);
 767
 768        return rc;
 769}
 770EXPORT_SYMBOL_GPL(ahci_platform_resume);
 771#endif
 772
 773MODULE_DESCRIPTION("AHCI SATA platform library");
 774MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
 775MODULE_LICENSE("GPL");
 776