root/drivers/phy/ti/phy-am654-serdes.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. serdes_am654_enable_pll
  2. serdes_am654_disable_pll
  3. serdes_am654_enable_txrx
  4. serdes_am654_disable_txrx
  5. serdes_am654_power_on
  6. serdes_am654_power_off
  7. serdes_am654_init
  8. serdes_am654_reset
  9. serdes_am654_release
  10. serdes_am654_xlate
  11. serdes_am654_clk_mux_get_parent
  12. serdes_am654_clk_mux_set_parent
  13. serdes_am654_clk_register
  14. serdes_am654_regfield_init
  15. serdes_am654_probe
  16. serdes_am654_remove

   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 
  64 struct 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 
  75 static struct regmap_config serdes_am654_regmap_config = {
  76         .reg_bits = 32,
  77         .val_bits = 32,
  78         .reg_stride = 4,
  79         .fast_io = true,
  80 };
  81 
  82 static const struct reg_field cmu_master_cdn_o = REG_FIELD(CMU_R07C, 24, 24);
  83 static const struct reg_field config_version = REG_FIELD(COMLANE_R138, 16, 23);
  84 static const struct reg_field l1_master_cdn_o = REG_FIELD(COMLANE_R190, 9, 9);
  85 static const struct reg_field cmu_ok_i_0 = REG_FIELD(COMLANE_R194, 19, 19);
  86 static const struct reg_field por_en = REG_FIELD(SERDES_CTRL, 29, 29);
  87 static const struct reg_field tx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 29, 31);
  88 static const struct reg_field rx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 13, 15);
  89 static const struct reg_field pll_enable = REG_FIELD(WIZ_PLL_CTRL, 29, 31);
  90 static const struct reg_field pll_ok = REG_FIELD(WIZ_PLL_CTRL, 28, 28);
  91 
  92 struct serdes_am654 {
  93         struct regmap           *regmap;
  94         struct regmap_field     *cmu_master_cdn_o;
  95         struct regmap_field     *config_version;
  96         struct regmap_field     *l1_master_cdn_o;
  97         struct regmap_field     *cmu_ok_i_0;
  98         struct regmap_field     *por_en;
  99         struct regmap_field     *tx0_enable;
 100         struct regmap_field     *rx0_enable;
 101         struct regmap_field     *pll_enable;
 102         struct regmap_field     *pll_ok;
 103 
 104         struct device           *dev;
 105         struct mux_control      *control;
 106         bool                    busy;
 107         u32                     type;
 108         struct device_node      *of_node;
 109         struct clk_onecell_data clk_data;
 110         struct clk              *clks[SERDES_NUM_CLOCKS];
 111 };
 112 
 113 static int serdes_am654_enable_pll(struct serdes_am654 *phy)
 114 {
 115         int ret;
 116         u32 val;
 117 
 118         ret = regmap_field_write(phy->pll_enable, PLL_ENABLE_STATE);
 119         if (ret)
 120                 return ret;
 121 
 122         return regmap_field_read_poll_timeout(phy->pll_ok, val, val, 1000,
 123                                               PLL_LOCK_TIME);
 124 }
 125 
 126 static void serdes_am654_disable_pll(struct serdes_am654 *phy)
 127 {
 128         struct device *dev = phy->dev;
 129         int ret;
 130 
 131         ret = regmap_field_write(phy->pll_enable, PLL_DISABLE_STATE);
 132         if (ret)
 133                 dev_err(dev, "Failed to disable PLL\n");
 134 }
 135 
 136 static int serdes_am654_enable_txrx(struct serdes_am654 *phy)
 137 {
 138         int ret;
 139 
 140         /* Enable TX */
 141         ret = regmap_field_write(phy->tx0_enable, TX0_ENABLE_STATE);
 142         if (ret)
 143                 return ret;
 144 
 145         /* Enable RX */
 146         ret = regmap_field_write(phy->rx0_enable, RX0_ENABLE_STATE);
 147         if (ret)
 148                 return ret;
 149 
 150         return 0;
 151 }
 152 
 153 static int serdes_am654_disable_txrx(struct serdes_am654 *phy)
 154 {
 155         int ret;
 156 
 157         /* Disable TX */
 158         ret = regmap_field_write(phy->tx0_enable, TX0_DISABLE_STATE);
 159         if (ret)
 160                 return ret;
 161 
 162         /* Disable RX */
 163         ret = regmap_field_write(phy->rx0_enable, RX0_DISABLE_STATE);
 164         if (ret)
 165                 return ret;
 166 
 167         return 0;
 168 }
 169 
 170 static int serdes_am654_power_on(struct phy *x)
 171 {
 172         struct serdes_am654 *phy = phy_get_drvdata(x);
 173         struct device *dev = phy->dev;
 174         int ret;
 175         u32 val;
 176 
 177         ret = serdes_am654_enable_pll(phy);
 178         if (ret) {
 179                 dev_err(dev, "Failed to enable PLL\n");
 180                 return ret;
 181         }
 182 
 183         ret = serdes_am654_enable_txrx(phy);
 184         if (ret) {
 185                 dev_err(dev, "Failed to enable TX RX\n");
 186                 return ret;
 187         }
 188 
 189         return regmap_field_read_poll_timeout(phy->cmu_ok_i_0, val, val,
 190                                               SLEEP_TIME, PLL_LOCK_TIME);
 191 }
 192 
 193 static int serdes_am654_power_off(struct phy *x)
 194 {
 195         struct serdes_am654 *phy = phy_get_drvdata(x);
 196 
 197         serdes_am654_disable_txrx(phy);
 198         serdes_am654_disable_pll(phy);
 199 
 200         return 0;
 201 }
 202 
 203 static int serdes_am654_init(struct phy *x)
 204 {
 205         struct serdes_am654 *phy = phy_get_drvdata(x);
 206         int ret;
 207 
 208         ret = regmap_field_write(phy->config_version, VERSION);
 209         if (ret)
 210                 return ret;
 211 
 212         ret = regmap_field_write(phy->cmu_master_cdn_o, 0x1);
 213         if (ret)
 214                 return ret;
 215 
 216         ret = regmap_field_write(phy->l1_master_cdn_o, 0x1);
 217         if (ret)
 218                 return ret;
 219 
 220         return 0;
 221 }
 222 
 223 static int serdes_am654_reset(struct phy *x)
 224 {
 225         struct serdes_am654 *phy = phy_get_drvdata(x);
 226         int ret;
 227 
 228         ret = regmap_field_write(phy->por_en, 0x1);
 229         if (ret)
 230                 return ret;
 231 
 232         mdelay(1);
 233 
 234         ret = regmap_field_write(phy->por_en, 0x0);
 235         if (ret)
 236                 return ret;
 237 
 238         return 0;
 239 }
 240 
 241 static void serdes_am654_release(struct phy *x)
 242 {
 243         struct serdes_am654 *phy = phy_get_drvdata(x);
 244 
 245         phy->type = PHY_NONE;
 246         phy->busy = false;
 247         mux_control_deselect(phy->control);
 248 }
 249 
 250 static struct phy *serdes_am654_xlate(struct device *dev,
 251                                       struct of_phandle_args *args)
 252 {
 253         struct serdes_am654 *am654_phy;
 254         struct phy *phy;
 255         int ret;
 256 
 257         phy = of_phy_simple_xlate(dev, args);
 258         if (IS_ERR(phy))
 259                 return phy;
 260 
 261         am654_phy = phy_get_drvdata(phy);
 262         if (am654_phy->busy)
 263                 return ERR_PTR(-EBUSY);
 264 
 265         ret = mux_control_select(am654_phy->control, args->args[1]);
 266         if (ret) {
 267                 dev_err(dev, "Failed to select SERDES Lane Function\n");
 268                 return ERR_PTR(ret);
 269         }
 270 
 271         am654_phy->busy = true;
 272         am654_phy->type = args->args[0];
 273 
 274         return phy;
 275 }
 276 
 277 static const struct phy_ops ops = {
 278         .reset          = serdes_am654_reset,
 279         .init           = serdes_am654_init,
 280         .power_on       = serdes_am654_power_on,
 281         .power_off      = serdes_am654_power_off,
 282         .release        = serdes_am654_release,
 283         .owner          = THIS_MODULE,
 284 };
 285 
 286 #define SERDES_NUM_MUX_COMBINATIONS 16
 287 
 288 #define LICLK 0
 289 #define EXT_REFCLK 1
 290 #define RICLK 2
 291 
 292 static const int
 293 serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = {
 294         /*
 295          * Each combination maps to one of
 296          * "Figure 12-1986. SerDes Reference Clock Distribution"
 297          * in TRM.
 298          */
 299          /* Parent of CMU refclk, Left output, Right output
 300           * either of EXT_REFCLK, LICLK, RICLK
 301           */
 302         { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */
 303         { RICLK, EXT_REFCLK, EXT_REFCLK },      /* 0001 */
 304         { EXT_REFCLK, RICLK, LICLK },           /* 0010 */
 305         { RICLK, RICLK, EXT_REFCLK },           /* 0011 */
 306         { LICLK, EXT_REFCLK, EXT_REFCLK },      /* 0100 */
 307         { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */
 308         { LICLK, RICLK, LICLK },                /* 0110 */
 309         { EXT_REFCLK, RICLK, LICLK },           /* 0111 */
 310         { EXT_REFCLK, EXT_REFCLK, LICLK },      /* 1000 */
 311         { RICLK, EXT_REFCLK, LICLK },           /* 1001 */
 312         { EXT_REFCLK, RICLK, EXT_REFCLK },      /* 1010 */
 313         { RICLK, RICLK, EXT_REFCLK },           /* 1011 */
 314         { LICLK, EXT_REFCLK, LICLK },           /* 1100 */
 315         { EXT_REFCLK, EXT_REFCLK, LICLK },      /* 1101 */
 316         { LICLK, RICLK, EXT_REFCLK },           /* 1110 */
 317         { EXT_REFCLK, RICLK, EXT_REFCLK },      /* 1111 */
 318 };
 319 
 320 static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw)
 321 {
 322         struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
 323         struct regmap *regmap = mux->regmap;
 324         unsigned int reg = mux->reg;
 325         unsigned int val;
 326 
 327         regmap_read(regmap, reg, &val);
 328         val &= AM654_SERDES_CTRL_CLKSEL_MASK;
 329         val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 330 
 331         return serdes_am654_mux_table[val][mux->clk_id];
 332 }
 333 
 334 static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index)
 335 {
 336         struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw);
 337         struct regmap *regmap = mux->regmap;
 338         const char *name = clk_hw_get_name(hw);
 339         unsigned int reg = mux->reg;
 340         int clk_id = mux->clk_id;
 341         int parents[SERDES_NUM_CLOCKS];
 342         const int *p;
 343         u32 val;
 344         int found, i;
 345         int ret;
 346 
 347         /* get existing setting */
 348         regmap_read(regmap, reg, &val);
 349         val &= AM654_SERDES_CTRL_CLKSEL_MASK;
 350         val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 351 
 352         for (i = 0; i < SERDES_NUM_CLOCKS; i++)
 353                 parents[i] = serdes_am654_mux_table[val][i];
 354 
 355         /* change parent of this clock. others left intact */
 356         parents[clk_id] = index;
 357 
 358         /* Find the match */
 359         for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) {
 360                 p = serdes_am654_mux_table[val];
 361                 found = 1;
 362                 for (i = 0; i < SERDES_NUM_CLOCKS; i++) {
 363                         if (parents[i] != p[i]) {
 364                                 found = 0;
 365                                 break;
 366                         }
 367                 }
 368 
 369                 if (found)
 370                         break;
 371         }
 372 
 373         if (!found) {
 374                 /*
 375                  * This can never happen, unless we missed
 376                  * a valid combination in serdes_am654_mux_table.
 377                  */
 378                 WARN(1, "Failed to find the parent of %s clock\n", name);
 379                 return -EINVAL;
 380         }
 381 
 382         val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT;
 383         ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK,
 384                                  val);
 385 
 386         return ret;
 387 }
 388 
 389 static const struct clk_ops serdes_am654_clk_mux_ops = {
 390         .set_parent = serdes_am654_clk_mux_set_parent,
 391         .get_parent = serdes_am654_clk_mux_get_parent,
 392 };
 393 
 394 static int serdes_am654_clk_register(struct serdes_am654 *am654_phy,
 395                                      const char *clock_name, int clock_num)
 396 {
 397         struct device_node *node = am654_phy->of_node;
 398         struct device *dev = am654_phy->dev;
 399         struct serdes_am654_clk_mux *mux;
 400         struct device_node *regmap_node;
 401         const char **parent_names;
 402         struct clk_init_data *init;
 403         unsigned int num_parents;
 404         struct regmap *regmap;
 405         const __be32 *addr;
 406         unsigned int reg;
 407         struct clk *clk;
 408         int ret = 0;
 409 
 410         mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
 411         if (!mux)
 412                 return -ENOMEM;
 413 
 414         init = &mux->clk_data;
 415 
 416         regmap_node = of_parse_phandle(node, "ti,serdes-clk", 0);
 417         if (!regmap_node) {
 418                 dev_err(dev, "Fail to get serdes-clk node\n");
 419                 ret = -ENODEV;
 420                 goto out_put_node;
 421         }
 422 
 423         regmap = syscon_node_to_regmap(regmap_node->parent);
 424         if (IS_ERR(regmap)) {
 425                 dev_err(dev, "Fail to get Syscon regmap\n");
 426                 ret = PTR_ERR(regmap);
 427                 goto out_put_node;
 428         }
 429 
 430         num_parents = of_clk_get_parent_count(node);
 431         if (num_parents < 2) {
 432                 dev_err(dev, "SERDES clock must have parents\n");
 433                 ret = -EINVAL;
 434                 goto out_put_node;
 435         }
 436 
 437         parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents),
 438                                     GFP_KERNEL);
 439         if (!parent_names) {
 440                 ret = -ENOMEM;
 441                 goto out_put_node;
 442         }
 443 
 444         of_clk_parent_fill(node, parent_names, num_parents);
 445 
 446         addr = of_get_address(regmap_node, 0, NULL, NULL);
 447         if (!addr) {
 448                 ret = -EINVAL;
 449                 goto out_put_node;
 450         }
 451 
 452         reg = be32_to_cpu(*addr);
 453 
 454         init->ops = &serdes_am654_clk_mux_ops;
 455         init->flags = CLK_SET_RATE_NO_REPARENT;
 456         init->parent_names = parent_names;
 457         init->num_parents = num_parents;
 458         init->name = clock_name;
 459 
 460         mux->regmap = regmap;
 461         mux->reg = reg;
 462         mux->clk_id = clock_num;
 463         mux->hw.init = init;
 464 
 465         clk = devm_clk_register(dev, &mux->hw);
 466         if (IS_ERR(clk)) {
 467                 ret = PTR_ERR(clk);
 468                 goto out_put_node;
 469         }
 470 
 471         am654_phy->clks[clock_num] = clk;
 472 
 473 out_put_node:
 474         of_node_put(regmap_node);
 475         return ret;
 476 }
 477 
 478 static const struct of_device_id serdes_am654_id_table[] = {
 479         {
 480                 .compatible = "ti,phy-am654-serdes",
 481         },
 482         {}
 483 };
 484 MODULE_DEVICE_TABLE(of, serdes_am654_id_table);
 485 
 486 static int serdes_am654_regfield_init(struct serdes_am654 *am654_phy)
 487 {
 488         struct regmap *regmap = am654_phy->regmap;
 489         struct device *dev = am654_phy->dev;
 490 
 491         am654_phy->cmu_master_cdn_o = devm_regmap_field_alloc(dev, regmap,
 492                                                               cmu_master_cdn_o);
 493         if (IS_ERR(am654_phy->cmu_master_cdn_o)) {
 494                 dev_err(dev, "CMU_MASTER_CDN_O reg field init failed\n");
 495                 return PTR_ERR(am654_phy->cmu_master_cdn_o);
 496         }
 497 
 498         am654_phy->config_version = devm_regmap_field_alloc(dev, regmap,
 499                                                             config_version);
 500         if (IS_ERR(am654_phy->config_version)) {
 501                 dev_err(dev, "CONFIG_VERSION reg field init failed\n");
 502                 return PTR_ERR(am654_phy->config_version);
 503         }
 504 
 505         am654_phy->l1_master_cdn_o = devm_regmap_field_alloc(dev, regmap,
 506                                                              l1_master_cdn_o);
 507         if (IS_ERR(am654_phy->l1_master_cdn_o)) {
 508                 dev_err(dev, "L1_MASTER_CDN_O reg field init failed\n");
 509                 return PTR_ERR(am654_phy->l1_master_cdn_o);
 510         }
 511 
 512         am654_phy->cmu_ok_i_0 = devm_regmap_field_alloc(dev, regmap,
 513                                                         cmu_ok_i_0);
 514         if (IS_ERR(am654_phy->cmu_ok_i_0)) {
 515                 dev_err(dev, "CMU_OK_I_0 reg field init failed\n");
 516                 return PTR_ERR(am654_phy->cmu_ok_i_0);
 517         }
 518 
 519         am654_phy->por_en = devm_regmap_field_alloc(dev, regmap, por_en);
 520         if (IS_ERR(am654_phy->por_en)) {
 521                 dev_err(dev, "POR_EN reg field init failed\n");
 522                 return PTR_ERR(am654_phy->por_en);
 523         }
 524 
 525         am654_phy->tx0_enable = devm_regmap_field_alloc(dev, regmap,
 526                                                         tx0_enable);
 527         if (IS_ERR(am654_phy->tx0_enable)) {
 528                 dev_err(dev, "TX0_ENABLE reg field init failed\n");
 529                 return PTR_ERR(am654_phy->tx0_enable);
 530         }
 531 
 532         am654_phy->rx0_enable = devm_regmap_field_alloc(dev, regmap,
 533                                                         rx0_enable);
 534         if (IS_ERR(am654_phy->rx0_enable)) {
 535                 dev_err(dev, "RX0_ENABLE reg field init failed\n");
 536                 return PTR_ERR(am654_phy->rx0_enable);
 537         }
 538 
 539         am654_phy->pll_enable = devm_regmap_field_alloc(dev, regmap,
 540                                                         pll_enable);
 541         if (IS_ERR(am654_phy->pll_enable)) {
 542                 dev_err(dev, "PLL_ENABLE reg field init failed\n");
 543                 return PTR_ERR(am654_phy->pll_enable);
 544         }
 545 
 546         am654_phy->pll_ok = devm_regmap_field_alloc(dev, regmap, pll_ok);
 547         if (IS_ERR(am654_phy->pll_ok)) {
 548                 dev_err(dev, "PLL_OK reg field init failed\n");
 549                 return PTR_ERR(am654_phy->pll_ok);
 550         }
 551 
 552         return 0;
 553 }
 554 
 555 static int serdes_am654_probe(struct platform_device *pdev)
 556 {
 557         struct phy_provider *phy_provider;
 558         struct device *dev = &pdev->dev;
 559         struct device_node *node = dev->of_node;
 560         struct clk_onecell_data *clk_data;
 561         struct serdes_am654 *am654_phy;
 562         struct mux_control *control;
 563         const char *clock_name;
 564         struct regmap *regmap;
 565         void __iomem *base;
 566         struct phy *phy;
 567         int ret;
 568         int i;
 569 
 570         am654_phy = devm_kzalloc(dev, sizeof(*am654_phy), GFP_KERNEL);
 571         if (!am654_phy)
 572                 return -ENOMEM;
 573 
 574         base = devm_platform_ioremap_resource(pdev, 0);
 575         if (IS_ERR(base))
 576                 return PTR_ERR(base);
 577 
 578         regmap = devm_regmap_init_mmio(dev, base, &serdes_am654_regmap_config);
 579         if (IS_ERR(regmap)) {
 580                 dev_err(dev, "Failed to initialize regmap\n");
 581                 return PTR_ERR(regmap);
 582         }
 583 
 584         control = devm_mux_control_get(dev, NULL);
 585         if (IS_ERR(control))
 586                 return PTR_ERR(control);
 587 
 588         am654_phy->dev = dev;
 589         am654_phy->of_node = node;
 590         am654_phy->regmap = regmap;
 591         am654_phy->control = control;
 592         am654_phy->type = PHY_NONE;
 593 
 594         ret = serdes_am654_regfield_init(am654_phy);
 595         if (ret) {
 596                 dev_err(dev, "Failed to initialize regfields\n");
 597                 return ret;
 598         }
 599 
 600         platform_set_drvdata(pdev, am654_phy);
 601 
 602         for (i = 0; i < SERDES_NUM_CLOCKS; i++) {
 603                 ret = of_property_read_string_index(node, "clock-output-names",
 604                                                     i, &clock_name);
 605                 if (ret) {
 606                         dev_err(dev, "Failed to get clock name\n");
 607                         return ret;
 608                 }
 609 
 610                 ret = serdes_am654_clk_register(am654_phy, clock_name, i);
 611                 if (ret) {
 612                         dev_err(dev, "Failed to initialize clock %s\n",
 613                                 clock_name);
 614                         return ret;
 615                 }
 616         }
 617 
 618         clk_data = &am654_phy->clk_data;
 619         clk_data->clks = am654_phy->clks;
 620         clk_data->clk_num = SERDES_NUM_CLOCKS;
 621         ret = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 622         if (ret)
 623                 return ret;
 624 
 625         pm_runtime_enable(dev);
 626 
 627         phy = devm_phy_create(dev, NULL, &ops);
 628         if (IS_ERR(phy))
 629                 return PTR_ERR(phy);
 630 
 631         phy_set_drvdata(phy, am654_phy);
 632         phy_provider = devm_of_phy_provider_register(dev, serdes_am654_xlate);
 633         if (IS_ERR(phy_provider)) {
 634                 ret = PTR_ERR(phy_provider);
 635                 goto clk_err;
 636         }
 637 
 638         return 0;
 639 
 640 clk_err:
 641         of_clk_del_provider(node);
 642 
 643         return ret;
 644 }
 645 
 646 static int serdes_am654_remove(struct platform_device *pdev)
 647 {
 648         struct serdes_am654 *am654_phy = platform_get_drvdata(pdev);
 649         struct device_node *node = am654_phy->of_node;
 650 
 651         pm_runtime_disable(&pdev->dev);
 652         of_clk_del_provider(node);
 653 
 654         return 0;
 655 }
 656 
 657 static struct platform_driver serdes_am654_driver = {
 658         .probe          = serdes_am654_probe,
 659         .remove         = serdes_am654_remove,
 660         .driver         = {
 661                 .name   = "phy-am654",
 662                 .of_match_table = serdes_am654_id_table,
 663         },
 664 };
 665 module_platform_driver(serdes_am654_driver);
 666 
 667 MODULE_AUTHOR("Texas Instruments Inc.");
 668 MODULE_DESCRIPTION("TI AM654x SERDES driver");
 669 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */