@@ -35,6 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
+#include <linux/clk.h>
#include <linux/libata.h>
/* Enclosure Management Control */
@@ -296,6 +297,9 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
+#ifdef CONFIG_HAVE_CLK
+ struct clk *clk; /* clk structure, only if HAVE_CLK is defined */
+#endif
};
extern int ahci_ignore_sss;
@@ -12,6 +12,7 @@
* any later version.
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
@@ -75,6 +76,20 @@ static int __init ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
+#ifdef CONFIG_HAVE_CLK
+ hpriv->clk = clk_get(dev, NULL);
+ if (IS_ERR(hpriv->clk)) {
+ dev_err(dev, "Clock not found\n");
+ return PTR_ERR(hpriv->clk);
+ }
+
+ rc = clk_enable(hpriv->clk);
+ if (rc) {
+ dev_err(dev, "clock enable failed");
+ goto free_clk;
+ }
+#endif
+
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@@ -84,7 +99,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_clk;
}
ahci_save_initial_config(dev, hpriv,
@@ -110,7 +125,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;
@@ -140,7 +155,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");
@@ -148,12 +163,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_clk:
+#ifdef CONFIG_HAVE_CLK
+ clk_disable(hpriv->clk);
+free_clk:
+ clk_put(hpriv->clk);
+#endif
return rc;
}
@@ -162,12 +183,17 @@ static int __devexit ahci_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev->platform_data;
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);
+#ifdef CONFIG_HAVE_CLK
+ clk_disable(hpriv->clk);
+ clk_put(hpriv->clk);
+#endif
return 0;
}
On many architectures, drivers are supposed to enable/disable functional clock of device. This patch adds support for clock enabling/disabling in ahci_platform.c. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> --- drivers/ata/ahci.h | 4 ++++ drivers/ata/ahci_platform.c | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-)