ARM: Orion: SATA: Add per channel clk/clkdev support.
authorAndrew Lunn <andrew@lunn.ch>
Sat, 18 Feb 2012 21:26:42 +0000 (22:26 +0100)
committerMike Turquette <mturquette@linaro.org>
Tue, 8 May 2012 23:33:58 +0000 (16:33 -0700)
The Orion kirkwood chips have a gatable clock per SATA channel. Add
code to get and enable this clk if it exists.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Jamie Lentin <jm@lentin.co.uk>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
arch/arm/mach-kirkwood/common.c
drivers/ata/sata_mv.c

index 46d7b4374908f1a19c959006a883da1343e5e6e9..c9fef5b7c56e5c846ae3ab422aa7ddcafb515ae9 100644 (file)
@@ -86,7 +86,7 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx)
 
 void __init kirkwood_clk_init(void)
 {
-       struct clk *runit, *ge0, *ge1;
+       struct clk *runit, *ge0, *ge1, *sata0, *sata1, *usb0;
 
        tclk = clk_register_fixed_rate(NULL, "tclk", NULL,
                                       CLK_IS_ROOT, kirkwood_tclk);
@@ -94,8 +94,8 @@ void __init kirkwood_clk_init(void)
        runit = kirkwood_register_gate("runit",  CGC_BIT_RUNIT);
        ge0 = kirkwood_register_gate("ge0",    CGC_BIT_GE0);
        ge1 = kirkwood_register_gate("ge1",    CGC_BIT_GE1);
-       kirkwood_register_gate("sata0",  CGC_BIT_SATA0);
-       kirkwood_register_gate("sata1",  CGC_BIT_SATA1);
+       sata0 = kirkwood_register_gate("sata0",  CGC_BIT_SATA0);
+       sata1 = kirkwood_register_gate("sata1",  CGC_BIT_SATA1);
        kirkwood_register_gate("usb0",   CGC_BIT_USB0);
        kirkwood_register_gate("sdio",   CGC_BIT_SDIO);
        kirkwood_register_gate("crypto", CGC_BIT_CRYPTO);
@@ -113,6 +113,8 @@ void __init kirkwood_clk_init(void)
        orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", ge0);
        orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", ge1);
        orion_clkdev_add(NULL, "orion_wdt", tclk);
+       orion_clkdev_add("0", "sata_mv.0", sata0);
+       orion_clkdev_add("1", "sata_mv.0", sata1);
 }
 
 /*****************************************************************************
index 7336d4a7ab317c091b7b991a1355a712f58023ab..24712adf69dfb8a876ff98d2d39df1182de03942 100644 (file)
@@ -553,6 +553,7 @@ struct mv_host_priv {
 
 #if defined(CONFIG_HAVE_CLK)
        struct clk              *clk;
+       struct clk              **port_clks;
 #endif
        /*
         * These consistent DMA memory pools give us guaranteed
@@ -4027,6 +4028,9 @@ static int mv_platform_probe(struct platform_device *pdev)
        struct resource *res;
        int n_ports = 0;
        int rc;
+#if defined(CONFIG_HAVE_CLK)
+       int port;
+#endif
 
        ata_print_version_once(&pdev->dev, DRV_VERSION);
 
@@ -4054,6 +4058,13 @@ static int mv_platform_probe(struct platform_device *pdev)
 
        if (!host || !hpriv)
                return -ENOMEM;
+#if defined(CONFIG_HAVE_CLK)
+       hpriv->port_clks = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct clk *) * n_ports,
+                                       GFP_KERNEL);
+       if (!hpriv->port_clks)
+               return -ENOMEM;
+#endif
        host->private_data = hpriv;
        hpriv->n_ports = n_ports;
        hpriv->board_idx = chip_soc;
@@ -4066,9 +4077,17 @@ static int mv_platform_probe(struct platform_device *pdev)
 #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");
+               dev_notice(&pdev->dev, "cannot get optional clkdev\n");
        else
-               clk_enable(hpriv->clk);
+               clk_prepare_enable(hpriv->clk);
+
+       for (port = 0; port < n_ports; port++) {
+               char port_number[16];
+               sprintf(port_number, "%d", port);
+               hpriv->port_clks[port] = clk_get(&pdev->dev, port_number);
+               if (!IS_ERR(hpriv->port_clks[port]))
+                       clk_prepare_enable(hpriv->port_clks[port]);
+       }
 #endif
 
        /*
@@ -4098,9 +4117,15 @@ static int mv_platform_probe(struct platform_device *pdev)
 err:
 #if defined(CONFIG_HAVE_CLK)
        if (!IS_ERR(hpriv->clk)) {
-               clk_disable(hpriv->clk);
+               clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
        }
+       for (port = 0; port < n_ports; port++) {
+               if (!IS_ERR(hpriv->port_clks[port])) {
+                       clk_disable_unprepare(hpriv->port_clks[port]);
+                       clk_put(hpriv->port_clks[port]);
+               }
+       }
 #endif
 
        return rc;
@@ -4119,14 +4144,21 @@ static int __devexit mv_platform_remove(struct platform_device *pdev)
        struct ata_host *host = platform_get_drvdata(pdev);
 #if defined(CONFIG_HAVE_CLK)
        struct mv_host_priv *hpriv = host->private_data;
+       int port;
 #endif
        ata_host_detach(host);
 
 #if defined(CONFIG_HAVE_CLK)
        if (!IS_ERR(hpriv->clk)) {
-               clk_disable(hpriv->clk);
+               clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
        }
+       for (port = 0; port < host->n_ports; port++) {
+               if (!IS_ERR(hpriv->port_clks[port])) {
+                       clk_disable_unprepare(hpriv->port_clks[port]);
+                       clk_put(hpriv->port_clks[port]);
+               }
+       }
 #endif
        return 0;
 }