summaryrefslogtreecommitdiffstats
path: root/drivers/ata/sata_mv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r--drivers/ata/sata_mv.c144
1 files changed, 125 insertions, 19 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a8a7be0d06ff..df8ee325d3ca 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -59,6 +59,7 @@
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
@@ -538,6 +539,7 @@ struct mv_port_signal {
struct mv_host_priv {
u32 hp_flags;
+ unsigned int board_idx;
u32 main_irq_mask;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
@@ -548,6 +550,10 @@ struct mv_host_priv {
u32 irq_cause_offset;
u32 irq_mask_offset;
u32 unmask_all_irqs;
+
+#if defined(CONFIG_HAVE_CLK)
+ struct clk *clk;
+#endif
/*
* These consistent DMA memory pools give us guaranteed
* alignment for hardware-accessed data structures,
@@ -2775,7 +2781,7 @@ static void mv_port_intr(struct ata_port *ap, u32 port_cause)
struct mv_port_priv *pp;
int edma_was_enabled;
- if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ if (ap->flags & ATA_FLAG_DISABLED) {
mv_unexpected_intr(ap, 0);
return;
}
@@ -3393,7 +3399,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0x800, port_mmio + EDMA_IORDY_TMOUT);
}
#undef ZERO
@@ -3854,7 +3860,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
/**
* mv_init_host - Perform some early initialization of the host.
* @host: ATA host to initialize
- * @board_idx: controller index
*
* If possible, do an early global reset of the host. Then do
* our port init and clear/unmask all/relevant host interrupts.
@@ -3862,13 +3867,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+static int mv_init_host(struct ata_host *host)
{
int rc = 0, n_hc, port, hc;
struct mv_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->base;
- rc = mv_chip_id(host, board_idx);
+ rc = mv_chip_id(host, hpriv->board_idx);
if (rc)
goto done;
@@ -3905,14 +3910,6 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
void __iomem *port_mmio = mv_port_base(mmio, port);
mv_port_init(&ap->ioaddr, port_mmio);
-
-#ifdef CONFIG_PCI
- if (!IS_SOC(hpriv)) {
- unsigned int offset = port_mmio - mmio;
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
- }
-#endif
}
for (hc = 0; hc < n_hc; hc++) {
@@ -4035,12 +4032,21 @@ static int mv_platform_probe(struct platform_device *pdev)
return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
+ hpriv->board_idx = chip_soc;
host->iomap = NULL;
hpriv->base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
hpriv->base -= SATAHC0_REG_BASE;
+#if defined(CONFIG_HAVE_CLK)
+ hpriv->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hpriv->clk))
+ dev_notice(&pdev->dev, "cannot get clkdev\n");
+ else
+ clk_enable(hpriv->clk);
+#endif
+
/*
* (Re-)program MBUS remapping windows if we are asked to.
*/
@@ -4049,12 +4055,12 @@ static int mv_platform_probe(struct platform_device *pdev)
rc = mv_create_dma_pools(hpriv, &pdev->dev);
if (rc)
- return rc;
+ goto err;
/* initialize adapter */
- rc = mv_init_host(host, chip_soc);
+ rc = mv_init_host(host);
if (rc)
- return rc;
+ goto err;
dev_printk(KERN_INFO, &pdev->dev,
"slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
@@ -4062,6 +4068,15 @@ static int mv_platform_probe(struct platform_device *pdev)
return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
IRQF_SHARED, &mv6_sht);
+err:
+#if defined(CONFIG_HAVE_CLK)
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+#endif
+
+ return rc;
}
/*
@@ -4076,14 +4091,66 @@ static int __devexit mv_platform_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
-
+#if defined(CONFIG_HAVE_CLK)
+ struct mv_host_priv *hpriv = host->private_data;
+#endif
ata_host_detach(host);
+
+#if defined(CONFIG_HAVE_CLK)
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+#endif
return 0;
}
+#ifdef CONFIG_PM
+static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
+}
+
+static int mv_platform_resume(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (host) {
+ struct mv_host_priv *hpriv = host->private_data;
+ const struct mv_sata_platform_data *mv_platform_data = \
+ pdev->dev.platform_data;
+ /*
+ * (Re-)program MBUS remapping windows if we are asked to.
+ */
+ if (mv_platform_data->dram != NULL)
+ mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
+
+ /* initialize adapter */
+ ret = mv_init_host(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
+ return 0;
+}
+#else
+#define mv_platform_suspend NULL
+#define mv_platform_resume NULL
+#endif
+
static struct platform_driver mv_platform_driver = {
.probe = mv_platform_probe,
.remove = __devexit_p(mv_platform_remove),
+ .suspend = mv_platform_suspend,
+ .resume = mv_platform_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
@@ -4094,6 +4161,9 @@ static struct platform_driver mv_platform_driver = {
#ifdef CONFIG_PCI
static int mv_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int mv_pci_device_resume(struct pci_dev *pdev);
+#endif
static struct pci_driver mv_pci_driver = {
@@ -4101,6 +4171,11 @@ static struct pci_driver mv_pci_driver = {
.id_table = mv_pci_tbl,
.probe = mv_pci_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = mv_pci_device_resume,
+#endif
+
};
/* move to PCI layer or libata core? */
@@ -4194,7 +4269,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
struct ata_host *host;
struct mv_host_priv *hpriv;
- int n_ports, rc;
+ int n_ports, port, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -4208,6 +4283,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
+ hpriv->board_idx = board_idx;
/* acquire resources */
rc = pcim_enable_device(pdev);
@@ -4230,8 +4306,17 @@ static int mv_pci_init_one(struct pci_dev *pdev,
if (rc)
return rc;
+ for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
+ void __iomem *port_mmio = mv_port_base(hpriv->base, port);
+ unsigned int offset = port_mmio - hpriv->base;
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+ }
+
/* initialize adapter */
- rc = mv_init_host(host, board_idx);
+ rc = mv_init_host(host);
if (rc)
return rc;
@@ -4247,6 +4332,27 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
}
+
+#ifdef CONFIG_PM
+static int mv_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ /* initialize adapter */
+ rc = mv_init_host(host);
+ if (rc)
+ return rc;
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
#endif
static int mv_platform_probe(struct platform_device *pdev);