12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20b56e9a7SVivek Gautam /*
30b56e9a7SVivek Gautam * phy-mvebu-sata.c: SATA Phy driver for the Marvell mvebu SoCs.
40b56e9a7SVivek Gautam *
50b56e9a7SVivek Gautam * Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
60b56e9a7SVivek Gautam */
70b56e9a7SVivek Gautam
80b56e9a7SVivek Gautam #include <linux/kernel.h>
9a211034aSPaul Gortmaker #include <linux/init.h>
100b56e9a7SVivek Gautam #include <linux/clk.h>
110b56e9a7SVivek Gautam #include <linux/phy/phy.h>
120b56e9a7SVivek Gautam #include <linux/io.h>
13*7559e757SRob Herring #include <linux/mod_devicetable.h>
140b56e9a7SVivek Gautam #include <linux/platform_device.h>
150b56e9a7SVivek Gautam
160b56e9a7SVivek Gautam struct priv {
170b56e9a7SVivek Gautam struct clk *clk;
180b56e9a7SVivek Gautam void __iomem *base;
190b56e9a7SVivek Gautam };
200b56e9a7SVivek Gautam
210b56e9a7SVivek Gautam #define SATA_PHY_MODE_2 0x0330
220b56e9a7SVivek Gautam #define MODE_2_FORCE_PU_TX BIT(0)
230b56e9a7SVivek Gautam #define MODE_2_FORCE_PU_RX BIT(1)
240b56e9a7SVivek Gautam #define MODE_2_PU_PLL BIT(2)
250b56e9a7SVivek Gautam #define MODE_2_PU_IVREF BIT(3)
260b56e9a7SVivek Gautam #define SATA_IF_CTRL 0x0050
270b56e9a7SVivek Gautam #define CTRL_PHY_SHUTDOWN BIT(9)
280b56e9a7SVivek Gautam
phy_mvebu_sata_power_on(struct phy * phy)290b56e9a7SVivek Gautam static int phy_mvebu_sata_power_on(struct phy *phy)
300b56e9a7SVivek Gautam {
310b56e9a7SVivek Gautam struct priv *priv = phy_get_drvdata(phy);
320b56e9a7SVivek Gautam u32 reg;
330b56e9a7SVivek Gautam
340b56e9a7SVivek Gautam clk_prepare_enable(priv->clk);
350b56e9a7SVivek Gautam
360b56e9a7SVivek Gautam /* Enable PLL and IVREF */
370b56e9a7SVivek Gautam reg = readl(priv->base + SATA_PHY_MODE_2);
380b56e9a7SVivek Gautam reg |= (MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
390b56e9a7SVivek Gautam MODE_2_PU_PLL | MODE_2_PU_IVREF);
400b56e9a7SVivek Gautam writel(reg , priv->base + SATA_PHY_MODE_2);
410b56e9a7SVivek Gautam
420b56e9a7SVivek Gautam /* Enable PHY */
430b56e9a7SVivek Gautam reg = readl(priv->base + SATA_IF_CTRL);
440b56e9a7SVivek Gautam reg &= ~CTRL_PHY_SHUTDOWN;
450b56e9a7SVivek Gautam writel(reg, priv->base + SATA_IF_CTRL);
460b56e9a7SVivek Gautam
470b56e9a7SVivek Gautam clk_disable_unprepare(priv->clk);
480b56e9a7SVivek Gautam
490b56e9a7SVivek Gautam return 0;
500b56e9a7SVivek Gautam }
510b56e9a7SVivek Gautam
phy_mvebu_sata_power_off(struct phy * phy)520b56e9a7SVivek Gautam static int phy_mvebu_sata_power_off(struct phy *phy)
530b56e9a7SVivek Gautam {
540b56e9a7SVivek Gautam struct priv *priv = phy_get_drvdata(phy);
550b56e9a7SVivek Gautam u32 reg;
560b56e9a7SVivek Gautam
570b56e9a7SVivek Gautam clk_prepare_enable(priv->clk);
580b56e9a7SVivek Gautam
590b56e9a7SVivek Gautam /* Disable PLL and IVREF */
600b56e9a7SVivek Gautam reg = readl(priv->base + SATA_PHY_MODE_2);
610b56e9a7SVivek Gautam reg &= ~(MODE_2_FORCE_PU_TX | MODE_2_FORCE_PU_RX |
620b56e9a7SVivek Gautam MODE_2_PU_PLL | MODE_2_PU_IVREF);
630b56e9a7SVivek Gautam writel(reg, priv->base + SATA_PHY_MODE_2);
640b56e9a7SVivek Gautam
650b56e9a7SVivek Gautam /* Disable PHY */
660b56e9a7SVivek Gautam reg = readl(priv->base + SATA_IF_CTRL);
670b56e9a7SVivek Gautam reg |= CTRL_PHY_SHUTDOWN;
680b56e9a7SVivek Gautam writel(reg, priv->base + SATA_IF_CTRL);
690b56e9a7SVivek Gautam
700b56e9a7SVivek Gautam clk_disable_unprepare(priv->clk);
710b56e9a7SVivek Gautam
720b56e9a7SVivek Gautam return 0;
730b56e9a7SVivek Gautam }
740b56e9a7SVivek Gautam
750b56e9a7SVivek Gautam static const struct phy_ops phy_mvebu_sata_ops = {
760b56e9a7SVivek Gautam .power_on = phy_mvebu_sata_power_on,
770b56e9a7SVivek Gautam .power_off = phy_mvebu_sata_power_off,
780b56e9a7SVivek Gautam .owner = THIS_MODULE,
790b56e9a7SVivek Gautam };
800b56e9a7SVivek Gautam
phy_mvebu_sata_probe(struct platform_device * pdev)810b56e9a7SVivek Gautam static int phy_mvebu_sata_probe(struct platform_device *pdev)
820b56e9a7SVivek Gautam {
830b56e9a7SVivek Gautam struct phy_provider *phy_provider;
840b56e9a7SVivek Gautam struct priv *priv;
850b56e9a7SVivek Gautam struct phy *phy;
860b56e9a7SVivek Gautam
870b56e9a7SVivek Gautam priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
880b56e9a7SVivek Gautam if (!priv)
890b56e9a7SVivek Gautam return -ENOMEM;
900b56e9a7SVivek Gautam
91ee55b501SChunfeng Yun priv->base = devm_platform_ioremap_resource(pdev, 0);
920b56e9a7SVivek Gautam if (IS_ERR(priv->base))
930b56e9a7SVivek Gautam return PTR_ERR(priv->base);
940b56e9a7SVivek Gautam
950b56e9a7SVivek Gautam priv->clk = devm_clk_get(&pdev->dev, "sata");
960b56e9a7SVivek Gautam if (IS_ERR(priv->clk))
970b56e9a7SVivek Gautam return PTR_ERR(priv->clk);
980b56e9a7SVivek Gautam
990b56e9a7SVivek Gautam phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);
1000b56e9a7SVivek Gautam if (IS_ERR(phy))
1010b56e9a7SVivek Gautam return PTR_ERR(phy);
1020b56e9a7SVivek Gautam
1030b56e9a7SVivek Gautam phy_set_drvdata(phy, priv);
1040b56e9a7SVivek Gautam
1050b56e9a7SVivek Gautam phy_provider = devm_of_phy_provider_register(&pdev->dev,
1060b56e9a7SVivek Gautam of_phy_simple_xlate);
1070b56e9a7SVivek Gautam if (IS_ERR(phy_provider))
1080b56e9a7SVivek Gautam return PTR_ERR(phy_provider);
1090b56e9a7SVivek Gautam
1100b56e9a7SVivek Gautam /* The boot loader may of left it on. Turn it off. */
1110b56e9a7SVivek Gautam phy_mvebu_sata_power_off(phy);
1120b56e9a7SVivek Gautam
1130b56e9a7SVivek Gautam return 0;
1140b56e9a7SVivek Gautam }
1150b56e9a7SVivek Gautam
1160b56e9a7SVivek Gautam static const struct of_device_id phy_mvebu_sata_of_match[] = {
1170b56e9a7SVivek Gautam { .compatible = "marvell,mvebu-sata-phy" },
1180b56e9a7SVivek Gautam { },
1190b56e9a7SVivek Gautam };
1200b56e9a7SVivek Gautam
1210b56e9a7SVivek Gautam static struct platform_driver phy_mvebu_sata_driver = {
1220b56e9a7SVivek Gautam .probe = phy_mvebu_sata_probe,
1230b56e9a7SVivek Gautam .driver = {
1240b56e9a7SVivek Gautam .name = "phy-mvebu-sata",
1250b56e9a7SVivek Gautam .of_match_table = phy_mvebu_sata_of_match,
1260b56e9a7SVivek Gautam }
1270b56e9a7SVivek Gautam };
128a211034aSPaul Gortmaker builtin_platform_driver(phy_mvebu_sata_driver);
129