xref: /openbmc/linux/drivers/phy/marvell/phy-mvebu-sata.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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