ahci-imx: Port to library-ised ahci_platform
authorHans de Goede <hdegoede@redhat.com>
Sat, 22 Feb 2014 15:53:37 +0000 (16:53 +0100)
committerTejun Heo <tj@kernel.org>
Sat, 22 Feb 2014 20:35:42 +0000 (15:35 -0500)
This avoids the ugliness of creating a nested platform device from probe.

While moving it around anyways, move the mk6q phy init code from probe
to imx_sata_enable, as the phy needs to be re-initialized on resume too,
otherwise the drive won't be recognized after resume.

Tested on a wandboard i.mx6 quad.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Documentation/devicetree/bindings/ata/ahci-platform.txt
drivers/ata/ahci_imx.c

index 499bfed81054b5b6dcd3fcc014d31804d12ead16..d86e854036575ab2d73e56068921298336e23339 100644 (file)
@@ -5,8 +5,9 @@ Each SATA controller should have its own node.
 
 Required properties:
 - compatible        : compatible list, one of "snps,spear-ahci",
-                      "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
-                      "allwinner,sun4i-a10-ahci"
+                      "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+                      "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci" or
+                      "fsl,imx6q-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
@@ -15,6 +16,10 @@ Optional properties:
 - clocks            : a list of phandle + clock specifier pairs
 - target-supply     : regulator for SATA target power
 
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks            : must contain the sata, sata_ref and ahb clocks
+- clock-names       : must contain "ahb" for the ahb clock
+
 Examples:
         sata@ffe08000 {
                compatible = "snps,spear-ahci";
index dd4d6f74d7bd5067a62840019a53c016b74efd6e..3cb5d69581f1f0ee54e0c53a72cc18f80ff5d279 100644 (file)
@@ -42,13 +42,7 @@ enum ahci_imx_type {
 struct imx_ahci_priv {
        struct platform_device *ahci_pdev;
        enum ahci_imx_type type;
-
-       /* i.MX53 clock */
-       struct clk *sata_gate_clk;
-       /* Common clock */
-       struct clk *sata_ref_clk;
        struct clk *ahb_clk;
-
        struct regmap *gpr;
        bool no_device;
        bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
 module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
 MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
 
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret;
 
-       if (imxpriv->type == AHCI_IMX53) {
-               ret = clk_prepare_enable(imxpriv->sata_gate_clk);
-               if (ret < 0) {
-                       dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
-                               ret);
+       if (imxpriv->no_device)
+               return 0;
+
+       if (hpriv->target_pwr) {
+               ret = regulator_enable(hpriv->target_pwr);
+               if (ret)
                        return ret;
-               }
        }
 
-       ret = clk_prepare_enable(imxpriv->sata_ref_clk);
-       if (ret < 0) {
-               dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
-                       ret);
-               goto clk_err;
-       }
+       ret = ahci_platform_enable_clks(hpriv);
+       if (ret < 0)
+               goto disable_regulator;
 
        if (imxpriv->type == AHCI_IMX6Q) {
+               /*
+                * set PHY Paremeters, two steps to configure the GPR13,
+                * one write for rest of parameters, mask of first write
+                * is 0x07ffffff, and the other one write for setting
+                * the mpll_clk_en.
+                */
+               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
 
        return 0;
 
-clk_err:
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+
        return ret;
 }
 
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+       if (imxpriv->no_device)
+               return;
 
        if (imxpriv->type == AHCI_IMX6Q) {
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
                                   !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
        }
 
-       clk_disable_unprepare(imxpriv->sata_ref_clk);
+       ahci_platform_disable_clks(hpriv);
 
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
 }
 
 static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
        struct ata_host *host = dev_get_drvdata(ap->dev);
        struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = hpriv->mmio;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
 
        ahci_error_handler(ap);
 
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
         */
        reg_val = readl(mmio + PORT_PHY_CTL);
        writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
-       imx_sata_clock_disable(ap->dev);
+       imx_sata_disable(hpriv);
        imxpriv->no_device = true;
 }
 
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
                       unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct ata_host *host = dev_get_drvdata(ap->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret = -EIO;
 
        if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
 }
 
 static struct ata_port_operations ahci_imx_ops = {
-       .inherits       = &ahci_platform_ops,
+       .inherits       = &ahci_ops,
+       .host_stop      = ahci_imx_host_stop,
        .error_handler  = ahci_imx_error_handler,
        .softreset      = ahci_imx_softreset,
 };
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
        .port_ops       = &ahci_imx_ops,
 };
 
-static int imx_sata_init(struct device *dev, void __iomem *mmio)
-{
-       int ret = 0;
-       unsigned int reg_val;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
-       ret = imx_sata_clock_enable(dev);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
-        * and IP vendor specific register HOST_TIMER1MS.
-        * Configure CAP_SSS (support stagered spin up).
-        * Implement the port0.
-        * Get the ahb clock rate, and configure the TIMER1MS register.
-        */
-       reg_val = readl(mmio + HOST_CAP);
-       if (!(reg_val & HOST_CAP_SSS)) {
-               reg_val |= HOST_CAP_SSS;
-               writel(reg_val, mmio + HOST_CAP);
-       }
-       reg_val = readl(mmio + HOST_PORTS_IMPL);
-       if (!(reg_val & 0x1)) {
-               reg_val |= 0x1;
-               writel(reg_val, mmio + HOST_PORTS_IMPL);
-       }
-
-       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
-       writel(reg_val, mmio + HOST_TIMER1MS);
-
-       return 0;
-}
-
-static void imx_sata_exit(struct device *dev)
-{
-       imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-
-       /*
-        * If no_device is set, The CLKs had been gated off in the
-        * initialization so don't do it again here.
-        */
-       if (!imxpriv->no_device)
-               imx_sata_clock_disable(dev);
-
-       return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-       int ret = 0;
-
-       if (!imxpriv->no_device)
-               ret = imx_sata_clock_enable(dev);
-
-       return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
-       .init           = imx_sata_init,
-       .exit           = imx_sata_exit,
-       .ata_port_info  = &ahci_imx_port_info,
-       .suspend        = imx_ahci_suspend,
-       .resume         = imx_ahci_resume,
-
-};
-
 static const struct of_device_id imx_ahci_of_match[] = {
        { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
        { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,122 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
 static int imx_ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *mem, *irq, res[2];
        const struct of_device_id *of_id;
-       enum ahci_imx_type type;
-       const struct ahci_platform_data *pdata = NULL;
+       struct ahci_host_priv *hpriv;
        struct imx_ahci_priv *imxpriv;
-       struct device *ahci_dev;
-       struct platform_device *ahci_pdev;
+       unsigned int reg_val;
        int ret;
 
        of_id = of_match_device(imx_ahci_of_match, dev);
        if (!of_id)
                return -EINVAL;
 
-       type = (enum ahci_imx_type)of_id->data;
-       pdata = &imx_sata_pdata;
-
        imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
-       if (!imxpriv) {
-               dev_err(dev, "can't alloc ahci_host_priv\n");
+       if (!imxpriv)
                return -ENOMEM;
-       }
-
-       ahci_pdev = platform_device_alloc("ahci", -1);
-       if (!ahci_pdev)
-               return -ENODEV;
-
-       ahci_dev = &ahci_pdev->dev;
-       ahci_dev->parent = dev;
 
        imxpriv->no_device = false;
        imxpriv->first_time = true;
-       imxpriv->type = type;
-
+       imxpriv->type = (enum ahci_imx_type)of_id->data;
        imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
        if (IS_ERR(imxpriv->ahb_clk)) {
                dev_err(dev, "can't get ahb clock.\n");
-               ret = PTR_ERR(imxpriv->ahb_clk);
-               goto err_out;
+               return PTR_ERR(imxpriv->ahb_clk);
        }
 
-       if (type == AHCI_IMX53) {
-               imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
-               if (IS_ERR(imxpriv->sata_gate_clk)) {
-                       dev_err(dev, "can't get sata_gate clock.\n");
-                       ret = PTR_ERR(imxpriv->sata_gate_clk);
-                       goto err_out;
+       if (imxpriv->type == AHCI_IMX6Q) {
+               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+                                                       "fsl,imx6q-iomuxc-gpr");
+               if (IS_ERR(imxpriv->gpr)) {
+                       dev_err(dev,
+                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
+                       return PTR_ERR(imxpriv->gpr);
                }
        }
 
-       imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
-       if (IS_ERR(imxpriv->sata_ref_clk)) {
-               dev_err(dev, "can't get sata_ref clock.\n");
-               ret = PTR_ERR(imxpriv->sata_ref_clk);
-               goto err_out;
-       }
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       hpriv->plat_data = imxpriv;
 
-       imxpriv->ahci_pdev = ahci_pdev;
-       platform_set_drvdata(pdev, imxpriv);
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!mem || !irq) {
-               dev_err(dev, "no mmio/irq resource\n");
-               ret = -ENOMEM;
-               goto err_out;
+       /*
+        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+        * and IP vendor specific register HOST_TIMER1MS.
+        * Configure CAP_SSS (support stagered spin up).
+        * Implement the port0.
+        * Get the ahb clock rate, and configure the TIMER1MS register.
+        */
+       reg_val = readl(hpriv->mmio + HOST_CAP);
+       if (!(reg_val & HOST_CAP_SSS)) {
+               reg_val |= HOST_CAP_SSS;
+               writel(reg_val, hpriv->mmio + HOST_CAP);
+       }
+       reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+       if (!(reg_val & 0x1)) {
+               reg_val |= 0x1;
+               writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
        }
 
-       res[0] = *mem;
-       res[1] = *irq;
+       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+       writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
 
-       ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
-       ahci_dev->of_node = dev->of_node;
+       ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+       if (ret)
+               imx_sata_disable(hpriv);
 
-       if (type == AHCI_IMX6Q) {
-               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
-                                                       "fsl,imx6q-iomuxc-gpr");
-               if (IS_ERR(imxpriv->gpr)) {
-                       dev_err(dev,
-                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
-                       ret = PTR_ERR(imxpriv->gpr);
-                       goto err_out;
-               }
+       return ret;
+}
 
-               /*
-                * Set PHY Paremeters, two steps to configure the GPR13,
-                * one write for rest of parameters, mask of first write
-                * is 0x07fffffe, and the other one write for setting
-                * the mpll_clk_en happens in imx_sata_clock_enable().
-                */
-               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
-                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
-                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
-                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
-       }
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
 
-       ret = platform_device_add_resources(ahci_pdev, res, 2);
-       if (ret)
-               goto err_out;
+       imx_sata_disable(hpriv);
+}
 
-       ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
-       if (ret)
-               goto err_out;
+static int imx_ahci_suspend(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       ret = platform_device_add(ahci_pdev);
-       if (ret) {
-err_out:
-               platform_device_put(ahci_pdev);
+       ret = ahci_platform_suspend_host(dev);
+       if (ret)
                return ret;
-       }
+
+       imx_sata_disable(hpriv);
 
        return 0;
 }
 
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
 {
-       struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
-       struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       platform_device_unregister(ahci_pdev);
-       return 0;
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
+
+       return ahci_platform_resume_host(dev);
 }
 
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
+
 static struct platform_driver imx_ahci_driver = {
        .probe = imx_ahci_probe,
-       .remove = imx_ahci_remove,
+       .remove = ata_platform_remove_one,
        .driver = {
                .name = "ahci-imx",
                .owner = THIS_MODULE,
                .of_match_table = imx_ahci_of_match,
+               .pm = &ahci_imx_pm_ops,
        },
 };
 module_platform_driver(imx_ahci_driver);