aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata/ahci_platform.c
diff options
context:
space:
mode:
authorLinus Torvalds2012-10-02 18:23:35 -0700
committerLinus Torvalds2012-10-02 18:23:35 -0700
commit51562cba98939da0a1d10fe7c25359b77a069033 (patch)
tree9c18b8ac63eab57a87cb19421734ce9843be30e6 /drivers/ata/ahci_platform.c
parent7fe0b14b725d6d09a1d9e1409bd465cb88b587f9 (diff)
parent13b74085d92feda78bad1045516d332a1e9a3407 (diff)
Merge tag 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
Pull libata changes from Jeff Garzik: "Minor libata updates, nothing notable. 1) Apply -- and then revert -- the FUA feature. Caused disk corruption in linux-next, proving it cannot be turned on by default. Net effect to upstream tree: zero 2) New AHCI platform driver sata_highbank 3) Improve SCSI MODE SENSE handling; support MODE SELECT 4) AHCI: support aggressive device sleep (power mgmt) 5) sata_fsl: minor fix 6) pata_arasan: clk support" * tag 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: sata_mv: Fix warnings when no PCI [libata] Makefile: Fix build error in sata_highbank [libata] export ata_dev_set_feature() libata-core: use ATA_LBA in ata_build_rw_tf() ata/ahci_platform: Add clock framework support pata_arasan: add Device Tree probing capability pata_arasan: Add clk_{un}prepare() support ata: add platform driver for Calxeda AHCI controller sata_fsl: add workaround for data length mismatch on freescale V2 controller ahci: implement aggressive SATA device sleep support ata: define enum constants for IDENTIFY DEVICE Revert "libata: enable SATA disk fua detection on default" [libata] scsi: implement MODE SELECT command [libata] scsi: support MODE SENSE request for changeable and default parameters [libata] scsi: Remove unlikely() from FUA check libata: enable SATA disk fua detection on default
Diffstat (limited to 'drivers/ata/ahci_platform.c')
-rw-r--r--drivers/ata/ahci_platform.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 09728e09cb31..b1ae48054dc5 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -12,6 +12,7 @@
* any later version.
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
@@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ hpriv->clk = clk_get(dev, NULL);
+ if (IS_ERR(hpriv->clk)) {
+ dev_err(dev, "can't get clock\n");
+ } else {
+ rc = clk_prepare_enable(hpriv->clk);
+ if (rc) {
+ dev_err(dev, "clock prepare enable failed");
+ goto free_clk;
+ }
+ }
+
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@@ -127,7 +139,7 @@ static int __init ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv->mmio);
if (rc)
- return rc;
+ goto disable_unprepare_clk;
}
ahci_save_initial_config(dev, hpriv,
@@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev)
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
if (!host) {
rc = -ENOMEM;
- goto err0;
+ goto pdata_exit;
}
host->private_data = hpriv;
@@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ahci_reset_controller(host);
if (rc)
- goto err0;
+ goto pdata_exit;
ahci_init_controller(host);
ahci_print_info(host, "platform");
@@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
&ahci_platform_sht);
if (rc)
- goto err0;
+ goto pdata_exit;
return 0;
-err0:
+pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
+disable_unprepare_clk:
+ if (!IS_ERR(hpriv->clk))
+ clk_disable_unprepare(hpriv->clk);
+free_clk:
+ if (!IS_ERR(hpriv->clk))
+ clk_put(hpriv->clk);
return rc;
}
@@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
ata_host_detach(host);
if (pdata && pdata->exit)
pdata->exit(dev);
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable_unprepare(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+
return 0;
}
@@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
+
+ if (!IS_ERR(hpriv->clk))
+ clk_disable_unprepare(hpriv->clk);
+
return 0;
}
@@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
int rc;
+ if (!IS_ERR(hpriv->clk)) {
+ rc = clk_prepare_enable(hpriv->clk);
+ if (rc) {
+ dev_err(dev, "clock prepare enable failed");
+ return rc;
+ }
+ }
+
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
if (rc)
- return rc;
+ goto disable_unprepare_clk;
}
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
- return rc;
+ goto disable_unprepare_clk;
ahci_init_controller(host);
}
@@ -271,13 +308,18 @@ static int ahci_resume(struct device *dev)
ata_host_resume(host);
return 0;
+
+disable_unprepare_clk:
+ if (!IS_ERR(hpriv->clk))
+ clk_disable_unprepare(hpriv->clk);
+
+ return rc;
}
#endif
SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
static const struct of_device_id ahci_of_match[] = {
- { .compatible = "calxeda,hb-ahci", },
{ .compatible = "snps,spear-ahci", },
{},
};