18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2018 Marvell
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *   Evan Wang <xswang@marvell.com>
78c2ecf20Sopenharmony_ci *   Miquèl Raynal <miquel.raynal@bootlin.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart.
108c2ecf20Sopenharmony_ci * SMC call initial support done by Grzegorz Jaszczyk.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/phy.h>
198c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define MVEBU_A3700_COMPHY_LANES		3
238c2ecf20Sopenharmony_ci#define MVEBU_A3700_COMPHY_PORTS		2
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* COMPHY Fast SMC function identifiers */
268c2ecf20Sopenharmony_ci#define COMPHY_SIP_POWER_ON			0x82000001
278c2ecf20Sopenharmony_ci#define COMPHY_SIP_POWER_OFF			0x82000002
288c2ecf20Sopenharmony_ci#define COMPHY_SIP_PLL_LOCK			0x82000003
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_SATA			0x1
318c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_SGMII			0x2
328c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_HS_SGMII			0x3
338c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_USB3H			0x4
348c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_USB3D			0x5
358c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_PCIE			0x6
368c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_RXAUI			0x7
378c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_XFI			0x8
388c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_SFI			0x9
398c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_USB3			0xa
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_1_25G			0 /* SGMII 1G */
428c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_2_5G			1
438c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_3_125G			2 /* SGMII 2.5G */
448c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_5G			3
458c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_5_15625G		4 /* XFI 5G */
468c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_6G			5
478c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_10_3125G		6 /* XFI 10G */
488c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_MAX			0x3F
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE(mode)			((mode) << 12)
518c2ecf20Sopenharmony_ci#define COMPHY_FW_NET(mode, idx, speed)		(COMPHY_FW_MODE(mode) | \
528c2ecf20Sopenharmony_ci						 ((idx) << 8) |	\
538c2ecf20Sopenharmony_ci						 ((speed) << 2))
548c2ecf20Sopenharmony_ci#define COMPHY_FW_PCIE(mode, idx, speed, width)	(COMPHY_FW_NET(mode, idx, speed) | \
558c2ecf20Sopenharmony_ci						 ((width) << 18))
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct mvebu_a3700_comphy_conf {
588c2ecf20Sopenharmony_ci	unsigned int lane;
598c2ecf20Sopenharmony_ci	enum phy_mode mode;
608c2ecf20Sopenharmony_ci	int submode;
618c2ecf20Sopenharmony_ci	unsigned int port;
628c2ecf20Sopenharmony_ci	u32 fw_mode;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw)	\
668c2ecf20Sopenharmony_ci	{								\
678c2ecf20Sopenharmony_ci		.lane = _lane,						\
688c2ecf20Sopenharmony_ci		.mode = _mode,						\
698c2ecf20Sopenharmony_ci		.submode = _smode,					\
708c2ecf20Sopenharmony_ci		.port = _port,						\
718c2ecf20Sopenharmony_ci		.fw_mode = _fw,						\
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
758c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw)
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
788c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
818c2ecf20Sopenharmony_ci	/* lane 0 */
828c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
838c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_USB3H),
848c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
858c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_SGMII),
868c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1,
878c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_HS_SGMII),
888c2ecf20Sopenharmony_ci	/* lane 1 */
898c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
908c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_PCIE),
918c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
928c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_SGMII),
938c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0,
948c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_HS_SGMII),
958c2ecf20Sopenharmony_ci	/* lane 2 */
968c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
978c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_SATA),
988c2ecf20Sopenharmony_ci	MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
998c2ecf20Sopenharmony_ci				    COMPHY_FW_MODE_USB3H),
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistruct mvebu_a3700_comphy_lane {
1038c2ecf20Sopenharmony_ci	struct device *dev;
1048c2ecf20Sopenharmony_ci	unsigned int id;
1058c2ecf20Sopenharmony_ci	enum phy_mode mode;
1068c2ecf20Sopenharmony_ci	int submode;
1078c2ecf20Sopenharmony_ci	int port;
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
1118c2ecf20Sopenharmony_ci				  unsigned long mode)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct arm_smccc_res res;
1148c2ecf20Sopenharmony_ci	s32 ret;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
1178c2ecf20Sopenharmony_ci	ret = res.a0;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	switch (ret) {
1208c2ecf20Sopenharmony_ci	case SMCCC_RET_SUCCESS:
1218c2ecf20Sopenharmony_ci		return 0;
1228c2ecf20Sopenharmony_ci	case SMCCC_RET_NOT_SUPPORTED:
1238c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1248c2ecf20Sopenharmony_ci	default:
1258c2ecf20Sopenharmony_ci		return -EINVAL;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
1308c2ecf20Sopenharmony_ci					  enum phy_mode mode,
1318c2ecf20Sopenharmony_ci					  int submode)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Unused PHY mux value is 0x0 */
1368c2ecf20Sopenharmony_ci	if (mode == PHY_MODE_INVALID)
1378c2ecf20Sopenharmony_ci		return -EINVAL;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
1408c2ecf20Sopenharmony_ci		if (mvebu_a3700_comphy_modes[i].lane == lane &&
1418c2ecf20Sopenharmony_ci		    mvebu_a3700_comphy_modes[i].port == port &&
1428c2ecf20Sopenharmony_ci		    mvebu_a3700_comphy_modes[i].mode == mode &&
1438c2ecf20Sopenharmony_ci		    mvebu_a3700_comphy_modes[i].submode == submode)
1448c2ecf20Sopenharmony_ci			break;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (i == n)
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return mvebu_a3700_comphy_modes[i].fw_mode;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode,
1548c2ecf20Sopenharmony_ci				       int submode)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
1578c2ecf20Sopenharmony_ci	int fw_mode;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (submode == PHY_INTERFACE_MODE_1000BASEX)
1608c2ecf20Sopenharmony_ci		submode = PHY_INTERFACE_MODE_SGMII;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
1638c2ecf20Sopenharmony_ci						 submode);
1648c2ecf20Sopenharmony_ci	if (fw_mode < 0) {
1658c2ecf20Sopenharmony_ci		dev_err(lane->dev, "invalid COMPHY mode\n");
1668c2ecf20Sopenharmony_ci		return fw_mode;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* Just remember the mode, ->power_on() will do the real setup */
1708c2ecf20Sopenharmony_ci	lane->mode = mode;
1718c2ecf20Sopenharmony_ci	lane->submode = submode;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_power_on(struct phy *phy)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
1798c2ecf20Sopenharmony_ci	u32 fw_param;
1808c2ecf20Sopenharmony_ci	int fw_mode;
1818c2ecf20Sopenharmony_ci	int ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
1848c2ecf20Sopenharmony_ci						 lane->mode, lane->submode);
1858c2ecf20Sopenharmony_ci	if (fw_mode < 0) {
1868c2ecf20Sopenharmony_ci		dev_err(lane->dev, "invalid COMPHY mode\n");
1878c2ecf20Sopenharmony_ci		return fw_mode;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	switch (lane->mode) {
1918c2ecf20Sopenharmony_ci	case PHY_MODE_USB_HOST_SS:
1928c2ecf20Sopenharmony_ci		dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id);
1938c2ecf20Sopenharmony_ci		fw_param = COMPHY_FW_MODE(fw_mode);
1948c2ecf20Sopenharmony_ci		break;
1958c2ecf20Sopenharmony_ci	case PHY_MODE_SATA:
1968c2ecf20Sopenharmony_ci		dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id);
1978c2ecf20Sopenharmony_ci		fw_param = COMPHY_FW_MODE(fw_mode);
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	case PHY_MODE_ETHERNET:
2008c2ecf20Sopenharmony_ci		switch (lane->submode) {
2018c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_SGMII:
2028c2ecf20Sopenharmony_ci			dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
2038c2ecf20Sopenharmony_ci				lane->id);
2048c2ecf20Sopenharmony_ci			fw_param = COMPHY_FW_NET(fw_mode, lane->port,
2058c2ecf20Sopenharmony_ci						 COMPHY_FW_SPEED_1_25G);
2068c2ecf20Sopenharmony_ci			break;
2078c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_2500BASEX:
2088c2ecf20Sopenharmony_ci			dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n",
2098c2ecf20Sopenharmony_ci				lane->id);
2108c2ecf20Sopenharmony_ci			fw_param = COMPHY_FW_NET(fw_mode, lane->port,
2118c2ecf20Sopenharmony_ci						 COMPHY_FW_SPEED_3_125G);
2128c2ecf20Sopenharmony_ci			break;
2138c2ecf20Sopenharmony_ci		default:
2148c2ecf20Sopenharmony_ci			dev_err(lane->dev, "unsupported PHY submode (%d)\n",
2158c2ecf20Sopenharmony_ci				lane->submode);
2168c2ecf20Sopenharmony_ci			return -ENOTSUPP;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci	case PHY_MODE_PCIE:
2208c2ecf20Sopenharmony_ci		dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
2218c2ecf20Sopenharmony_ci		fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
2228c2ecf20Sopenharmony_ci					  COMPHY_FW_SPEED_5G,
2238c2ecf20Sopenharmony_ci					  phy->attrs.bus_width);
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci	default:
2268c2ecf20Sopenharmony_ci		dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode);
2278c2ecf20Sopenharmony_ci		return -ENOTSUPP;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
2318c2ecf20Sopenharmony_ci	if (ret == -EOPNOTSUPP)
2328c2ecf20Sopenharmony_ci		dev_err(lane->dev,
2338c2ecf20Sopenharmony_ci			"unsupported SMC call, try updating your firmware\n");
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return ret;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_power_off(struct phy *phy)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic const struct phy_ops mvebu_a3700_comphy_ops = {
2468c2ecf20Sopenharmony_ci	.power_on	= mvebu_a3700_comphy_power_on,
2478c2ecf20Sopenharmony_ci	.power_off	= mvebu_a3700_comphy_power_off,
2488c2ecf20Sopenharmony_ci	.set_mode	= mvebu_a3700_comphy_set_mode,
2498c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
2508c2ecf20Sopenharmony_ci};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic struct phy *mvebu_a3700_comphy_xlate(struct device *dev,
2538c2ecf20Sopenharmony_ci					    struct of_phandle_args *args)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct mvebu_a3700_comphy_lane *lane;
2568c2ecf20Sopenharmony_ci	struct phy *phy;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS))
2598c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	phy = of_phy_simple_xlate(dev, args);
2628c2ecf20Sopenharmony_ci	if (IS_ERR(phy))
2638c2ecf20Sopenharmony_ci		return phy;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	lane = phy_get_drvdata(phy);
2668c2ecf20Sopenharmony_ci	lane->port = args->args[0];
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return phy;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int mvebu_a3700_comphy_probe(struct platform_device *pdev)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct phy_provider *provider;
2748c2ecf20Sopenharmony_ci	struct device_node *child;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	for_each_available_child_of_node(pdev->dev.of_node, child) {
2778c2ecf20Sopenharmony_ci		struct mvebu_a3700_comphy_lane *lane;
2788c2ecf20Sopenharmony_ci		struct phy *phy;
2798c2ecf20Sopenharmony_ci		int ret;
2808c2ecf20Sopenharmony_ci		u32 lane_id;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		ret = of_property_read_u32(child, "reg", &lane_id);
2838c2ecf20Sopenharmony_ci		if (ret < 0) {
2848c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "missing 'reg' property (%d)\n",
2858c2ecf20Sopenharmony_ci				ret);
2868c2ecf20Sopenharmony_ci			continue;
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		if (lane_id >= MVEBU_A3700_COMPHY_LANES) {
2908c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "invalid 'reg' property\n");
2918c2ecf20Sopenharmony_ci			continue;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);
2958c2ecf20Sopenharmony_ci		if (!lane) {
2968c2ecf20Sopenharmony_ci			of_node_put(child);
2978c2ecf20Sopenharmony_ci			return -ENOMEM;
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		phy = devm_phy_create(&pdev->dev, child,
3018c2ecf20Sopenharmony_ci				      &mvebu_a3700_comphy_ops);
3028c2ecf20Sopenharmony_ci		if (IS_ERR(phy)) {
3038c2ecf20Sopenharmony_ci			of_node_put(child);
3048c2ecf20Sopenharmony_ci			return PTR_ERR(phy);
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		lane->dev = &pdev->dev;
3088c2ecf20Sopenharmony_ci		lane->mode = PHY_MODE_INVALID;
3098c2ecf20Sopenharmony_ci		lane->submode = PHY_INTERFACE_MODE_NA;
3108c2ecf20Sopenharmony_ci		lane->id = lane_id;
3118c2ecf20Sopenharmony_ci		lane->port = -1;
3128c2ecf20Sopenharmony_ci		phy_set_drvdata(phy, lane);
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	provider = devm_of_phy_provider_register(&pdev->dev,
3168c2ecf20Sopenharmony_ci						 mvebu_a3700_comphy_xlate);
3178c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(provider);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic const struct of_device_id mvebu_a3700_comphy_of_match_table[] = {
3218c2ecf20Sopenharmony_ci	{ .compatible = "marvell,comphy-a3700" },
3228c2ecf20Sopenharmony_ci	{ },
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic struct platform_driver mvebu_a3700_comphy_driver = {
3278c2ecf20Sopenharmony_ci	.probe	= mvebu_a3700_comphy_probe,
3288c2ecf20Sopenharmony_ci	.driver	= {
3298c2ecf20Sopenharmony_ci		.name = "mvebu-a3700-comphy",
3308c2ecf20Sopenharmony_ci		.of_match_table = mvebu_a3700_comphy_of_match_table,
3318c2ecf20Sopenharmony_ci	},
3328c2ecf20Sopenharmony_ci};
3338c2ecf20Sopenharmony_cimodule_platform_driver(mvebu_a3700_comphy_driver);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>");
3368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Common PHY driver for A3700");
3378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
338