brintos

brintos / linux-shallow public Read only

0
0
Text · 14.8 KiB · 1cd1b5d Raw
551 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * SerDes PHY driver for Microsemi Ocelot4 *5 * Copyright (c) 2018 Microsemi6 *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     5035 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_DATA196			   (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     50267 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				       const 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	struct resource *res;498	unsigned int i;499	int ret;500 501	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);502	if (!ctrl)503		return -ENOMEM;504 505	ctrl->dev = &pdev->dev;506	ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);507	if (IS_ERR(ctrl->regs)) {508		/* Fall back to using IORESOURCE_REG, if possible */509		res = platform_get_resource(pdev, IORESOURCE_REG, 0);510		if (res)511			ctrl->regs = dev_get_regmap(ctrl->dev->parent,512						    res->name);513	}514 515	if (IS_ERR(ctrl->regs))516		return PTR_ERR(ctrl->regs);517 518	for (i = 0; i < SERDES_MAX; i++) {519		ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]);520		if (ret)521			return ret;522	}523 524	dev_set_drvdata(&pdev->dev, ctrl);525 526	provider = devm_of_phy_provider_register(ctrl->dev,527						 serdes_simple_xlate);528 529	return PTR_ERR_OR_ZERO(provider);530}531 532static const struct of_device_id serdes_ids[] = {533	{ .compatible = "mscc,vsc7514-serdes", },534	{},535};536MODULE_DEVICE_TABLE(of, serdes_ids);537 538static struct platform_driver mscc_ocelot_serdes = {539	.probe		= serdes_probe,540	.driver		= {541		.name	= "mscc,ocelot-serdes",542		.of_match_table = of_match_ptr(serdes_ids),543	},544};545 546module_platform_driver(mscc_ocelot_serdes);547 548MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>");549MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot");550MODULE_LICENSE("Dual MIT/GPL");551