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: Viresh Kumar <viresh.kumar@linaro.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
Viresh Kumar 2012-08-27 10:37:19 +05:30 committed by Jeff Garzik
parent 26fdaa7453
commit f1e70c2c53
2 changed files with 52 additions and 7 deletions

View File

@ -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 {
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;

View File

@ -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)
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)
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)
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)
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)
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)
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)
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)
{ {
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)
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