linux/drivers/phy/ti/phy-am654-serdes.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/**
   3 * PCIe SERDES driver for AM654x SoC
   4 *
   5 * Copyright (C) 2018 - 2019 Texas Instruments Incorporated - http://www.ti.com/
   6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
   7 */
   8
   9#include <dt-bindings/phy/phy.h>
  10#include <linux/clk.h>
  11#include <linux/clk-provider.h>
  12#include <linux/delay.h>
  13#include <linux/module.h>
  14#include <linux/mfd/syscon.h>
  15#include <linux/mux/consumer.h>
  16#include <linux/of_address.h>
  17#include <linux/phy/phy.h>
  18#include <linux/platform_device.h>
  19#include <linux/pm_runtime.h>
  20#include <linux/regmap.h>
  21
  22#define CMU_R07C                0x7c
  23
  24#define COMLANE_R138            0xb38
  25#define VERSION                 0x70
  26
  27#define COMLANE_R190            0xb90
  28
  29#define COMLANE_R194            0xb94
  30
  31#define SERDES_CTRL             0x1fd0
  32
  33#define WIZ_LANEXCTL_STS        0x1fe0
  34#define TX0_DISABLE_STATE       0x4
  35#define TX0_SLEEP_STATE         0x5
  36#define TX0_SNOOZE_STATE        0x6
  37#define TX0_ENABLE_STATE        0x7
  38
  39#define RX0_DISABLE_STATE       0x4
  40#define RX0_SLEEP_STATE         0x5
  41#define RX0_SNOOZE_STATE        0x6
  42#define RX0_ENABLE_STATE        0x7
  43
  44#define WIZ_PLL_CTRL            0x1ff4
  45#define PLL_DISABLE_STATE       0x4
  46#define PLL_SLEEP_STATE         0x5
  47#define PLL_SNOOZE_STATE        0x6
  48#define PLL_ENABLE_STATE        0x7
  49
  50#define PLL_LOCK_TIME           100000  /* in microseconds */
  51#define SLEEP_TIME              100     /* in microseconds */
  52
  53#define LANE_USB3               0x0
  54#define LANE_PCIE0_LANE0        0x1
  55
  56#define LANE_PCIE1_LANE0        0x0
  57#define LANE_PCIE0_LANE1        0x1
  58
  59#define SERDES_NUM_CLOCKS       3
  60
  61#define AM654_SERDES_CTRL_CLKSEL_MASK   GENMASK(7, 4)
  62#define AM654_SERDES_CTRL_CLKSEL_SHIFT  4
  63
  64struct serdes_am654_clk_mux {
  65        struct clk_hw   hw;
  66        struct regmap   *regmap;
  67        unsigned int    reg;
  68        int             clk_id;
  69        struct clk_init_data clk_data;
  70};
  71
  72#define to_serdes_am654_clk_mux(_hw)    \
  73                container_of(_hw, struct serdes_am654_clk_mux, hw)
  74
  75static const struct regmap_config serdes_am654_regmap_config = {
  76        .reg_bits = 32,
  77        .val_bits = 32,
  78        .reg_stride = 4,
  79        .fast_io = true,
  80        .max_register = 0x1ffc,
  81};
  82
  83static const struct reg_field cmu_master_cdn_o = REG_FIELD(CMU_R07C, 24, 24);
  84static const struct reg_field config_version = REG_FIELD(COMLANE_R138, 16, 23);
  85static const struct reg_field l1_master_cdn_o = REG_FIELD(COMLANE_R190, 9, 9);
  86static const struct reg_field cmu_ok_i_0 = REG_FIELD(COMLANE_R194, 19, 19);
  87static const struct reg_field por_en = REG_FIELD(SERDES_CTRL, 29, 29);
  88static const struct reg_field tx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 29, 31);
  89static const struct reg_field rx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 13, 15);
  90static const struct reg_field pll_enable = REG_FIELD(WIZ_PLL_CTRL, 29, 31);
  91static const struct reg_field pll_ok = REG_FIELD(WIZ_PLL_CTRL, 28, 28);
  92
  93struct serdes_am654 {
  94        struct regmap           *regmap;
  95        struct regmap_field     *cmu_master_cdn_o;
  96        struct regmap_field     *config_version;
  97        struct regmap_field     *l1_master_cdn_o;
  98        struct regmap_field     *cmu_ok_i_0;
  99        struct regmap_field     *por_en;
 100        struct regmap_field     *tx0_enable;
 101        struct regmap_field     *rx0_enable;
 102        struct regmap_field     *pll_enable;
 103        struct regmap_field     *pll_ok;
 104
 105        struct device           *dev;
 106        struct mux_control      *control;
 107        bool                    busy;
 108        u32                     type;
 109        struct device_node      *of_node;
 110        struct clk_onecell_data clk_data;
 111        struct clk              *clks[SERDES_NUM_CLOCKS];
 112};
 113
 114static int serdes_am654_enable_pll(struct serdes_am654 *phy)
 115{
 116        int ret;
 117        u32 val;
 118
 119        ret = regmap_field_write(phy->pll_enable, PLL_ENABLE_STATE);
 120        if (ret)
 121                return ret;
 122
 123        return regmap_field_read_poll_timeout(phy->pll_ok, val, val, 1000,
 124                                              PLL_LOCK_TIME);
 125}
 126
 127static void serdes_am654_disable_pll(struct serdes_am654 *phy)
 128{
 129        struct device *dev = phy->dev;
 130        int ret;
 131
 132        ret = regmap_field_write(phy->pll_enable, PLL_DISABLE_STATE);
 133        if (ret)
 134                dev_err(dev, "Failed to disable PLL\n");
 135}
 136
 137static int serdes_am654_enable_txrx(struct serdes_am654 *phy)
 138{
 139        int ret;
 140
 141        /* Enable TX */
 142        ret = regmap_field_write(phy->tx0_enable, TX0_ENABLE_STATE);
 143        if (ret)
 144                return ret;
 145
 146        /* Enable RX */
 147        ret = regmap_field_write(phy->rx0_enable, RX0_ENABLE_STATE);
 148        if (ret)
 149                return ret;
 150
 151        return 0;
 152}
 153
 154static int serdes_am654_disable_txrx(struct serdes_am654 *phy)
 155{
 156        int ret;
 157
 158        /* Disable TX */
 159        ret = regmap_field_write(phy->tx0_enable, TX0_DISABLE_STATE);
 160        if (ret)
 161                return ret;
 162
 163        /* Disable RX */
 164        ret = regmap_field_write(phy->rx0_enable, RX0_DISABLE_STATE);
 165        if (ret)
 166                return ret;
 167
 168        return 0;
 169}
 170
 171static int serdes_am654_power_on(struct phy *x)
 172{
 173        struct serdes_am654 *phy = phy_get_drvdata(x);
 174        struct device *dev = phy->dev;
 175        int ret;
 176        u32 val;
 177
 178        ret = serdes_am654_enable_pll(phy);
 179        if (ret) {
 180                dev_err(dev, "Failed to enable PLL\n");
 181                return ret;
 182        }
 183
 184        ret = serdes_am654_enable_txrx(phy);
 185        if (ret) {
 186                dev_err(dev, "Failed to enable TX RX\n");
 187                return ret;
 188        }
 189
 190        return regmap_field_read_poll_timeout(phy->cmu_ok_i_0, val, val,
 191                                              SLEEP_TIME, PLL_LOCK_TIME);
 192}
 193
 194static int serdes_am654_power_off(struct phy *x)
 195{
 196        struct serdes_am654 *phy = phy_get_drvdata(x);
 197
 198        serdes_am654_disable_txrx(phy);
 199        serdes_am654_disable_pll(phy);
 200
 201        return 0;
 202}
 203
 204#define SERDES_AM654_CFG(offset, a, b, val) \
 205        regmap_update_bits(phy->regmap, (offset),\
 206                           GENMASK((a), (b)), (val) << (b))
 207
 208static int serdes_am654_usb3_init(struct serdes_am654 *phy)
 209{
 210        SERDES_AM654_CFG(0x0000, 31, 24, 0x17);
 211        SERDES_AM654_CFG(0x0004, 15, 8, 0x02);
 212        SERDES_AM654_CFG(0x0004, 7, 0, 0x0e);
 213        SERDES_AM654_CFG(0x0008, 23, 16, 0x2e);
 214        SERDES_AM654_CFG(0x0008, 31, 24, 0x2e);
 215        SERDES_AM654_CFG(0x0060, 7, 0, 0x4b);
 216        SERDES_AM654_CFG(0x0060, 15, 8, 0x98);
 217        SERDES_AM654_CFG(0x0060, 23, 16, 0x60);
 218        SERDES_AM654_CFG(0x00d0, 31, 24, 0x45);
 219        SERDES_AM654_CFG(0x00e8, 15, 8, 0x0e);
 220        SERDES_AM654_CFG(0x0220, 7, 0, 0x34);
 221        SERDES_AM654_CFG(0x0220, 15, 8, 0x34);
 222        SERDES_AM654_CFG(0x0220, 31, 24, 0x37);
 223        SERDES_AM654_CFG(0x0224, 7, 0, 0x37);
 224        SERDES_AM654_CFG(0x0224, 15, 8, 0x37);
 225        SERDES_AM654_CFG(0x0228, 23, 16, 0x37);
 226        SERDES_AM654_CFG(0x0228, 31, 24, 0x37);
 227        SERDES_AM654_CFG(0x022c, 7, 0, 0x37);
 228        SERDES_AM654_CFG(0x022c, 15, 8, 0x37);
 229        SERDES_AM654_CFG(0x0230, 15, 8, 0x2a);
 230        SERDES_AM654_CFG(0x0230, 23, 16, 0x2a);
 231        SERDES_AM654_CFG(0x0240, 23, 16, 0x10);
 232        SERDES_AM654_CFG(0x0240, 31, 24, 0x34);
 233        SERDES_AM654_CFG(0x0244, 7, 0, 0x40);
 234        SERDES_AM654_CFG(0x0244, 23, 16, 0x34);
 235        SERDES_AM654_CFG(0x0248, 15, 8, 0x0d);
 236        SERDES_AM654_CFG(0x0258, 15, 8, 0x16);
 237        SERDES_AM654_CFG(0x0258, 23, 16, 0x84);
 238        SERDES_AM654_CFG(0x0258, 31, 24, 0xf2);
 239        SERDES_AM654_CFG(0x025c, 7, 0, 0x21);
 240        SERDES_AM654_CFG(0x0260, 7, 0, 0x27);
 241        SERDES_AM654_CFG(0x0260, 15, 8, 0x04);
 242        SERDES_AM654_CFG(0x0268, 15, 8, 0x04);
 243        SERDES_AM654_CFG(0x0288, 15, 8, 0x2c);
 244        SERDES_AM654_CFG(0x0330, 31, 24, 0xa0);
 245        SERDES_AM654_CFG(0x0338, 23, 16, 0x03);
 246        SERDES_AM654_CFG(0x0338, 31, 24, 0x00);
 247        SERDES_AM654_CFG(0x033c, 7, 0, 0x00);
 248        SERDES_AM654_CFG(0x0344, 31, 24, 0x18);
 249        SERDES_AM654_CFG(0x034c, 7, 0, 0x18);
 250        SERDES_AM654_CFG(0x039c, 23, 16, 0x3b);
 251        SERDES_AM654_CFG(0x0a04, 7, 0, 0x03);
 252        SERDES_AM654_CFG(0x0a14, 31, 24, 0x3c);
 253        SERDES_AM654_CFG(0x0a18, 15, 8, 0x3c);
 254        SERDES_AM654_CFG(0x0a38, 7, 0, 0x3e);
 255        SERDES_AM654_CFG(0x0a38, 15, 8, 0x3e);
 256        SERDES_AM654_CFG(0x0ae0, 7, 0, 0x07);
 257        SERDES_AM654_CFG(0x0b6c, 23, 16, 0xcd);
 258        SERDES_AM654_CFG(0x0b6c, 31, 24, 0x04);
 259        SERDES_AM654_CFG(0x0b98, 23, 16, 0x03);
 260        SERDES_AM654_CFG(0x1400, 7, 0, 0x3f);
 261        SERDES_AM654_CFG(0x1404, 23, 16, 0x6f);
 262        SERDES_AM654_CFG(0x1404, 31, 24, 0x6f);
 263        SERDES_AM654_CFG(0x140c, 7, 0, 0x6f);
 264        SERDES_AM654_CFG(0x140c, 15, 8, 0x6f);
 265        SERDES_AM654_CFG(0x1410, 15, 8, 0x27);
 266        SERDES_AM654_CFG(0x1414, 7, 0, 0x0c);
 267        SERDES_AM654_CFG(0x1414, 23, 16, 0x07);
 268        SERDES_AM654_CFG(0x1418, 23, 16, 0x40);
 269        SERDES_AM654_CFG(0x141c, 7, 0, 0x00);
 270        SERDES_AM654_CFG(0x141c, 15, 8, 0x1f);
 271        SERDES_AM654_CFG(0x1428, 31, 24, 0x08);
 272        SERDES_AM654_CFG(0x1434, 31, 24, 0x00);
 273        SERDES_AM654_CFG(0x1444, 7, 0, 0x94);
 274        SERDES_AM654_CFG(0x1460, 31, 24, 0x7f);
 275        SERDES_AM654_CFG(0x1464, 7, 0, 0x43);
 276        SERDES_AM654_CFG(0x1464, 23, 16, 0x6f);
 277        SERDES_AM654_CFG(0x1464, 31, 24, 0x43);
 278        SERDES_AM654_CFG(0x1484, 23, 16, 0x8f);
 279        SERDES_AM654_CFG(0x1498, 7, 0, 0x4f);
 280        SERDES_AM654_CFG(0x1498, 23, 16, 0x4f);
 281        SERDES_AM654_CFG(0x007c, 31, 24, 0x0d);
 282        SERDES_AM654_CFG(0x0b90, 15, 8, 0x0f);
 283
 284        return 0;
 285}
 286
 287static int serdes_am654_pcie_init(struct serdes_am654 *phy)
 288{
 289        int ret;
 290
 291        ret = regmap_field_write(phy->config_version, VERSION);
 292        if (ret)
 293                return ret;
 294
 295        ret = regmap_field_write(phy->cmu_master_cdn_o, 0x1);
 296        if (ret)
 297                return ret;
 298
 299        ret = regmap_field_write(phy->l1_master_cdn_o, 0x1);
 300        if (ret)
 301                return ret;
 302
 303        return 0;
 304}
 305
 306static int serdes_am654_init(struct phy *x)
 307{
 308        struct serdes_am654 *phy = phy_get_drvdata(x);
 309
 310        switch (phy->type) {
 311        case PHY_TYPE_PCIE:
 312                return serdes_am654_pcie_init(phy);
 313        case PHY_TYPE_USB3:
 314                return serdes_am654_usb3_init(phy);
 315        default:
 316                return -EINVAL;
 317        }
 318}
 319
 320static int serdes_am654_reset(struct phy *x)
 321{
 322        struct serdes_am654 *phy = phy_get_drvdata(x);
 323        int ret;
 324
 325        serdes_am654_disable_pll(phy);
 326        serdes_am654_disable_txrx(phy);
 327
 328        ret = regmap_field_write(phy->por_en, 0x1);
 329        if (ret)
 330                return ret;
 331
 332        mdelay(1);
 333
 334        ret = regmap_field_write(phy->por_en, 0x0);
 335        if (ret)
 336                return ret;
 337
 338        return 0;
 339}
 340
 341static void serdes_am654_release(struct phy *x)
 342{
 343        struct serdes_am654 *phy = phy_get_drvdata(x);
 344
 345        phy->type = PHY_NONE;
 346        phy->busy = false;
 347        mux_control_deselect(phy->control);
 348}
 349
 350static struct phy *serdes_am654_xlate(struct device *dev,
 351                                      struct of_phandle_args *args)
 352{
 353        struct serdes_am654 *am654_phy;
 354        struct phy *phy;
 355        int ret;
 356
 357        phy = of_phy_simple_xlate(dev, args);
 358        if (IS_ERR(phy))
 359                return phy;
 360
 361        am654_phy = phy_get_drvdata(phy);
 362        if (am654_phy->busy)
 363                return ERR_PTR(-EBUSY);
 364
 365        ret = mux_control_select(am654_phy->control, args->args[1]);
 366        if (ret) {
 367                dev_err(dev, "Failed to select SERDES Lane Function\n");
 368                return ERR_PTR(ret);
 369        }
 370
 371        am654_phy->busy = true;
 372        am654_phy->type = args->args[0];
 373
 374        return phy;
 375}
 376
 377static const struct phy_ops ops = {
 378        .reset          = serdes_am654_reset,
 379        .init           = serdes_am654_init,
 380        .power_on       = serdes_am654_power_on,
 381        .power_off      = serdes_am654_power_off,
 382        .release        = serdes_am654_release,
 383        .owner          = THIS_MODULE,
 384};
 385
 386#define SERDES_NUM_MUX_COMBINATIONS 16
 387
 388#define LICLK 0
 389#define EXT_REFCLK 1
 390#define RICLK 2
 391
 392static const int
 393serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = {
 394        /*
 395         * Each combination maps to one of
 396         * "Figure 12-1986. SerDes Reference Clock Distribution"
 397         * in TRM.
 398         */
 399         /* Parent of CMU refclk, Left output, Right output
 400          * either of EXT_REFCLK, LICLK, RICLK
 401          */
 402        { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */
 403        { RICLK, EXT_REFCLK, EXT_REFCLK },      /* 0001 */
 404        { EXT_REFCLK, RICLK, LICLK },           /* 0010 */
 405        { RICLK, RICLK, EXT_REFCLK },           /* 0011 */
 406        { LICLK, EXT_REFCLK, EXT_REFCLK },      /* 0100 */
 407        { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */
 408        { LICLK, RICLK, LICLK },                /* 0110 */
 409        { EXT_REFCLK, RICLK, LICLK },           /* 0111 */
 410        { EXT_REFCLK, EXT_REFCLK, LICLK },      /* 1000 */
 411        { RICLK, EXT_REFCLK, LICLK },           /* 1001 */
 412        { EXT_REFCLK, RICLK, EXT_REFCLK },      /* 1010 */
 413        { RICLK, RICLK, EXT_REFCLK },           /* 1011 */
 414        { LICLK, EXT_REFCLK, LICLK },           /* 1100 */
 415        { EXT_REFCLK, EXT_REFCLK, LICLK },      /* 1101 */
 416        { LICLK, RICLK, EXT_REFCLK },           /* 1110 */
 417        { EXT_REFCLK, RICLK, EXT_REFCLK },      /* 1111 */
 418};
 419
 420static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw)
 421{
 422        struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
 423        struct regmap *regmap = mux->regmap;
 424        unsigned int reg = mux->reg;
 425        unsigned int val;
 426
 427        regmap_read(regmap, reg, &val);
 428        val &= AM654_SERDES_CTRL_CLKSEL_MASK;
 429        val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 430
 431        return serdes_am654_mux_table[val][mux->clk_id];
 432}
 433
 434static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index)
 435{
 436        struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
 437        struct regmap *regmap = mux->regmap;
 438        const char *name = clk_hw_get_name(hw);
 439        unsigned int reg = mux->reg;
 440        int clk_id = mux->clk_id;
 441        int parents[SERDES_NUM_CLOCKS];
 442        const int *p;
 443        u32 val;
 444        int found, i;
 445        int ret;
 446
 447        /* get existing setting */
 448        regmap_read(regmap, reg, &val);
 449        val &= AM654_SERDES_CTRL_CLKSEL_MASK;
 450        val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 451
 452        for (i = 0; i < SERDES_NUM_CLOCKS; i++)
 453                parents[i] = serdes_am654_mux_table[val][i];
 454
 455        /* change parent of this clock. others left intact */
 456        parents[clk_id] = index;
 457
 458        /* Find the match */
 459        for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) {
 460                p = serdes_am654_mux_table[val];
 461                found = 1;
 462                for (i = 0; i < SERDES_NUM_CLOCKS; i++) {
 463                        if (parents[i] != p[i]) {
 464                                found = 0;
 465                                break;
 466                        }
 467                }
 468
 469                if (found)
 470                        break;
 471        }
 472
 473        if (!found) {
 474                /*
 475                 * This can never happen, unless we missed
 476                 * a valid combination in serdes_am654_mux_table.
 477                 */
 478                WARN(1, "Failed to find the parent of %s clock\n", name);
 479                return -EINVAL;
 480        }
 481
 482        val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 483        ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK,
 484                                 val);
 485
 486        return ret;
 487}
 488
 489static const struct clk_ops serdes_am654_clk_mux_ops = {
 490        .set_parent = serdes_am654_clk_mux_set_parent,
 491        .get_parent = serdes_am654_clk_mux_get_parent,
 492};
 493
 494static int serdes_am654_clk_register(struct serdes_am654 *am654_phy,
 495                                     const char *clock_name, int clock_num)
 496{
 497        struct device_node *node = am654_phy->of_node;
 498        struct device *dev = am654_phy->dev;
 499        struct serdes_am654_clk_mux *mux;
 500        struct device_node *regmap_node;
 501        const char **parent_names;
 502        struct clk_init_data *init;
 503        unsigned int num_parents;
 504        struct regmap *regmap;
 505        const __be32 *addr;
 506        unsigned int reg;
 507        struct clk *clk;
 508        int ret = 0;
 509
 510        mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
 511        if (!mux)
 512                return -ENOMEM;
 513
 514        init = &mux->clk_data;
 515
 516        regmap_node = of_parse_phandle(node, "ti,serdes-clk", 0);
 517        if (!regmap_node) {
 518                dev_err(dev, "Fail to get serdes-clk node\n");
 519                ret = -ENODEV;
 520                goto out_put_node;
 521        }
 522
 523        regmap = syscon_node_to_regmap(regmap_node->parent);
 524        if (IS_ERR(regmap)) {
 525                dev_err(dev, "Fail to get Syscon regmap\n");
 526                ret = PTR_ERR(regmap);
 527                goto out_put_node;
 528        }
 529
 530        num_parents = of_clk_get_parent_count(node);
 531        if (num_parents < 2) {
 532                dev_err(dev, "SERDES clock must have parents\n");
 533                ret = -EINVAL;
 534                goto out_put_node;
 535        }
 536
 537        parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents),
 538                                    GFP_KERNEL);
 539        if (!parent_names) {
 540                ret = -ENOMEM;
 541                goto out_put_node;
 542        }
 543
 544        of_clk_parent_fill(node, parent_names, num_parents);
 545
 546        addr = of_get_address(regmap_node, 0, NULL, NULL);
 547        if (!addr) {
 548                ret = -EINVAL;
 549                goto out_put_node;
 550        }
 551
 552        reg = be32_to_cpu(*addr);
 553
 554        init->ops = &serdes_am654_clk_mux_ops;
 555        init->flags = CLK_SET_RATE_NO_REPARENT;
 556        init->parent_names = parent_names;
 557        init->num_parents = num_parents;
 558        init->name = clock_name;
 559
 560        mux->regmap = regmap;
 561        mux->reg = reg;
 562        mux->clk_id = clock_num;
 563        mux->hw.init = init;
 564
 565        clk = devm_clk_register(dev, &mux->hw);
 566        if (IS_ERR(clk)) {
 567                ret = PTR_ERR(clk);
 568                goto out_put_node;
 569        }
 570
 571        am654_phy->clks[clock_num] = clk;
 572
 573out_put_node:
 574        of_node_put(regmap_node);
 575        return ret;
 576}
 577
 578static const struct of_device_id serdes_am654_id_table[] = {
 579        {
 580                .compatible = "ti,phy-am654-serdes",
 581        },
 582        {}
 583};
 584MODULE_DEVICE_TABLE(of, serdes_am654_id_table);
 585
 586static int serdes_am654_regfield_init(struct serdes_am654 *am654_phy)
 587{
 588        struct regmap *regmap = am654_phy->regmap;
 589        struct device *dev = am654_phy->dev;
 590
 591        am654_phy->cmu_master_cdn_o = devm_regmap_field_alloc(dev, regmap,
 592                                                              cmu_master_cdn_o);
 593        if (IS_ERR(am654_phy->cmu_master_cdn_o)) {
 594                dev_err(dev, "CMU_MASTER_CDN_O reg field init failed\n");
 595                return PTR_ERR(am654_phy->cmu_master_cdn_o);
 596        }
 597
 598        am654_phy->config_version = devm_regmap_field_alloc(dev, regmap,
 599                                                            config_version);
 600        if (IS_ERR(am654_phy->config_version)) {
 601                dev_err(dev, "CONFIG_VERSION reg field init failed\n");
 602                return PTR_ERR(am654_phy->config_version);
 603        }
 604
 605        am654_phy->l1_master_cdn_o = devm_regmap_field_alloc(dev, regmap,
 606                                                             l1_master_cdn_o);
 607        if (IS_ERR(am654_phy->l1_master_cdn_o)) {
 608                dev_err(dev, "L1_MASTER_CDN_O reg field init failed\n");
 609                return PTR_ERR(am654_phy->l1_master_cdn_o);
 610        }
 611
 612        am654_phy->cmu_ok_i_0 = devm_regmap_field_alloc(dev, regmap,
 613                                                        cmu_ok_i_0);
 614        if (IS_ERR(am654_phy->cmu_ok_i_0)) {
 615                dev_err(dev, "CMU_OK_I_0 reg field init failed\n");
 616                return PTR_ERR(am654_phy->cmu_ok_i_0);
 617        }
 618
 619        am654_phy->por_en = devm_regmap_field_alloc(dev, regmap, por_en);
 620        if (IS_ERR(am654_phy->por_en)) {
 621                dev_err(dev, "POR_EN reg field init failed\n");
 622                return PTR_ERR(am654_phy->por_en);
 623        }
 624
 625        am654_phy->tx0_enable = devm_regmap_field_alloc(dev, regmap,
 626                                                        tx0_enable);
 627        if (IS_ERR(am654_phy->tx0_enable)) {
 628                dev_err(dev, "TX0_ENABLE reg field init failed\n");
 629                return PTR_ERR(am654_phy->tx0_enable);
 630        }
 631
 632        am654_phy->rx0_enable = devm_regmap_field_alloc(dev, regmap,
 633                                                        rx0_enable);
 634        if (IS_ERR(am654_phy->rx0_enable)) {
 635                dev_err(dev, "RX0_ENABLE reg field init failed\n");
 636                return PTR_ERR(am654_phy->rx0_enable);
 637        }
 638
 639        am654_phy->pll_enable = devm_regmap_field_alloc(dev, regmap,
 640                                                        pll_enable);
 641        if (IS_ERR(am654_phy->pll_enable)) {
 642                dev_err(dev, "PLL_ENABLE reg field init failed\n");
 643                return PTR_ERR(am654_phy->pll_enable);
 644        }
 645
 646        am654_phy->pll_ok = devm_regmap_field_alloc(dev, regmap, pll_ok);
 647        if (IS_ERR(am654_phy->pll_ok)) {
 648                dev_err(dev, "PLL_OK reg field init failed\n");
 649                return PTR_ERR(am654_phy->pll_ok);
 650        }
 651
 652        return 0;
 653}
 654
 655static int serdes_am654_probe(struct platform_device *pdev)
 656{
 657        struct phy_provider *phy_provider;
 658        struct device *dev = &pdev->dev;
 659        struct device_node *node = dev->of_node;
 660        struct clk_onecell_data *clk_data;
 661        struct serdes_am654 *am654_phy;
 662        struct mux_control *control;
 663        const char *clock_name;
 664        struct regmap *regmap;
 665        void __iomem *base;
 666        struct phy *phy;
 667        int ret;
 668        int i;
 669
 670        am654_phy = devm_kzalloc(dev, sizeof(*am654_phy), GFP_KERNEL);
 671        if (!am654_phy)
 672                return -ENOMEM;
 673
 674        base = devm_platform_ioremap_resource(pdev, 0);
 675        if (IS_ERR(base))
 676                return PTR_ERR(base);
 677
 678        regmap = devm_regmap_init_mmio(dev, base, &serdes_am654_regmap_config);
 679        if (IS_ERR(regmap)) {
 680                dev_err(dev, "Failed to initialize regmap\n");
 681                return PTR_ERR(regmap);
 682        }
 683
 684        control = devm_mux_control_get(dev, NULL);
 685        if (IS_ERR(control))
 686                return PTR_ERR(control);
 687
 688        am654_phy->dev = dev;
 689        am654_phy->of_node = node;
 690        am654_phy->regmap = regmap;
 691        am654_phy->control = control;
 692        am654_phy->type = PHY_NONE;
 693
 694        ret = serdes_am654_regfield_init(am654_phy);
 695        if (ret) {
 696                dev_err(dev, "Failed to initialize regfields\n");
 697                return ret;
 698        }
 699
 700        platform_set_drvdata(pdev, am654_phy);
 701
 702        for (i = 0; i < SERDES_NUM_CLOCKS; i++) {
 703                ret = of_property_read_string_index(node, "clock-output-names",
 704                                                    i, &clock_name);
 705                if (ret) {
 706                        dev_err(dev, "Failed to get clock name\n");
 707                        return ret;
 708                }
 709
 710                ret = serdes_am654_clk_register(am654_phy, clock_name, i);
 711                if (ret) {
 712                        dev_err(dev, "Failed to initialize clock %s\n",
 713                                clock_name);
 714                        return ret;
 715                }
 716        }
 717
 718        clk_data = &am654_phy->clk_data;
 719        clk_data->clks = am654_phy->clks;
 720        clk_data->clk_num = SERDES_NUM_CLOCKS;
 721        ret = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 722        if (ret)
 723                return ret;
 724
 725        pm_runtime_enable(dev);
 726
 727        phy = devm_phy_create(dev, NULL, &ops);
 728        if (IS_ERR(phy)) {
 729                ret = PTR_ERR(phy);
 730                goto clk_err;
 731        }
 732
 733        phy_set_drvdata(phy, am654_phy);
 734        phy_provider = devm_of_phy_provider_register(dev, serdes_am654_xlate);
 735        if (IS_ERR(phy_provider)) {
 736                ret = PTR_ERR(phy_provider);
 737                goto clk_err;
 738        }
 739
 740        return 0;
 741
 742clk_err:
 743        of_clk_del_provider(node);
 744
 745        return ret;
 746}
 747
 748static int serdes_am654_remove(struct platform_device *pdev)
 749{
 750        struct serdes_am654 *am654_phy = platform_get_drvdata(pdev);
 751        struct device_node *node = am654_phy->of_node;
 752
 753        pm_runtime_disable(&pdev->dev);
 754        of_clk_del_provider(node);
 755
 756        return 0;
 757}
 758
 759static struct platform_driver serdes_am654_driver = {
 760        .probe          = serdes_am654_probe,
 761        .remove         = serdes_am654_remove,
 762        .driver         = {
 763                .name   = "phy-am654",
 764                .of_match_table = serdes_am654_id_table,
 765        },
 766};
 767module_platform_driver(serdes_am654_driver);
 768
 769MODULE_AUTHOR("Texas Instruments Inc.");
 770MODULE_DESCRIPTION("TI AM654x SERDES driver");
 771MODULE_LICENSE("GPL v2");
 772