phy-ocelot-serdes.c (14895B)
1// SPDX-License-Identifier: (GPL-2.0 OR MIT) 2/* 3 * SerDes PHY driver for Microsemi Ocelot 4 * 5 * Copyright (c) 2018 Microsemi 6 * 7 */ 8 9#include <linux/err.h> 10#include <linux/mfd/syscon.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/of_platform.h> 14#include <linux/phy.h> 15#include <linux/phy/phy.h> 16#include <linux/platform_device.h> 17#include <linux/regmap.h> 18#include <soc/mscc/ocelot_hsio.h> 19#include <dt-bindings/phy/phy-ocelot-serdes.h> 20 21struct serdes_ctrl { 22 struct regmap *regs; 23 struct device *dev; 24 struct phy *phys[SERDES_MAX]; 25}; 26 27struct serdes_macro { 28 u8 idx; 29 /* Not used when in QSGMII or PCIe mode */ 30 int port; 31 struct serdes_ctrl *ctrl; 32}; 33 34#define MCB_S6G_CFG_TIMEOUT 50 35 36static int __serdes_write_mcb_s6g(struct regmap *regmap, u8 macro, u32 op) 37{ 38 unsigned int regval = 0; 39 40 regmap_write(regmap, HSIO_MCB_S6G_ADDR_CFG, op | 41 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(BIT(macro))); 42 43 return regmap_read_poll_timeout(regmap, HSIO_MCB_S6G_ADDR_CFG, regval, 44 (regval & op) != op, 100, 45 MCB_S6G_CFG_TIMEOUT * 1000); 46} 47 48static int serdes_commit_mcb_s6g(struct regmap *regmap, u8 macro) 49{ 50 return __serdes_write_mcb_s6g(regmap, macro, 51 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT); 52} 53 54static int serdes_update_mcb_s6g(struct regmap *regmap, u8 macro) 55{ 56 return __serdes_write_mcb_s6g(regmap, macro, 57 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT); 58} 59 60static int serdes_init_s6g(struct regmap *regmap, u8 serdes, int mode) 61{ 62 u32 pll_fsm_ctrl_data; 63 u32 ob_ena1v_mode; 64 u32 des_bw_ana; 65 u32 ob_ena_cas; 66 u32 if_mode; 67 u32 ob_lev; 68 u32 qrate; 69 int ret; 70 71 if (mode == PHY_INTERFACE_MODE_QSGMII) { 72 pll_fsm_ctrl_data = 120; 73 ob_ena1v_mode = 0; 74 ob_ena_cas = 0; 75 des_bw_ana = 5; 76 ob_lev = 24; 77 if_mode = 3; 78 qrate = 0; 79 } else { 80 pll_fsm_ctrl_data = 60; 81 ob_ena1v_mode = 1; 82 ob_ena_cas = 2; 83 des_bw_ana = 3; 84 ob_lev = 48; 85 if_mode = 1; 86 qrate = 1; 87 } 88 89 ret = serdes_update_mcb_s6g(regmap, serdes); 90 if (ret) 91 return ret; 92 93 /* Test pattern */ 94 95 regmap_update_bits(regmap, HSIO_S6G_COMMON_CFG, 96 HSIO_S6G_COMMON_CFG_SYS_RST, 0); 97 98 regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, 99 HSIO_S6G_PLL_CFG_PLL_FSM_ENA, 0); 100 101 regmap_update_bits(regmap, HSIO_S6G_IB_CFG, 102 HSIO_S6G_IB_CFG_IB_SIG_DET_ENA | 103 HSIO_S6G_IB_CFG_IB_REG_ENA | 104 HSIO_S6G_IB_CFG_IB_SAM_ENA | 105 HSIO_S6G_IB_CFG_IB_EQZ_ENA | 106 HSIO_S6G_IB_CFG_IB_CONCUR | 107 HSIO_S6G_IB_CFG_IB_CAL_ENA, 108 HSIO_S6G_IB_CFG_IB_SIG_DET_ENA | 109 HSIO_S6G_IB_CFG_IB_REG_ENA | 110 HSIO_S6G_IB_CFG_IB_SAM_ENA | 111 HSIO_S6G_IB_CFG_IB_EQZ_ENA | 112 HSIO_S6G_IB_CFG_IB_CONCUR); 113 114 regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, 115 HSIO_S6G_IB_CFG1_IB_FRC_OFFSET | 116 HSIO_S6G_IB_CFG1_IB_FRC_LP | 117 HSIO_S6G_IB_CFG1_IB_FRC_MID | 118 HSIO_S6G_IB_CFG1_IB_FRC_HP | 119 HSIO_S6G_IB_CFG1_IB_FILT_OFFSET | 120 HSIO_S6G_IB_CFG1_IB_FILT_LP | 121 HSIO_S6G_IB_CFG1_IB_FILT_MID | 122 HSIO_S6G_IB_CFG1_IB_FILT_HP, 123 HSIO_S6G_IB_CFG1_IB_FILT_OFFSET | 124 HSIO_S6G_IB_CFG1_IB_FILT_HP | 125 HSIO_S6G_IB_CFG1_IB_FILT_LP | 126 HSIO_S6G_IB_CFG1_IB_FILT_MID); 127 128 regmap_update_bits(regmap, HSIO_S6G_IB_CFG2, 129 HSIO_S6G_IB_CFG2_IB_UREG_M, 130 HSIO_S6G_IB_CFG2_IB_UREG(4)); 131 132 regmap_update_bits(regmap, HSIO_S6G_IB_CFG3, 133 HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M | 134 HSIO_S6G_IB_CFG3_IB_INI_LP_M | 135 HSIO_S6G_IB_CFG3_IB_INI_MID_M | 136 HSIO_S6G_IB_CFG3_IB_INI_HP_M, 137 HSIO_S6G_IB_CFG3_IB_INI_OFFSET(31) | 138 HSIO_S6G_IB_CFG3_IB_INI_LP(1) | 139 HSIO_S6G_IB_CFG3_IB_INI_MID(31) | 140 HSIO_S6G_IB_CFG3_IB_INI_HP(0)); 141 142 regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, 143 HSIO_S6G_MISC_CFG_LANE_RST, 144 HSIO_S6G_MISC_CFG_LANE_RST); 145 146 ret = serdes_commit_mcb_s6g(regmap, serdes); 147 if (ret) 148 return ret; 149 150 /* OB + DES + IB + SER CFG */ 151 regmap_update_bits(regmap, HSIO_S6G_OB_CFG, 152 HSIO_S6G_OB_CFG_OB_IDLE | 153 HSIO_S6G_OB_CFG_OB_ENA1V_MODE | 154 HSIO_S6G_OB_CFG_OB_POST0_M | 155 HSIO_S6G_OB_CFG_OB_PREC_M, 156 (ob_ena1v_mode ? HSIO_S6G_OB_CFG_OB_ENA1V_MODE : 0) | 157 HSIO_S6G_OB_CFG_OB_POST0(0) | 158 HSIO_S6G_OB_CFG_OB_PREC(0)); 159 160 regmap_update_bits(regmap, HSIO_S6G_OB_CFG1, 161 HSIO_S6G_OB_CFG1_OB_ENA_CAS_M | 162 HSIO_S6G_OB_CFG1_OB_LEV_M, 163 HSIO_S6G_OB_CFG1_OB_LEV(ob_lev) | 164 HSIO_S6G_OB_CFG1_OB_ENA_CAS(ob_ena_cas)); 165 166 regmap_update_bits(regmap, HSIO_S6G_DES_CFG, 167 HSIO_S6G_DES_CFG_DES_PHS_CTRL_M | 168 HSIO_S6G_DES_CFG_DES_CPMD_SEL_M | 169 HSIO_S6G_DES_CFG_DES_BW_ANA_M, 170 HSIO_S6G_DES_CFG_DES_PHS_CTRL(2) | 171 HSIO_S6G_DES_CFG_DES_CPMD_SEL(0) | 172 HSIO_S6G_DES_CFG_DES_BW_ANA(des_bw_ana)); 173 174 regmap_update_bits(regmap, HSIO_S6G_IB_CFG, 175 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M | 176 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M, 177 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) | 178 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(0)); 179 180 regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, 181 HSIO_S6G_IB_CFG1_IB_TSDET_M, 182 HSIO_S6G_IB_CFG1_IB_TSDET(16)); 183 184 regmap_update_bits(regmap, HSIO_S6G_SER_CFG, 185 HSIO_S6G_SER_CFG_SER_ALISEL_M | 186 HSIO_S6G_SER_CFG_SER_ENALI, 187 HSIO_S6G_SER_CFG_SER_ALISEL(0)); 188 189 regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, 190 HSIO_S6G_PLL_CFG_PLL_DIV4 | 191 HSIO_S6G_PLL_CFG_PLL_ENA_ROT | 192 HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M | 193 HSIO_S6G_PLL_CFG_PLL_ROT_DIR | 194 HSIO_S6G_PLL_CFG_PLL_ROT_FRQ, 195 HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA 196 (pll_fsm_ctrl_data)); 197 198 regmap_update_bits(regmap, HSIO_S6G_COMMON_CFG, 199 HSIO_S6G_COMMON_CFG_SYS_RST | 200 HSIO_S6G_COMMON_CFG_ENA_LANE | 201 HSIO_S6G_COMMON_CFG_PWD_RX | 202 HSIO_S6G_COMMON_CFG_PWD_TX | 203 HSIO_S6G_COMMON_CFG_HRATE | 204 HSIO_S6G_COMMON_CFG_QRATE | 205 HSIO_S6G_COMMON_CFG_ENA_ELOOP | 206 HSIO_S6G_COMMON_CFG_ENA_FLOOP | 207 HSIO_S6G_COMMON_CFG_IF_MODE_M, 208 HSIO_S6G_COMMON_CFG_SYS_RST | 209 HSIO_S6G_COMMON_CFG_ENA_LANE | 210 (qrate ? HSIO_S6G_COMMON_CFG_QRATE : 0) | 211 HSIO_S6G_COMMON_CFG_IF_MODE(if_mode)); 212 213 regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, 214 HSIO_S6G_MISC_CFG_LANE_RST | 215 HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA | 216 HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA | 217 HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA, 218 HSIO_S6G_MISC_CFG_LANE_RST | 219 HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA); 220 221 222 ret = serdes_commit_mcb_s6g(regmap, serdes); 223 if (ret) 224 return ret; 225 226 regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, 227 HSIO_S6G_PLL_CFG_PLL_FSM_ENA, 228 HSIO_S6G_PLL_CFG_PLL_FSM_ENA); 229 230 ret = serdes_commit_mcb_s6g(regmap, serdes); 231 if (ret) 232 return ret; 233 234 /* Wait for PLL bringup */ 235 msleep(20); 236 237 regmap_update_bits(regmap, HSIO_S6G_IB_CFG, 238 HSIO_S6G_IB_CFG_IB_CAL_ENA, 239 HSIO_S6G_IB_CFG_IB_CAL_ENA); 240 241 regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, 242 HSIO_S6G_MISC_CFG_LANE_RST, 0); 243 244 ret = serdes_commit_mcb_s6g(regmap, serdes); 245 if (ret) 246 return ret; 247 248 /* Wait for calibration */ 249 msleep(60); 250 251 regmap_update_bits(regmap, HSIO_S6G_IB_CFG, 252 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M | 253 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M, 254 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) | 255 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(7)); 256 257 regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, 258 HSIO_S6G_IB_CFG1_IB_TSDET_M, 259 HSIO_S6G_IB_CFG1_IB_TSDET(3)); 260 261 /* IB CFG */ 262 263 return 0; 264} 265 266#define MCB_S1G_CFG_TIMEOUT 50 267 268static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op) 269{ 270 unsigned int regval; 271 272 regmap_write(regmap, HSIO_MCB_S1G_ADDR_CFG, op | 273 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro))); 274 275 return regmap_read_poll_timeout(regmap, HSIO_MCB_S1G_ADDR_CFG, regval, 276 (regval & op) != op, 100, 277 MCB_S1G_CFG_TIMEOUT * 1000); 278} 279 280static int serdes_commit_mcb_s1g(struct regmap *regmap, u8 macro) 281{ 282 return __serdes_write_mcb_s1g(regmap, macro, 283 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT); 284} 285 286static int serdes_update_mcb_s1g(struct regmap *regmap, u8 macro) 287{ 288 return __serdes_write_mcb_s1g(regmap, macro, 289 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT); 290} 291 292static int serdes_init_s1g(struct regmap *regmap, u8 serdes) 293{ 294 int ret; 295 296 ret = serdes_update_mcb_s1g(regmap, serdes); 297 if (ret) 298 return ret; 299 300 regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG, 301 HSIO_S1G_COMMON_CFG_SYS_RST | 302 HSIO_S1G_COMMON_CFG_ENA_LANE | 303 HSIO_S1G_COMMON_CFG_ENA_ELOOP | 304 HSIO_S1G_COMMON_CFG_ENA_FLOOP, 305 HSIO_S1G_COMMON_CFG_ENA_LANE); 306 307 regmap_update_bits(regmap, HSIO_S1G_PLL_CFG, 308 HSIO_S1G_PLL_CFG_PLL_FSM_ENA | 309 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M, 310 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) | 311 HSIO_S1G_PLL_CFG_PLL_FSM_ENA); 312 313 regmap_update_bits(regmap, HSIO_S1G_MISC_CFG, 314 HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA | 315 HSIO_S1G_MISC_CFG_LANE_RST, 316 HSIO_S1G_MISC_CFG_LANE_RST); 317 318 ret = serdes_commit_mcb_s1g(regmap, serdes); 319 if (ret) 320 return ret; 321 322 regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG, 323 HSIO_S1G_COMMON_CFG_SYS_RST, 324 HSIO_S1G_COMMON_CFG_SYS_RST); 325 326 regmap_update_bits(regmap, HSIO_S1G_MISC_CFG, 327 HSIO_S1G_MISC_CFG_LANE_RST, 0); 328 329 ret = serdes_commit_mcb_s1g(regmap, serdes); 330 if (ret) 331 return ret; 332 333 return 0; 334} 335 336struct serdes_mux { 337 u8 idx; 338 u8 port; 339 enum phy_mode mode; 340 int submode; 341 u32 mask; 342 u32 mux; 343}; 344 345#define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \ 346 .idx = _idx, \ 347 .port = _port, \ 348 .mode = _mode, \ 349 .submode = _submode, \ 350 .mask = _mask, \ 351 .mux = _mux, \ 352} 353 354#define SERDES_MUX_SGMII(i, p, m, c) \ 355 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c) 356#define SERDES_MUX_QSGMII(i, p, m, c) \ 357 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c) 358 359static const struct serdes_mux ocelot_serdes_muxes[] = { 360 SERDES_MUX_SGMII(SERDES1G(0), 0, 0, 0), 361 SERDES_MUX_SGMII(SERDES1G(1), 1, HSIO_HW_CFG_DEV1G_5_MODE, 0), 362 SERDES_MUX_SGMII(SERDES1G(1), 5, HSIO_HW_CFG_QSGMII_ENA | 363 HSIO_HW_CFG_DEV1G_5_MODE, HSIO_HW_CFG_DEV1G_5_MODE), 364 SERDES_MUX_SGMII(SERDES1G(2), 2, HSIO_HW_CFG_DEV1G_4_MODE, 0), 365 SERDES_MUX_SGMII(SERDES1G(2), 4, HSIO_HW_CFG_QSGMII_ENA | 366 HSIO_HW_CFG_DEV1G_4_MODE, HSIO_HW_CFG_DEV1G_4_MODE), 367 SERDES_MUX_SGMII(SERDES1G(3), 3, HSIO_HW_CFG_DEV1G_6_MODE, 0), 368 SERDES_MUX_SGMII(SERDES1G(3), 6, HSIO_HW_CFG_QSGMII_ENA | 369 HSIO_HW_CFG_DEV1G_6_MODE, HSIO_HW_CFG_DEV1G_6_MODE), 370 SERDES_MUX_SGMII(SERDES1G(4), 4, HSIO_HW_CFG_QSGMII_ENA | 371 HSIO_HW_CFG_DEV1G_4_MODE | HSIO_HW_CFG_DEV1G_9_MODE, 372 0), 373 SERDES_MUX_SGMII(SERDES1G(4), 9, HSIO_HW_CFG_DEV1G_4_MODE | 374 HSIO_HW_CFG_DEV1G_9_MODE, HSIO_HW_CFG_DEV1G_4_MODE | 375 HSIO_HW_CFG_DEV1G_9_MODE), 376 SERDES_MUX_SGMII(SERDES1G(5), 5, HSIO_HW_CFG_QSGMII_ENA | 377 HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE, 378 0), 379 SERDES_MUX_SGMII(SERDES1G(5), 10, HSIO_HW_CFG_PCIE_ENA | 380 HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE, 381 HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE), 382 SERDES_MUX_QSGMII(SERDES6G(0), 4, HSIO_HW_CFG_QSGMII_ENA, 383 HSIO_HW_CFG_QSGMII_ENA), 384 SERDES_MUX_QSGMII(SERDES6G(0), 5, HSIO_HW_CFG_QSGMII_ENA, 385 HSIO_HW_CFG_QSGMII_ENA), 386 SERDES_MUX_QSGMII(SERDES6G(0), 6, HSIO_HW_CFG_QSGMII_ENA, 387 HSIO_HW_CFG_QSGMII_ENA), 388 SERDES_MUX_SGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA, 0), 389 SERDES_MUX_QSGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA, 390 HSIO_HW_CFG_QSGMII_ENA), 391 SERDES_MUX_SGMII(SERDES6G(1), 8, 0, 0), 392 SERDES_MUX_SGMII(SERDES6G(2), 10, HSIO_HW_CFG_PCIE_ENA | 393 HSIO_HW_CFG_DEV2G5_10_MODE, 0), 394 SERDES_MUX(SERDES6G(2), 10, PHY_MODE_PCIE, 0, HSIO_HW_CFG_PCIE_ENA, 395 HSIO_HW_CFG_PCIE_ENA), 396}; 397 398static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) 399{ 400 struct serdes_macro *macro = phy_get_drvdata(phy); 401 unsigned int i; 402 int ret; 403 404 /* As of now only PHY_MODE_ETHERNET is supported */ 405 if (mode != PHY_MODE_ETHERNET) 406 return -EOPNOTSUPP; 407 408 for (i = 0; i < ARRAY_SIZE(ocelot_serdes_muxes); i++) { 409 if (macro->idx != ocelot_serdes_muxes[i].idx || 410 mode != ocelot_serdes_muxes[i].mode || 411 submode != ocelot_serdes_muxes[i].submode) 412 continue; 413 414 if (submode != PHY_INTERFACE_MODE_QSGMII && 415 macro->port != ocelot_serdes_muxes[i].port) 416 continue; 417 418 ret = regmap_update_bits(macro->ctrl->regs, HSIO_HW_CFG, 419 ocelot_serdes_muxes[i].mask, 420 ocelot_serdes_muxes[i].mux); 421 if (ret) 422 return ret; 423 424 if (macro->idx <= SERDES1G_MAX) 425 return serdes_init_s1g(macro->ctrl->regs, macro->idx); 426 else if (macro->idx <= SERDES6G_MAX) 427 return serdes_init_s6g(macro->ctrl->regs, 428 macro->idx - (SERDES1G_MAX + 1), 429 ocelot_serdes_muxes[i].submode); 430 431 /* PCIe not supported yet */ 432 return -EOPNOTSUPP; 433 } 434 435 return -EINVAL; 436} 437 438static const struct phy_ops serdes_ops = { 439 .set_mode = serdes_set_mode, 440 .owner = THIS_MODULE, 441}; 442 443static struct phy *serdes_simple_xlate(struct device *dev, 444 struct of_phandle_args *args) 445{ 446 struct serdes_ctrl *ctrl = dev_get_drvdata(dev); 447 unsigned int port, idx, i; 448 449 if (args->args_count != 2) 450 return ERR_PTR(-EINVAL); 451 452 port = args->args[0]; 453 idx = args->args[1]; 454 455 for (i = 0; i < SERDES_MAX; i++) { 456 struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]); 457 458 if (idx != macro->idx) 459 continue; 460 461 /* SERDES6G(0) is the only SerDes capable of QSGMII */ 462 if (idx != SERDES6G(0) && macro->port >= 0) 463 return ERR_PTR(-EBUSY); 464 465 macro->port = port; 466 return ctrl->phys[i]; 467 } 468 469 return ERR_PTR(-ENODEV); 470} 471 472static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy) 473{ 474 struct serdes_macro *macro; 475 476 *phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops); 477 if (IS_ERR(*phy)) 478 return PTR_ERR(*phy); 479 480 macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL); 481 if (!macro) 482 return -ENOMEM; 483 484 macro->idx = idx; 485 macro->ctrl = ctrl; 486 macro->port = -1; 487 488 phy_set_drvdata(*phy, macro); 489 490 return 0; 491} 492 493static int serdes_probe(struct platform_device *pdev) 494{ 495 struct phy_provider *provider; 496 struct serdes_ctrl *ctrl; 497 unsigned int i; 498 int ret; 499 500 ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 501 if (!ctrl) 502 return -ENOMEM; 503 504 ctrl->dev = &pdev->dev; 505 ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node); 506 if (IS_ERR(ctrl->regs)) 507 return PTR_ERR(ctrl->regs); 508 509 for (i = 0; i < SERDES_MAX; i++) { 510 ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]); 511 if (ret) 512 return ret; 513 } 514 515 dev_set_drvdata(&pdev->dev, ctrl); 516 517 provider = devm_of_phy_provider_register(ctrl->dev, 518 serdes_simple_xlate); 519 520 return PTR_ERR_OR_ZERO(provider); 521} 522 523static const struct of_device_id serdes_ids[] = { 524 { .compatible = "mscc,vsc7514-serdes", }, 525 {}, 526}; 527MODULE_DEVICE_TABLE(of, serdes_ids); 528 529static struct platform_driver mscc_ocelot_serdes = { 530 .probe = serdes_probe, 531 .driver = { 532 .name = "mscc,ocelot-serdes", 533 .of_match_table = of_match_ptr(serdes_ids), 534 }, 535}; 536 537module_platform_driver(mscc_ocelot_serdes); 538 539MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>"); 540MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot"); 541MODULE_LICENSE("Dual MIT/GPL");