linux/drivers/phy/socionext/phy-uniphier-ahci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * phy-uniphier-ahci.c - PHY driver for UniPhier AHCI controller
   4 * Copyright 2016-2020, Socionext Inc.
   5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/bitops.h>
  10#include <linux/clk.h>
  11#include <linux/iopoll.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_platform.h>
  15#include <linux/phy/phy.h>
  16#include <linux/platform_device.h>
  17#include <linux/reset.h>
  18
  19struct uniphier_ahciphy_priv {
  20        struct device *dev;
  21        void __iomem  *base;
  22        struct clk *clk, *clk_parent;
  23        struct reset_control *rst, *rst_parent;
  24        const struct uniphier_ahciphy_soc_data *data;
  25};
  26
  27struct uniphier_ahciphy_soc_data {
  28        int (*init)(struct uniphier_ahciphy_priv *priv);
  29        int (*power_on)(struct uniphier_ahciphy_priv *priv);
  30        int (*power_off)(struct uniphier_ahciphy_priv *priv);
  31        bool is_ready_high;
  32        bool is_phy_clk;
  33};
  34
  35/* for PXs2/PXs3 */
  36#define CKCTRL                          0x0
  37#define CKCTRL_P0_READY                 BIT(15)
  38#define CKCTRL_P0_RESET                 BIT(10)
  39#define CKCTRL_REF_SSP_EN               BIT(9)
  40#define TXCTRL0                         0x4
  41#define TXCTRL0_AMP_G3_MASK             GENMASK(22, 16)
  42#define TXCTRL0_AMP_G2_MASK             GENMASK(14, 8)
  43#define TXCTRL0_AMP_G1_MASK             GENMASK(6, 0)
  44#define TXCTRL1                         0x8
  45#define TXCTRL1_DEEMPH_G3_MASK          GENMASK(21, 16)
  46#define TXCTRL1_DEEMPH_G2_MASK          GENMASK(13, 8)
  47#define TXCTRL1_DEEMPH_G1_MASK          GENMASK(5, 0)
  48#define RXCTRL                          0xc
  49#define RXCTRL_LOS_LVL_MASK             GENMASK(20, 16)
  50#define RXCTRL_LOS_BIAS_MASK            GENMASK(10, 8)
  51#define RXCTRL_RX_EQ_MASK               GENMASK(2, 0)
  52
  53static void uniphier_ahciphy_pxs2_enable(struct uniphier_ahciphy_priv *priv,
  54                                         bool enable)
  55{
  56        u32 val;
  57
  58        val = readl(priv->base + CKCTRL);
  59
  60        if (enable) {
  61                val |= CKCTRL_REF_SSP_EN;
  62                writel(val, priv->base + CKCTRL);
  63                val &= ~CKCTRL_P0_RESET;
  64                writel(val, priv->base + CKCTRL);
  65        } else {
  66                val |= CKCTRL_P0_RESET;
  67                writel(val, priv->base + CKCTRL);
  68                val &= ~CKCTRL_REF_SSP_EN;
  69                writel(val, priv->base + CKCTRL);
  70        }
  71}
  72
  73static int uniphier_ahciphy_pxs2_power_on(struct uniphier_ahciphy_priv *priv)
  74{
  75        int ret;
  76        u32 val;
  77
  78        uniphier_ahciphy_pxs2_enable(priv, true);
  79
  80        /* wait until PLL is ready */
  81        if (priv->data->is_ready_high)
  82                ret = readl_poll_timeout(priv->base + CKCTRL, val,
  83                                         (val & CKCTRL_P0_READY), 200, 400);
  84        else
  85                ret = readl_poll_timeout(priv->base + CKCTRL, val,
  86                                         !(val & CKCTRL_P0_READY), 200, 400);
  87        if (ret) {
  88                dev_err(priv->dev, "Failed to check whether PHY PLL is ready\n");
  89                uniphier_ahciphy_pxs2_enable(priv, false);
  90        }
  91
  92        return ret;
  93}
  94
  95static int uniphier_ahciphy_pxs2_power_off(struct uniphier_ahciphy_priv *priv)
  96{
  97        uniphier_ahciphy_pxs2_enable(priv, false);
  98
  99        return 0;
 100}
 101
 102static int uniphier_ahciphy_pxs3_init(struct uniphier_ahciphy_priv *priv)
 103{
 104        int i;
 105        u32 val;
 106
 107        /* setup port parameter */
 108        val = readl(priv->base + TXCTRL0);
 109        val &= ~TXCTRL0_AMP_G3_MASK;
 110        val |= FIELD_PREP(TXCTRL0_AMP_G3_MASK, 0x73);
 111        val &= ~TXCTRL0_AMP_G2_MASK;
 112        val |= FIELD_PREP(TXCTRL0_AMP_G2_MASK, 0x46);
 113        val &= ~TXCTRL0_AMP_G1_MASK;
 114        val |= FIELD_PREP(TXCTRL0_AMP_G1_MASK, 0x42);
 115        writel(val, priv->base + TXCTRL0);
 116
 117        val = readl(priv->base + TXCTRL1);
 118        val &= ~TXCTRL1_DEEMPH_G3_MASK;
 119        val |= FIELD_PREP(TXCTRL1_DEEMPH_G3_MASK, 0x23);
 120        val &= ~TXCTRL1_DEEMPH_G2_MASK;
 121        val |= FIELD_PREP(TXCTRL1_DEEMPH_G2_MASK, 0x05);
 122        val &= ~TXCTRL1_DEEMPH_G1_MASK;
 123        val |= FIELD_PREP(TXCTRL1_DEEMPH_G1_MASK, 0x05);
 124
 125        val = readl(priv->base + RXCTRL);
 126        val &= ~RXCTRL_LOS_LVL_MASK;
 127        val |= FIELD_PREP(RXCTRL_LOS_LVL_MASK, 0x9);
 128        val &= ~RXCTRL_LOS_BIAS_MASK;
 129        val |= FIELD_PREP(RXCTRL_LOS_BIAS_MASK, 0x2);
 130        val &= ~RXCTRL_RX_EQ_MASK;
 131        val |= FIELD_PREP(RXCTRL_RX_EQ_MASK, 0x1);
 132
 133        /* dummy read 25 times to make a wait time for the phy to stabilize */
 134        for (i = 0; i < 25; i++)
 135                readl(priv->base + CKCTRL);
 136
 137        return 0;
 138}
 139
 140static int uniphier_ahciphy_init(struct phy *phy)
 141{
 142        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 143        int ret;
 144
 145        ret = clk_prepare_enable(priv->clk_parent);
 146        if (ret)
 147                return ret;
 148
 149        ret = reset_control_deassert(priv->rst_parent);
 150        if (ret)
 151                goto out_clk_disable;
 152
 153        if (priv->data->init) {
 154                ret = priv->data->init(priv);
 155                if (ret)
 156                        goto out_rst_assert;
 157        }
 158
 159        return 0;
 160
 161out_rst_assert:
 162        reset_control_assert(priv->rst_parent);
 163out_clk_disable:
 164        clk_disable_unprepare(priv->clk_parent);
 165
 166        return ret;
 167}
 168
 169static int uniphier_ahciphy_exit(struct phy *phy)
 170{
 171        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 172
 173        reset_control_assert(priv->rst_parent);
 174        clk_disable_unprepare(priv->clk_parent);
 175
 176        return 0;
 177}
 178
 179static int uniphier_ahciphy_power_on(struct phy *phy)
 180{
 181        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 182        int ret = 0;
 183
 184        ret = clk_prepare_enable(priv->clk);
 185        if (ret)
 186                return ret;
 187
 188        ret = reset_control_deassert(priv->rst);
 189        if (ret)
 190                goto out_clk_disable;
 191
 192        if (priv->data->power_on) {
 193                ret = priv->data->power_on(priv);
 194                if (ret)
 195                        goto out_reset_assert;
 196        }
 197
 198        return 0;
 199
 200out_reset_assert:
 201        reset_control_assert(priv->rst);
 202out_clk_disable:
 203        clk_disable_unprepare(priv->clk);
 204
 205        return ret;
 206}
 207
 208static int uniphier_ahciphy_power_off(struct phy *phy)
 209{
 210        struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy);
 211        int ret = 0;
 212
 213        if (priv->data->power_off)
 214                ret = priv->data->power_off(priv);
 215
 216        reset_control_assert(priv->rst);
 217        clk_disable_unprepare(priv->clk);
 218
 219        return ret;
 220}
 221
 222static const struct phy_ops uniphier_ahciphy_ops = {
 223        .init  = uniphier_ahciphy_init,
 224        .exit  = uniphier_ahciphy_exit,
 225        .power_on  = uniphier_ahciphy_power_on,
 226        .power_off = uniphier_ahciphy_power_off,
 227        .owner = THIS_MODULE,
 228};
 229
 230static int uniphier_ahciphy_probe(struct platform_device *pdev)
 231{
 232        struct device *dev = &pdev->dev;
 233        struct uniphier_ahciphy_priv *priv;
 234        struct phy *phy;
 235        struct phy_provider *phy_provider;
 236
 237        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 238        if (!priv)
 239                return -ENOMEM;
 240
 241        priv->dev = dev;
 242        priv->data = of_device_get_match_data(dev);
 243        if (WARN_ON(!priv->data))
 244                return -EINVAL;
 245
 246        priv->base = devm_platform_ioremap_resource(pdev, 0);
 247        if (IS_ERR(priv->base))
 248                return PTR_ERR(priv->base);
 249
 250        priv->clk_parent = devm_clk_get(dev, "link");
 251        if (IS_ERR(priv->clk_parent))
 252                return PTR_ERR(priv->clk_parent);
 253
 254        if (priv->data->is_phy_clk) {
 255                priv->clk = devm_clk_get(dev, "phy");
 256                if (IS_ERR(priv->clk))
 257                        return PTR_ERR(priv->clk);
 258        }
 259
 260        priv->rst_parent = devm_reset_control_get_shared(dev, "link");
 261        if (IS_ERR(priv->rst_parent))
 262                return PTR_ERR(priv->rst_parent);
 263
 264        priv->rst = devm_reset_control_get_shared(dev, "phy");
 265        if (IS_ERR(priv->rst))
 266                return PTR_ERR(priv->rst);
 267
 268        phy = devm_phy_create(dev, dev->of_node, &uniphier_ahciphy_ops);
 269        if (IS_ERR(phy)) {
 270                dev_err(dev, "failed to create phy\n");
 271                return PTR_ERR(phy);
 272        }
 273
 274        phy_set_drvdata(phy, priv);
 275        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 276        if (IS_ERR(phy_provider))
 277                return PTR_ERR(phy_provider);
 278
 279        return 0;
 280}
 281
 282static const struct uniphier_ahciphy_soc_data uniphier_pxs2_data = {
 283        .power_on  = uniphier_ahciphy_pxs2_power_on,
 284        .power_off = uniphier_ahciphy_pxs2_power_off,
 285        .is_ready_high = false,
 286        .is_phy_clk = false,
 287};
 288
 289static const struct uniphier_ahciphy_soc_data uniphier_pxs3_data = {
 290        .init      = uniphier_ahciphy_pxs3_init,
 291        .power_on  = uniphier_ahciphy_pxs2_power_on,
 292        .power_off = uniphier_ahciphy_pxs2_power_off,
 293        .is_ready_high = true,
 294        .is_phy_clk = true,
 295};
 296
 297static const struct of_device_id uniphier_ahciphy_match[] = {
 298        {
 299                .compatible = "socionext,uniphier-pxs2-ahci-phy",
 300                .data = &uniphier_pxs2_data,
 301        },
 302        {
 303                .compatible = "socionext,uniphier-pxs3-ahci-phy",
 304                .data = &uniphier_pxs3_data,
 305        },
 306        { /* Sentinel */ },
 307};
 308MODULE_DEVICE_TABLE(of, uniphier_ahciphy_match);
 309
 310static struct platform_driver uniphier_ahciphy_driver = {
 311        .probe = uniphier_ahciphy_probe,
 312        .driver = {
 313                .name = "uniphier-ahci-phy",
 314                .of_match_table = uniphier_ahciphy_match,
 315        },
 316};
 317module_platform_driver(uniphier_ahciphy_driver);
 318
 319MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
 320MODULE_DESCRIPTION("UniPhier PHY driver for AHCI controller");
 321MODULE_LICENSE("GPL v2");
 322