1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * phy-mvebu-sata.c: SATA Phy driver for the Marvell mvebu SoCs.
5 * Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/clk.h>
11 #include <linux/phy/phy.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/platform_device.h>
21 #define SATA_PHY_MODE_2 0x0330
22 #define MODE_2_FORCE_PU_TX BIT(0)
23 #define MODE_2_FORCE_PU_RX BIT(1)
24 #define MODE_2_PU_PLL BIT(2)
25 #define MODE_2_PU_IVREF BIT(3)
26 #define SATA_IF_CTRL 0x0050
27 #define CTRL_PHY_SHUTDOWN BIT(9)
29 static int phy_mvebu_sata_power_on(struct phy
*phy
)
31 struct priv
*priv
= phy_get_drvdata(phy
);
34 clk_prepare_enable(priv
->clk
);
36 /* Enable PLL and IVREF */
37 reg
= readl(priv
->base
+ SATA_PHY_MODE_2
);
38 reg
|= (MODE_2_FORCE_PU_TX
| MODE_2_FORCE_PU_RX
|
39 MODE_2_PU_PLL
| MODE_2_PU_IVREF
);
40 writel(reg
, priv
->base
+ SATA_PHY_MODE_2
);
43 reg
= readl(priv
->base
+ SATA_IF_CTRL
);
44 reg
&= ~CTRL_PHY_SHUTDOWN
;
45 writel(reg
, priv
->base
+ SATA_IF_CTRL
);
47 clk_disable_unprepare(priv
->clk
);
52 static int phy_mvebu_sata_power_off(struct phy
*phy
)
54 struct priv
*priv
= phy_get_drvdata(phy
);
57 clk_prepare_enable(priv
->clk
);
59 /* Disable PLL and IVREF */
60 reg
= readl(priv
->base
+ SATA_PHY_MODE_2
);
61 reg
&= ~(MODE_2_FORCE_PU_TX
| MODE_2_FORCE_PU_RX
|
62 MODE_2_PU_PLL
| MODE_2_PU_IVREF
);
63 writel(reg
, priv
->base
+ SATA_PHY_MODE_2
);
66 reg
= readl(priv
->base
+ SATA_IF_CTRL
);
67 reg
|= CTRL_PHY_SHUTDOWN
;
68 writel(reg
, priv
->base
+ SATA_IF_CTRL
);
70 clk_disable_unprepare(priv
->clk
);
75 static const struct phy_ops phy_mvebu_sata_ops
= {
76 .power_on
= phy_mvebu_sata_power_on
,
77 .power_off
= phy_mvebu_sata_power_off
,
81 static int phy_mvebu_sata_probe(struct platform_device
*pdev
)
83 struct phy_provider
*phy_provider
;
87 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
91 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
92 if (IS_ERR(priv
->base
))
93 return PTR_ERR(priv
->base
);
95 priv
->clk
= devm_clk_get(&pdev
->dev
, "sata");
96 if (IS_ERR(priv
->clk
))
97 return PTR_ERR(priv
->clk
);
99 phy
= devm_phy_create(&pdev
->dev
, NULL
, &phy_mvebu_sata_ops
);
103 phy_set_drvdata(phy
, priv
);
105 phy_provider
= devm_of_phy_provider_register(&pdev
->dev
,
106 of_phy_simple_xlate
);
107 if (IS_ERR(phy_provider
))
108 return PTR_ERR(phy_provider
);
110 /* The boot loader may of left it on. Turn it off. */
111 phy_mvebu_sata_power_off(phy
);
116 static const struct of_device_id phy_mvebu_sata_of_match
[] = {
117 { .compatible
= "marvell,mvebu-sata-phy" },
121 static struct platform_driver phy_mvebu_sata_driver
= {
122 .probe
= phy_mvebu_sata_probe
,
124 .name
= "phy-mvebu-sata",
125 .of_match_table
= phy_mvebu_sata_of_match
,
128 builtin_platform_driver(phy_mvebu_sata_driver
);