提交 f1e70c2c 编写于 作者: V Viresh Kumar 提交者: Jeff Garzik

ata/ahci_platform: Add clock framework support

On many architectures, drivers are supposed to prepare/unprepare &
enable/disable functional clock of device. This patch adds clock support for
ahci_platform.
Signed-off-by: NViresh Kumar <viresh.kumar@linaro.com>
Signed-off-by: NJeff Garzik <jgarzik@redhat.com>
上级 26fdaa74
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#ifndef _AHCI_H #ifndef _AHCI_H
#define _AHCI_H #define _AHCI_H
#include <linux/clk.h>
#include <linux/libata.h> #include <linux/libata.h>
/* Enclosure Management Control */ /* Enclosure Management Control */
...@@ -316,6 +317,7 @@ struct ahci_host_priv { ...@@ -316,6 +317,7 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */ u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */ u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */ u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
}; };
extern int ahci_ignore_sss; extern int ahci_ignore_sss;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* any later version. * any later version.
*/ */
#include <linux/clk.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev) ...@@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev)
return -ENOMEM; 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, * Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio * 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) ...@@ -127,7 +139,7 @@ static int __init ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) { if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv->mmio); rc = pdata->init(dev, hpriv->mmio);
if (rc) if (rc)
return rc; goto disable_unprepare_clk;
} }
ahci_save_initial_config(dev, hpriv, ahci_save_initial_config(dev, hpriv,
...@@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev) ...@@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev)
host = ata_host_alloc_pinfo(dev, ppi, n_ports); host = ata_host_alloc_pinfo(dev, ppi, n_ports);
if (!host) { if (!host) {
rc = -ENOMEM; rc = -ENOMEM;
goto err0; goto pdata_exit;
} }
host->private_data = hpriv; host->private_data = hpriv;
...@@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev) ...@@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ahci_reset_controller(host); rc = ahci_reset_controller(host);
if (rc) if (rc)
goto err0; goto pdata_exit;
ahci_init_controller(host); ahci_init_controller(host);
ahci_print_info(host, "platform"); ahci_print_info(host, "platform");
...@@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev) ...@@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
&ahci_platform_sht); &ahci_platform_sht);
if (rc) if (rc)
goto err0; goto pdata_exit;
return 0; return 0;
err0: pdata_exit:
if (pdata && pdata->exit) if (pdata && pdata->exit)
pdata->exit(dev); 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; return rc;
} }
...@@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev) ...@@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
ata_host_detach(host); ata_host_detach(host);
if (pdata && pdata->exit) if (pdata && pdata->exit)
pdata->exit(dev); pdata->exit(dev);
if (!IS_ERR(hpriv->clk)) {
clk_disable_unprepare(hpriv->clk);
clk_put(hpriv->clk);
}
return 0; return 0;
} }
...@@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev) ...@@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend) if (pdata && pdata->suspend)
return pdata->suspend(dev); return pdata->suspend(dev);
if (!IS_ERR(hpriv->clk))
clk_disable_unprepare(hpriv->clk);
return 0; return 0;
} }
...@@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev) ...@@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev)
{ {
struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
int rc; 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) { if (pdata && pdata->resume) {
rc = pdata->resume(dev); rc = pdata->resume(dev);
if (rc) if (rc)
return rc; goto disable_unprepare_clk;
} }
if (dev->power.power_state.event == PM_EVENT_SUSPEND) { if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host); rc = ahci_reset_controller(host);
if (rc) if (rc)
return rc; goto disable_unprepare_clk;
ahci_init_controller(host); ahci_init_controller(host);
} }
...@@ -271,6 +308,12 @@ static int ahci_resume(struct device *dev) ...@@ -271,6 +308,12 @@ static int ahci_resume(struct device *dev)
ata_host_resume(host); ata_host_resume(host);
return 0; return 0;
disable_unprepare_clk:
if (!IS_ERR(hpriv->clk))
clk_disable_unprepare(hpriv->clk);
return rc;
} }
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册