Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  phy-mvebu-sata.c: SATA Phy driver for the Marvell mvebu SoCs.
0004  *
0005  *  Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010 #include <linux/clk.h>
0011 #include <linux/phy/phy.h>
0012 #include <linux/io.h>
0013 #include <linux/platform_device.h>
0014 
0015 struct priv {
0016     struct clk  *clk;
0017     void __iomem    *base;
0018 };
0019 
0020 #define SATA_PHY_MODE_2 0x0330
0021 #define  MODE_2_FORCE_PU_TX BIT(0)
0022 #define  MODE_2_FORCE_PU_RX BIT(1)
0023 #define  MODE_2_PU_PLL      BIT(2)
0024 #define  MODE_2_PU_IVREF    BIT(3)
0025 #define SATA_IF_CTRL    0x0050
0026 #define  CTRL_PHY_SHUTDOWN  BIT(9)
0027 
0028 static int phy_mvebu_sata_power_on(struct phy *phy)
0029 {
0030     struct priv *priv = phy_get_drvdata(phy);
0031     u32 reg;
0032 
0033     clk_prepare_enable(priv->clk);
0034 
0035     /* Enable PLL and IVREF */
0036     reg = readl(priv->base + SATA_PHY_MODE_2);
0037     reg |= (MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
0038         MODE_2_PU_PLL | MODE_2_PU_IVREF);
0039     writel(reg , priv->base + SATA_PHY_MODE_2);
0040 
0041     /* Enable PHY */
0042     reg = readl(priv->base + SATA_IF_CTRL);
0043     reg &= ~CTRL_PHY_SHUTDOWN;
0044     writel(reg, priv->base + SATA_IF_CTRL);
0045 
0046     clk_disable_unprepare(priv->clk);
0047 
0048     return 0;
0049 }
0050 
0051 static int phy_mvebu_sata_power_off(struct phy *phy)
0052 {
0053     struct priv *priv = phy_get_drvdata(phy);
0054     u32 reg;
0055 
0056     clk_prepare_enable(priv->clk);
0057 
0058     /* Disable PLL and IVREF */
0059     reg = readl(priv->base + SATA_PHY_MODE_2);
0060     reg &= ~(MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
0061          MODE_2_PU_PLL | MODE_2_PU_IVREF);
0062     writel(reg, priv->base + SATA_PHY_MODE_2);
0063 
0064     /* Disable PHY */
0065     reg = readl(priv->base + SATA_IF_CTRL);
0066     reg |= CTRL_PHY_SHUTDOWN;
0067     writel(reg, priv->base + SATA_IF_CTRL);
0068 
0069     clk_disable_unprepare(priv->clk);
0070 
0071     return 0;
0072 }
0073 
0074 static const struct phy_ops phy_mvebu_sata_ops = {
0075     .power_on   = phy_mvebu_sata_power_on,
0076     .power_off  = phy_mvebu_sata_power_off,
0077     .owner      = THIS_MODULE,
0078 };
0079 
0080 static int phy_mvebu_sata_probe(struct platform_device *pdev)
0081 {
0082     struct phy_provider *phy_provider;
0083     struct priv *priv;
0084     struct phy *phy;
0085 
0086     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0087     if (!priv)
0088         return -ENOMEM;
0089 
0090     priv->base = devm_platform_ioremap_resource(pdev, 0);
0091     if (IS_ERR(priv->base))
0092         return PTR_ERR(priv->base);
0093 
0094     priv->clk = devm_clk_get(&pdev->dev, "sata");
0095     if (IS_ERR(priv->clk))
0096         return PTR_ERR(priv->clk);
0097 
0098     phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);
0099     if (IS_ERR(phy))
0100         return PTR_ERR(phy);
0101 
0102     phy_set_drvdata(phy, priv);
0103 
0104     phy_provider = devm_of_phy_provider_register(&pdev->dev,
0105                              of_phy_simple_xlate);
0106     if (IS_ERR(phy_provider))
0107         return PTR_ERR(phy_provider);
0108 
0109     /* The boot loader may of left it on. Turn it off. */
0110     phy_mvebu_sata_power_off(phy);
0111 
0112     return 0;
0113 }
0114 
0115 static const struct of_device_id phy_mvebu_sata_of_match[] = {
0116     { .compatible = "marvell,mvebu-sata-phy" },
0117     { },
0118 };
0119 
0120 static struct platform_driver phy_mvebu_sata_driver = {
0121     .probe  = phy_mvebu_sata_probe,
0122     .driver = {
0123         .name   = "phy-mvebu-sata",
0124         .of_match_table = phy_mvebu_sata_of_match,
0125     }
0126 };
0127 builtin_platform_driver(phy_mvebu_sata_driver);