129 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * phy-mvebu-sata.c: SATA Phy driver for the Marvell mvebu SoCs.4 *5 * Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>6 */7 8#include <linux/kernel.h>9#include <linux/init.h>10#include <linux/clk.h>11#include <linux/phy/phy.h>12#include <linux/io.h>13#include <linux/mod_devicetable.h>14#include <linux/platform_device.h>15 16struct priv {17 struct clk *clk;18 void __iomem *base;19};20 21#define SATA_PHY_MODE_2 0x033022#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 0x005027#define CTRL_PHY_SHUTDOWN BIT(9)28 29static int phy_mvebu_sata_power_on(struct phy *phy)30{31 struct priv *priv = phy_get_drvdata(phy);32 u32 reg;33 34 clk_prepare_enable(priv->clk);35 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);41 42 /* Enable PHY */43 reg = readl(priv->base + SATA_IF_CTRL);44 reg &= ~CTRL_PHY_SHUTDOWN;45 writel(reg, priv->base + SATA_IF_CTRL);46 47 clk_disable_unprepare(priv->clk);48 49 return 0;50}51 52static int phy_mvebu_sata_power_off(struct phy *phy)53{54 struct priv *priv = phy_get_drvdata(phy);55 u32 reg;56 57 clk_prepare_enable(priv->clk);58 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);64 65 /* Disable PHY */66 reg = readl(priv->base + SATA_IF_CTRL);67 reg |= CTRL_PHY_SHUTDOWN;68 writel(reg, priv->base + SATA_IF_CTRL);69 70 clk_disable_unprepare(priv->clk);71 72 return 0;73}74 75static const struct phy_ops phy_mvebu_sata_ops = {76 .power_on = phy_mvebu_sata_power_on,77 .power_off = phy_mvebu_sata_power_off,78 .owner = THIS_MODULE,79};80 81static int phy_mvebu_sata_probe(struct platform_device *pdev)82{83 struct phy_provider *phy_provider;84 struct priv *priv;85 struct phy *phy;86 87 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);88 if (!priv)89 return -ENOMEM;90 91 priv->base = devm_platform_ioremap_resource(pdev, 0);92 if (IS_ERR(priv->base))93 return PTR_ERR(priv->base);94 95 priv->clk = devm_clk_get(&pdev->dev, "sata");96 if (IS_ERR(priv->clk))97 return PTR_ERR(priv->clk);98 99 phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);100 if (IS_ERR(phy))101 return PTR_ERR(phy);102 103 phy_set_drvdata(phy, priv);104 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);109 110 /* The boot loader may of left it on. Turn it off. */111 phy_mvebu_sata_power_off(phy);112 113 return 0;114}115 116static const struct of_device_id phy_mvebu_sata_of_match[] = {117 { .compatible = "marvell,mvebu-sata-phy" },118 { },119};120 121static struct platform_driver phy_mvebu_sata_driver = {122 .probe = phy_mvebu_sata_probe,123 .driver = {124 .name = "phy-mvebu-sata",125 .of_match_table = phy_mvebu_sata_of_match,126 }127};128builtin_platform_driver(phy_mvebu_sata_driver);129