File Index
Files and directories
Sign in
FILE

marvell-88q2xxx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/phy/marvell-88q2xxx.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
   4 *
   5 * Derived from Marvell Q222x API
   6 *
   7 * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
   8 */
   9#include <linux/ethtool_netlink.h>
  10#include <linux/hwmon.h>
  11#include <linux/marvell_phy.h>
  12#include <linux/of.h>
  13#include <linux/phy.h>
  14
  15#define PHY_ID_88Q2220_REVB0				(MARVELL_PHY_ID_88Q2220 | 0x1)
  16#define PHY_ID_88Q2220_REVB1				(MARVELL_PHY_ID_88Q2220 | 0x2)
  17#define PHY_ID_88Q2220_REVB2				(MARVELL_PHY_ID_88Q2220 | 0x3)
  18
  19#define MDIO_MMD_AN_MV_STAT				32769
  20#define MDIO_MMD_AN_MV_STAT_ANEG			0x0100
  21#define MDIO_MMD_AN_MV_STAT_LOCAL_RX			0x1000
  22#define MDIO_MMD_AN_MV_STAT_REMOTE_RX			0x2000
  23#define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER		0x4000
  24#define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT		0x8000
  25
  26#define MDIO_MMD_AN_MV_STAT2				32794
  27#define MDIO_MMD_AN_MV_STAT2_AN_RESOLVED		0x0800
  28#define MDIO_MMD_AN_MV_STAT2_100BT1			0x2000
  29#define MDIO_MMD_AN_MV_STAT2_1000BT1			0x4000
  30
  31#define MDIO_MMD_PCS_MV_RESET_CTRL			32768
  32#define MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE		0x8
  33
  34#define MDIO_MMD_PCS_MV_INT_EN				32784
  35#define MDIO_MMD_PCS_MV_INT_EN_LINK_UP			0x0040
  36#define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN		0x0080
  37#define MDIO_MMD_PCS_MV_INT_EN_100BT1			0x1000
  38
  39#define MDIO_MMD_PCS_MV_GPIO_INT_STAT			32785
  40#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP		0x0040
  41#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN		0x0080
  42#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_100BT1_GEN	0x1000
  43
  44#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL			32787
  45#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS		0x0800
  46
  47#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL			32790
  48#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK	GENMASK(7, 4)
  49#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK	GENMASK(3, 0)
  50#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK		0x0 /* Link established */
  51#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX	0x1 /* Link established, blink for rx or tx activity */
  52#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1	0x2 /* Blink 3x for 1000BT1 link established */
  53#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX_ON		0x3 /* Receive or transmit activity */
  54#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX		0x4 /* Blink on receive or transmit activity */
  55#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX		0x5 /* Transmit activity */
  56#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_COPPER	0x6 /* Copper Link established */
  57#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON	0x7 /* 1000BT1 link established */
  58#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_OFF		0x8 /* Force off */
  59#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_ON		0x9 /* Force on */
  60#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_HIGHZ	0xa /* Force Hi-Z */
  61#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_BLINK	0xb /* Force blink */
  62
  63#define MDIO_MMD_PCS_MV_TEMP_SENSOR1			32833
  64#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT		0x0001
  65#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT		0x0040
  66#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT_EN		0x0080
  67
  68#define MDIO_MMD_PCS_MV_TEMP_SENSOR2			32834
  69#define MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK		0xc000
  70
  71#define MDIO_MMD_PCS_MV_TEMP_SENSOR3			32835
  72#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK	0xff00
  73#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK		0x00ff
  74
  75#define MDIO_MMD_PCS_MV_100BT1_STAT1			33032
  76#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR		0x00ff
  77#define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER		0x0100
  78#define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK		0x0200
  79#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX		0x1000
  80#define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX		0x2000
  81#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER	0x4000
  82
  83#define MDIO_MMD_PCS_MV_100BT1_STAT2			33033
  84#define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER		0x0001
  85#define MDIO_MMD_PCS_MV_100BT1_STAT2_POL		0x0002
  86#define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK		0x0004
  87#define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE		0x0008
  88
  89#define MDIO_MMD_PCS_MV_100BT1_INT_EN			33042
  90#define MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT		0x0400
  91
  92#define MDIO_MMD_PCS_MV_COPPER_INT_STAT			33043
  93#define MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT	0x0400
  94
  95#define MDIO_MMD_PCS_MV_RX_STAT				33328
  96
  97#define MDIO_MMD_PCS_MV_TDR_RESET			65226
  98#define MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST		0x1000
  99
 100#define MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE		65241
 101
 102#define MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE		65242
 103
 104#define MDIO_MMD_PCS_MV_TDR_STATUS			65245
 105#define MDIO_MMD_PCS_MV_TDR_STATUS_MASK			0x0003
 106#define MDIO_MMD_PCS_MV_TDR_STATUS_OFF			0x0001
 107#define MDIO_MMD_PCS_MV_TDR_STATUS_ON			0x0002
 108#define MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK		0xff00
 109#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK	0x00f0
 110#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT	0x0030
 111#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN	0x00e0
 112#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK		0x0070
 113#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_IN_PROGR	0x0080
 114#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_NOISE	0x0050
 115
 116#define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF			65246
 117
 118#define MV88Q2XXX_LED_INDEX_TX_ENABLE			0
 119#define MV88Q2XXX_LED_INDEX_GPIO			1
 120
 121struct mv88q2xxx_priv {
 122	bool enable_led0;
 123};
 124
 125struct mmd_val {
 126	int devad;
 127	u32 regnum;
 128	u16 val;
 129};
 130
 131static const struct mmd_val mv88q2110_init_seq0[] = {
 132	{ MDIO_MMD_PCS, 0xffe4, 0x07b5 },
 133	{ MDIO_MMD_PCS, 0xffe4, 0x06b6 },
 134};
 135
 136static const struct mmd_val mv88q2110_init_seq1[] = {
 137	{ MDIO_MMD_PCS, 0xffde, 0x402f },
 138	{ MDIO_MMD_PCS, 0xfe34, 0x4040 },
 139	{ MDIO_MMD_PCS, 0xfe2a, 0x3c1d },
 140	{ MDIO_MMD_PCS, 0xfe34, 0x0040 },
 141	{ MDIO_MMD_AN, 0x8032, 0x0064 },
 142	{ MDIO_MMD_AN, 0x8031, 0x0a01 },
 143	{ MDIO_MMD_AN, 0x8031, 0x0c01 },
 144	{ MDIO_MMD_PCS, 0xffdb, 0x0010 },
 145};
 146
 147static const struct mmd_val mv88q222x_revb0_init_seq0[] = {
 148	{ MDIO_MMD_PCS, 0x8033, 0x6801 },
 149	{ MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
 150	{ MDIO_MMD_PMAPMD, MDIO_CTRL1,
 151	  MDIO_CTRL1_LPOWER | MDIO_PMA_CTRL1_SPEED1000 },
 152	{ MDIO_MMD_PCS, 0xfe1b, 0x48 },
 153	{ MDIO_MMD_PCS, 0xffe4, 0x6b6 },
 154	{ MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0 },
 155	{ MDIO_MMD_PCS, MDIO_CTRL1, 0x0 },
 156};
 157
 158static const struct mmd_val mv88q222x_revb0_init_seq1[] = {
 159	{ MDIO_MMD_PCS, 0xfe79, 0x0 },
 160	{ MDIO_MMD_PCS, 0xfe07, 0x125a },
 161	{ MDIO_MMD_PCS, 0xfe09, 0x1288 },
 162	{ MDIO_MMD_PCS, 0xfe08, 0x2588 },
 163	{ MDIO_MMD_PCS, 0xfe11, 0x1105 },
 164	{ MDIO_MMD_PCS, 0xfe72, 0x042c },
 165	{ MDIO_MMD_PCS, 0xfbba, 0xcb2 },
 166	{ MDIO_MMD_PCS, 0xfbbb, 0xc4a },
 167	{ MDIO_MMD_AN, 0x8032, 0x2020 },
 168	{ MDIO_MMD_AN, 0x8031, 0xa28 },
 169	{ MDIO_MMD_AN, 0x8031, 0xc28 },
 170	{ MDIO_MMD_PCS, 0xffdb, 0xfc10 },
 171	{ MDIO_MMD_PCS, 0xfe1b, 0x58 },
 172	{ MDIO_MMD_PCS, 0xfe79, 0x4 },
 173	{ MDIO_MMD_PCS, 0xfe5f, 0xe8 },
 174	{ MDIO_MMD_PCS, 0xfe05, 0x755c },
 175};
 176
 177static const struct mmd_val mv88q222x_revb1_init_seq0[] = {
 178	{ MDIO_MMD_PCS, 0xffe4, 0x0007 },
 179	{ MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
 180	{ MDIO_MMD_PCS, 0xffe3, 0x7000 },
 181	{ MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0840 },
 182};
 183
 184static const struct mmd_val mv88q222x_revb2_init_seq0[] = {
 185	{ MDIO_MMD_PCS, 0xffe4, 0x0007 },
 186	{ MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
 187	{ MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0840 },
 188};
 189
 190static const struct mmd_val mv88q222x_revb1_revb2_init_seq1[] = {
 191	{ MDIO_MMD_PCS, 0xfe07, 0x125a },
 192	{ MDIO_MMD_PCS, 0xfe09, 0x1288 },
 193	{ MDIO_MMD_PCS, 0xfe08, 0x2588 },
 194	{ MDIO_MMD_PCS, 0xfe72, 0x042c },
 195	{ MDIO_MMD_PCS, 0xffe4, 0x0071 },
 196	{ MDIO_MMD_PCS, 0xffe4, 0x0001 },
 197	{ MDIO_MMD_PCS, 0xfe1b, 0x0048 },
 198	{ MDIO_MMD_PMAPMD, 0x0000, 0x0000 },
 199	{ MDIO_MMD_PCS, 0x0000, 0x0000 },
 200	{ MDIO_MMD_PCS, 0xffdb, 0xfc10 },
 201	{ MDIO_MMD_PCS, 0xfe1b, 0x58 },
 202	{ MDIO_MMD_PCS, 0xfcad, 0x030c },
 203	{ MDIO_MMD_PCS, 0x8032, 0x6001 },
 204	{ MDIO_MMD_PCS, 0xfdff, 0x05a5 },
 205	{ MDIO_MMD_PCS, 0xfdec, 0xdbaf },
 206	{ MDIO_MMD_PCS, 0xfcab, 0x1054 },
 207	{ MDIO_MMD_PCS, 0xfcac, 0x1483 },
 208	{ MDIO_MMD_PCS, 0x8033, 0xc801 },
 209	{ MDIO_MMD_AN, 0x8032, 0x2020 },
 210	{ MDIO_MMD_AN, 0x8031, 0xa28 },
 211	{ MDIO_MMD_AN, 0x8031, 0xc28 },
 212	{ MDIO_MMD_PCS, 0xfbba, 0x0cb2 },
 213	{ MDIO_MMD_PCS, 0xfbbb, 0x0c4a },
 214	{ MDIO_MMD_PCS, 0xfe5f, 0xe8 },
 215	{ MDIO_MMD_PCS, 0xfe05, 0x755c },
 216	{ MDIO_MMD_PCS, 0xfa20, 0x002a },
 217	{ MDIO_MMD_PCS, 0xfe11, 0x1105 },
 218};
 219
 220static int mv88q2xxx_write_mmd_vals(struct phy_device *phydev,
 221				    const struct mmd_val *vals, size_t len)
 222{
 223	int ret;
 224
 225	for (; len; vals++, len--) {
 226		ret = phy_write_mmd(phydev, vals->devad, vals->regnum,
 227				    vals->val);
 228		if (ret < 0)
 229			return ret;
 230	}
 231
 232	return 0;
 233}
 234
 235static int mv88q2xxx_soft_reset(struct phy_device *phydev)
 236{
 237	int ret;
 238	int val;
 239
 240	/* Enable RESET of DCL */
 241	if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) {
 242		ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48);
 243		if (ret < 0)
 244			return ret;
 245	}
 246
 247	ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL,
 248			    MDIO_PCS_1000BT1_CTRL_RESET);
 249	if (ret < 0)
 250		return ret;
 251
 252	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
 253					MDIO_PCS_1000BT1_CTRL, val,
 254					!(val & MDIO_PCS_1000BT1_CTRL_RESET),
 255					50000, 600000, true);
 256	if (ret < 0)
 257		return ret;
 258
 259	ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc);
 260	if (ret < 0)
 261		return ret;
 262
 263	/* Disable RESET of DCL */
 264	if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000)
 265		return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58);
 266
 267	return 0;
 268}
 269
 270static int mv88q2xxx_read_link_gbit(struct phy_device *phydev)
 271{
 272	int ret;
 273	bool link = false;
 274
 275	/* Read vendor specific Auto-Negotiation status register to get local
 276	 * and remote receiver status according to software initialization
 277	 * guide. However, when not in polling mode the local and remote
 278	 * receiver status are not evaluated due to the Marvell 88Q2xxx APIs.
 279	 */
 280	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
 281	if (ret < 0) {
 282		return ret;
 283	} else if (((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) &&
 284		   (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) ||
 285		   !phy_polling_mode(phydev)) {
 286		/* The link state is latched low so that momentary link
 287		 * drops can be detected. Do not double-read the status
 288		 * in polling mode to detect such short link drops except
 289		 * the link was already down.
 290		 */
 291		if (!phy_polling_mode(phydev) || !phydev->link) {
 292			ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 293					   MDIO_PCS_1000BT1_STAT);
 294			if (ret < 0)
 295				return ret;
 296			else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
 297				link = true;
 298		}
 299
 300		if (!link) {
 301			ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 302					   MDIO_PCS_1000BT1_STAT);
 303			if (ret < 0)
 304				return ret;
 305			else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
 306				link = true;
 307		}
 308	}
 309
 310	phydev->link = link;
 311
 312	return 0;
 313}
 314
 315static int mv88q2xxx_read_link_100m(struct phy_device *phydev)
 316{
 317	int ret;
 318
 319	/* The link state is latched low so that momentary link
 320	 * drops can be detected. Do not double-read the status
 321	 * in polling mode to detect such short link drops except
 322	 * the link was already down. In case we are not polling,
 323	 * we always read the realtime status.
 324	 */
 325	if (!phy_polling_mode(phydev)) {
 326		phydev->link = false;
 327		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 328				   MDIO_MMD_PCS_MV_100BT1_STAT2);
 329		if (ret < 0)
 330			return ret;
 331
 332		if (ret & MDIO_MMD_PCS_MV_100BT1_STAT2_LINK)
 333			phydev->link = true;
 334
 335		return 0;
 336	} else if (!phydev->link) {
 337		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 338				   MDIO_MMD_PCS_MV_100BT1_STAT1);
 339		if (ret < 0)
 340			return ret;
 341		else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK)
 342			goto out;
 343	}
 344
 345	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
 346	if (ret < 0)
 347		return ret;
 348
 349out:
 350	/* Check if we have link and if the remote and local receiver are ok */
 351	if ((ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) &&
 352	    (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX) &&
 353	    (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX))
 354		phydev->link = true;
 355	else
 356		phydev->link = false;
 357
 358	return 0;
 359}
 360
 361static int mv88q2xxx_read_link(struct phy_device *phydev)
 362{
 363	/* The 88Q2XXX PHYs do not have the PMA/PMD status register available,
 364	 * therefore we need to read the link status from the vendor specific
 365	 * registers depending on the speed.
 366	 */
 367
 368	if (phydev->speed == SPEED_1000)
 369		return mv88q2xxx_read_link_gbit(phydev);
 370	else if (phydev->speed == SPEED_100)
 371		return mv88q2xxx_read_link_100m(phydev);
 372
 373	phydev->link = false;
 374	return 0;
 375}
 376
 377static int mv88q2xxx_read_master_slave_state(struct phy_device *phydev)
 378{
 379	int ret;
 380
 381	phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
 382	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
 383	if (ret < 0)
 384		return ret;
 385
 386	if (ret & MDIO_MMD_AN_MV_STAT_LOCAL_MASTER)
 387		phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
 388	else
 389		phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
 390
 391	return 0;
 392}
 393
 394static int mv88q2xxx_read_aneg_speed(struct phy_device *phydev)
 395{
 396	int ret;
 397
 398	phydev->speed = SPEED_UNKNOWN;
 399	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT2);
 400	if (ret < 0)
 401		return ret;
 402
 403	if (!(ret & MDIO_MMD_AN_MV_STAT2_AN_RESOLVED))
 404		return 0;
 405
 406	if (ret & MDIO_MMD_AN_MV_STAT2_100BT1)
 407		phydev->speed = SPEED_100;
 408	else if (ret & MDIO_MMD_AN_MV_STAT2_1000BT1)
 409		phydev->speed = SPEED_1000;
 410
 411	return 0;
 412}
 413
 414static int mv88q2xxx_read_status(struct phy_device *phydev)
 415{
 416	int ret;
 417
 418	if (phydev->autoneg == AUTONEG_ENABLE) {
 419		/* We have to get the negotiated speed first, otherwise we are
 420		 * not able to read the link.
 421		 */
 422		ret = mv88q2xxx_read_aneg_speed(phydev);
 423		if (ret < 0)
 424			return ret;
 425
 426		ret = mv88q2xxx_read_link(phydev);
 427		if (ret < 0)
 428			return ret;
 429
 430		ret = genphy_c45_read_lpa(phydev);
 431		if (ret < 0)
 432			return ret;
 433
 434		ret = genphy_c45_baset1_read_status(phydev);
 435		if (ret < 0)
 436			return ret;
 437
 438		ret = mv88q2xxx_read_master_slave_state(phydev);
 439		if (ret < 0)
 440			return ret;
 441
 442		phy_resolve_aneg_linkmode(phydev);
 443
 444		return 0;
 445	}
 446
 447	ret = mv88q2xxx_read_link(phydev);
 448	if (ret < 0)
 449		return ret;
 450
 451	return genphy_c45_read_pma(phydev);
 452}
 453
 454static int mv88q2xxx_get_features(struct phy_device *phydev)
 455{
 456	int ret;
 457
 458	ret = genphy_c45_pma_read_abilities(phydev);
 459	if (ret)
 460		return ret;
 461
 462	/* We need to read the baset1 extended abilities manually because the
 463	 * PHY does not signalize it has the extended abilities register
 464	 * available.
 465	 */
 466	ret = genphy_c45_pma_baset1_read_abilities(phydev);
 467	if (ret)
 468		return ret;
 469
 470	return 0;
 471}
 472
 473static int mv88q2xxx_config_aneg(struct phy_device *phydev)
 474{
 475	int ret;
 476
 477	ret = genphy_c45_config_aneg(phydev);
 478	if (ret)
 479		return ret;
 480
 481	return phydev->drv->soft_reset(phydev);
 482}
 483
 484static int mv88q2xxx_get_sqi(struct phy_device *phydev)
 485{
 486	int ret;
 487
 488	if (phydev->speed == SPEED_100) {
 489		/* Read the SQI from the vendor specific receiver status
 490		 * register
 491		 */
 492		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 493				   MDIO_MMD_PCS_MV_RX_STAT);
 494		if (ret < 0)
 495			return ret;
 496
 497		ret = ret >> 12;
 498	} else {
 499		/* Read from vendor specific registers, they are not documented
 500		 * but can be found in the Software Initialization Guide. Only
 501		 * revisions >= A0 are supported.
 502		 */
 503		ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xfc5d, 0xff, 0xac);
 504		if (ret < 0)
 505			return ret;
 506
 507		ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0xfc88);
 508		if (ret < 0)
 509			return ret;
 510	}
 511
 512	return ret & 0x0f;
 513}
 514
 515static int mv88q2xxx_get_sqi_max(struct phy_device *phydev)
 516{
 517	return 15;
 518}
 519
 520static int mv88q2xxx_config_intr(struct phy_device *phydev)
 521{
 522	int ret;
 523
 524	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 525		/* Enable interrupts for 1000BASE-T1 link up and down events
 526		 * and enable general interrupts for 100BASE-T1.
 527		 */
 528		ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
 529				    MDIO_MMD_PCS_MV_INT_EN,
 530				    MDIO_MMD_PCS_MV_INT_EN_LINK_UP |
 531				    MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN |
 532				    MDIO_MMD_PCS_MV_INT_EN_100BT1);
 533		if (ret < 0)
 534			return ret;
 535
 536		/* Enable interrupts for 100BASE-T1 link events */
 537		return phy_write_mmd(phydev, MDIO_MMD_PCS,
 538				     MDIO_MMD_PCS_MV_100BT1_INT_EN,
 539				     MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT);
 540	} else {
 541		ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
 542				    MDIO_MMD_PCS_MV_INT_EN, 0);
 543		if (ret < 0)
 544			return ret;
 545
 546		return phy_write_mmd(phydev, MDIO_MMD_PCS,
 547				     MDIO_MMD_PCS_MV_100BT1_INT_EN, 0);
 548	}
 549}
 550
 551static irqreturn_t mv88q2xxx_handle_interrupt(struct phy_device *phydev)
 552{
 553	bool trigger_machine = false;
 554	int irq;
 555
 556	/* Before we can acknowledge the 100BT1 general interrupt, that is in
 557	 * the 1000BT1 interrupt status register, we have to acknowledge any
 558	 * interrupts that are related to it. Therefore we read first the 100BT1
 559	 * interrupt status register, followed by reading the 1000BT1 interrupt
 560	 * status register.
 561	 */
 562
 563	irq = phy_read_mmd(phydev, MDIO_MMD_PCS,
 564			   MDIO_MMD_PCS_MV_COPPER_INT_STAT);
 565	if (irq < 0) {
 566		phy_error(phydev);
 567		return IRQ_NONE;
 568	}
 569
 570	/* Check link status for 100BT1 */
 571	if (irq & MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT)
 572		trigger_machine = true;
 573
 574	irq = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_GPIO_INT_STAT);
 575	if (irq < 0) {
 576		phy_error(phydev);
 577		return IRQ_NONE;
 578	}
 579
 580	/* Check link status for 1000BT1 */
 581	if ((irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP) ||
 582	    (irq & MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN))
 583		trigger_machine = true;
 584
 585	if (!trigger_machine)
 586		return IRQ_NONE;
 587
 588	phy_trigger_machine(phydev);
 589
 590	return IRQ_HANDLED;
 591}
 592
 593static int mv88q2xxx_suspend(struct phy_device *phydev)
 594{
 595	int ret;
 596
 597	/* Disable PHY interrupts */
 598	if (phy_interrupt_is_valid(phydev)) {
 599		phydev->interrupts = PHY_INTERRUPT_DISABLED;
 600		ret = mv88q2xxx_config_intr(phydev);
 601		if (ret)
 602			return ret;
 603	}
 604
 605	return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
 606				MDIO_CTRL1_LPOWER);
 607}
 608
 609static int mv88q2xxx_resume(struct phy_device *phydev)
 610{
 611	int ret;
 612
 613	/* Enable PHY interrupts */
 614	if (phy_interrupt_is_valid(phydev)) {
 615		phydev->interrupts = PHY_INTERRUPT_ENABLED;
 616		ret = mv88q2xxx_config_intr(phydev);
 617		if (ret)
 618			return ret;
 619	}
 620
 621	return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
 622				  MDIO_CTRL1_LPOWER);
 623}
 624
 625#if IS_ENABLED(CONFIG_HWMON)
 626static int mv88q2xxx_enable_temp_sense(struct phy_device *phydev)
 627{
 628	return phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TEMP_SENSOR2,
 629			      MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK, 0);
 630}
 631
 632static const struct hwmon_channel_info * const mv88q2xxx_hwmon_info[] = {
 633	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_ALARM),
 634	NULL
 635};
 636
 637static umode_t mv88q2xxx_hwmon_is_visible(const void *data,
 638					  enum hwmon_sensor_types type,
 639					  u32 attr, int channel)
 640{
 641	switch (attr) {
 642	case hwmon_temp_input:
 643		return 0444;
 644	case hwmon_temp_max:
 645		return 0644;
 646	case hwmon_temp_alarm:
 647		return 0444;
 648	default:
 649		return 0;
 650	}
 651}
 652
 653static int mv88q2xxx_hwmon_read(struct device *dev,
 654				enum hwmon_sensor_types type,
 655				u32 attr, int channel, long *val)
 656{
 657	struct phy_device *phydev = dev_get_drvdata(dev);
 658	int ret;
 659
 660	switch (attr) {
 661	case hwmon_temp_input:
 662		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 663				   MDIO_MMD_PCS_MV_TEMP_SENSOR3);
 664		if (ret < 0)
 665			return ret;
 666
 667		ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK, ret);
 668		*val = (ret - 75) * 1000;
 669		return 0;
 670	case hwmon_temp_max:
 671		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 672				   MDIO_MMD_PCS_MV_TEMP_SENSOR3);
 673		if (ret < 0)
 674			return ret;
 675
 676		ret = FIELD_GET(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
 677				ret);
 678		*val = (ret - 75) * 1000;
 679		return 0;
 680	case hwmon_temp_alarm:
 681		ret = phy_read_mmd(phydev, MDIO_MMD_PCS,
 682				   MDIO_MMD_PCS_MV_TEMP_SENSOR1);
 683		if (ret < 0)
 684			return ret;
 685
 686		*val = !!(ret & MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT);
 687		return 0;
 688	default:
 689		return -EOPNOTSUPP;
 690	}
 691}
 692
 693static int mv88q2xxx_hwmon_write(struct device *dev,
 694				 enum hwmon_sensor_types type, u32 attr,
 695				 int channel, long val)
 696{
 697	struct phy_device *phydev = dev_get_drvdata(dev);
 698
 699	switch (attr) {
 700	case hwmon_temp_max:
 701		val = clamp(val, -75000, 180000);
 702		val = (val / 1000) + 75;
 703		val = FIELD_PREP(MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
 704				 val);
 705		return phy_modify_mmd(phydev, MDIO_MMD_PCS,
 706				      MDIO_MMD_PCS_MV_TEMP_SENSOR3,
 707				      MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK,
 708				      val);
 709	default:
 710		return -EOPNOTSUPP;
 711	}
 712}
 713
 714static const struct hwmon_ops mv88q2xxx_hwmon_hwmon_ops = {
 715	.is_visible = mv88q2xxx_hwmon_is_visible,
 716	.read = mv88q2xxx_hwmon_read,
 717	.write = mv88q2xxx_hwmon_write,
 718};
 719
 720static const struct hwmon_chip_info mv88q2xxx_hwmon_chip_info = {
 721	.ops = &mv88q2xxx_hwmon_hwmon_ops,
 722	.info = mv88q2xxx_hwmon_info,
 723};
 724
 725static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
 726{
 727	struct device *dev = &phydev->mdio.dev;
 728	struct device *hwmon;
 729	int ret;
 730
 731	ret = mv88q2xxx_enable_temp_sense(phydev);
 732	if (ret < 0)
 733		return ret;
 734
 735	hwmon = devm_hwmon_device_register_with_info(dev, NULL, phydev,
 736						     &mv88q2xxx_hwmon_chip_info,
 737						     NULL);
 738
 739	return PTR_ERR_OR_ZERO(hwmon);
 740}
 741
 742#else
 743static int mv88q2xxx_enable_temp_sense(struct phy_device *phydev)
 744{
 745	return 0;
 746}
 747
 748static int mv88q2xxx_hwmon_probe(struct phy_device *phydev)
 749{
 750	return 0;
 751}
 752#endif
 753
 754#if IS_ENABLED(CONFIG_OF_MDIO)
 755static int mv88q2xxx_leds_probe(struct phy_device *phydev)
 756{
 757	struct device_node *node = phydev->mdio.dev.of_node;
 758	struct mv88q2xxx_priv *priv = phydev->priv;
 759	struct device_node *leds;
 760	int ret = 0;
 761	u32 index;
 762
 763	if (!node)
 764		return 0;
 765
 766	leds = of_get_child_by_name(node, "leds");
 767	if (!leds)
 768		return 0;
 769
 770	for_each_available_child_of_node_scoped(leds, led) {
 771		ret = of_property_read_u32(led, "reg", &index);
 772		if (ret)
 773			goto exit;
 774
 775		if (index > MV88Q2XXX_LED_INDEX_GPIO) {
 776			ret = -EINVAL;
 777			goto exit;
 778		}
 779
 780		if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE)
 781			priv->enable_led0 = true;
 782	}
 783
 784exit:
 785	of_node_put(leds);
 786
 787	return ret;
 788}
 789
 790#else
 791static int mv88q2xxx_leds_probe(struct phy_device *phydev)
 792{
 793	return 0;
 794}
 795#endif
 796
 797static int mv88q2xxx_probe(struct phy_device *phydev)
 798{
 799	struct mv88q2xxx_priv *priv;
 800	int ret;
 801
 802	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 803	if (!priv)
 804		return -ENOMEM;
 805
 806	phydev->priv = priv;
 807
 808	ret = mv88q2xxx_leds_probe(phydev);
 809	if (ret)
 810		return ret;
 811
 812	return mv88q2xxx_hwmon_probe(phydev);
 813}
 814
 815static int mv88q2xxx_config_init(struct phy_device *phydev)
 816{
 817	struct mv88q2xxx_priv *priv = phydev->priv;
 818	int ret;
 819
 820	/* The 88Q2XXX PHYs do have the extended ability register available, but
 821	 * register MDIO_PMA_EXTABLE where they should signalize it does not
 822	 * work according to specification. Therefore, we force it here.
 823	 */
 824	phydev->pma_extable = MDIO_PMA_EXTABLE_BT1;
 825
 826	/* Configure interrupt with default settings, output is driven low for
 827	 * active interrupt and high for inactive.
 828	 */
 829	if (phy_interrupt_is_valid(phydev)) {
 830		ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
 831				       MDIO_MMD_PCS_MV_GPIO_INT_CTRL,
 832				       MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS);
 833		if (ret < 0)
 834			return ret;
 835	}
 836
 837	/* Enable LED function and disable TX disable feature on LED/TX_ENABLE */
 838	if (priv->enable_led0) {
 839		ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS,
 840					 MDIO_MMD_PCS_MV_RESET_CTRL,
 841					 MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE);
 842		if (ret < 0)
 843			return ret;
 844	}
 845
 846	/* Enable temperature sense again. There might have been a hard reset
 847	 * of the PHY and in this case the register content is restored to
 848	 * defaults and we need to enable it again.
 849	 */
 850	ret = mv88q2xxx_enable_temp_sense(phydev);
 851	if (ret < 0)
 852		return ret;
 853
 854	return 0;
 855}
 856
 857static int mv88q2110_config_init(struct phy_device *phydev)
 858{
 859	int ret;
 860
 861	ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq0,
 862				       ARRAY_SIZE(mv88q2110_init_seq0));
 863	if (ret < 0)
 864		return ret;
 865
 866	usleep_range(5000, 10000);
 867
 868	ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq1,
 869				       ARRAY_SIZE(mv88q2110_init_seq1));
 870	if (ret < 0)
 871		return ret;
 872
 873	return mv88q2xxx_config_init(phydev);
 874}
 875
 876static int mv88q222x_revb0_config_init(struct phy_device *phydev)
 877{
 878	int ret;
 879
 880	ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0,
 881				       ARRAY_SIZE(mv88q222x_revb0_init_seq0));
 882	if (ret < 0)
 883		return ret;
 884
 885	usleep_range(5000, 10000);
 886
 887	ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1,
 888				       ARRAY_SIZE(mv88q222x_revb0_init_seq1));
 889	if (ret < 0)
 890		return ret;
 891
 892	return mv88q2xxx_config_init(phydev);
 893}
 894
 895static int mv88q222x_revb1_revb2_config_init(struct phy_device *phydev)
 896{
 897	bool is_rev_b1 = phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] == PHY_ID_88Q2220_REVB1;
 898	int ret;
 899
 900	if (is_rev_b1)
 901		ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0,
 902					       ARRAY_SIZE(mv88q222x_revb1_init_seq0));
 903	else
 904		ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0,
 905					       ARRAY_SIZE(mv88q222x_revb2_init_seq0));
 906	if (ret < 0)
 907		return ret;
 908
 909	usleep_range(3000, 5000);
 910
 911	ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1,
 912				       ARRAY_SIZE(mv88q222x_revb1_revb2_init_seq1));
 913	if (ret < 0)
 914		return ret;
 915
 916	return mv88q2xxx_config_init(phydev);
 917}
 918
 919static int mv88q222x_config_init(struct phy_device *phydev)
 920{
 921	if (phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] == PHY_ID_88Q2220_REVB0)
 922		return mv88q222x_revb0_config_init(phydev);
 923	else
 924		return mv88q222x_revb1_revb2_config_init(phydev);
 925}
 926
 927static int mv88q222x_cable_test_start(struct phy_device *phydev)
 928{
 929	int ret;
 930
 931	ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
 932			    MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF, 0x0058);
 933	if (ret < 0)
 934		return ret;
 935
 936	ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
 937			    MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE, 0x00eb);
 938	if (ret < 0)
 939		return ret;
 940
 941	ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
 942			    MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE, 0x010e);
 943	if (ret < 0)
 944		return ret;
 945
 946	ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
 947			    0x0d90);
 948	if (ret < 0)
 949		return ret;
 950
 951	ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS,
 952			    MDIO_MMD_PCS_MV_TDR_STATUS_ON);
 953	if (ret < 0)
 954		return ret;
 955
 956	/* According to the Marvell API the test is finished within 500 ms */
 957	msleep(500);
 958
 959	return 0;
 960}
 961
 962static int mv88q222x_cable_test_get_status(struct phy_device *phydev,
 963					   bool *finished)
 964{
 965	int ret, status;
 966	u32 dist;
 967
 968	status = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_STATUS);
 969	if (status < 0)
 970		return status;
 971
 972	ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_TDR_RESET,
 973			    MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST | 0xd90);
 974	if (ret < 0)
 975		return ret;
 976
 977	/* Test could not be finished */
 978	if (FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_MASK, status) !=
 979	    MDIO_MMD_PCS_MV_TDR_STATUS_OFF)
 980		return -ETIMEDOUT;
 981
 982	*finished = true;
 983	/* Fault length reported in meters, convert to centimeters */
 984	dist = FIELD_GET(MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK, status) * 100;
 985	switch (status & MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK) {
 986	case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN:
 987		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
 988					ETHTOOL_A_CABLE_RESULT_CODE_OPEN);
 989		ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
 990					      dist);
 991		break;
 992	case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT:
 993		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
 994					ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT);
 995		ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
 996					      dist);
 997		break;
 998	case MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK:
 999		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
1000					ETHTOOL_A_CABLE_RESULT_CODE_OK);
1001		break;
1002	default:
1003		ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
1004					ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
1005	}
1006
1007	return 0;
1008}
1009
1010static int mv88q2xxx_led_mode(u8 index, unsigned long rules)
1011{
1012	switch (rules) {
1013	case BIT(TRIGGER_NETDEV_LINK):
1014		return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK;
1015	case BIT(TRIGGER_NETDEV_LINK_1000):
1016		return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON;
1017	case BIT(TRIGGER_NETDEV_TX):
1018		return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX;
1019	case BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
1020		return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX;
1021	case BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
1022		return MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX;
1023	default:
1024		return -EOPNOTSUPP;
1025	}
1026}
1027
1028static int mv88q2xxx_led_hw_is_supported(struct phy_device *phydev, u8 index,
1029					 unsigned long rules)
1030{
1031	int mode;
1032
1033	mode = mv88q2xxx_led_mode(index, rules);
1034	if (mode < 0)
1035		return mode;
1036
1037	return 0;
1038}
1039
1040static int mv88q2xxx_led_hw_control_set(struct phy_device *phydev, u8 index,
1041					unsigned long rules)
1042{
1043	int mode;
1044
1045	mode = mv88q2xxx_led_mode(index, rules);
1046	if (mode < 0)
1047		return mode;
1048
1049	if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE)
1050		return phy_modify_mmd(phydev, MDIO_MMD_PCS,
1051				      MDIO_MMD_PCS_MV_LED_FUNC_CTRL,
1052				      MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK,
1053				      FIELD_PREP(MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK,
1054						 mode));
1055	else
1056		return phy_modify_mmd(phydev, MDIO_MMD_PCS,
1057				      MDIO_MMD_PCS_MV_LED_FUNC_CTRL,
1058				      MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK,
1059				      FIELD_PREP(MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK,
1060						 mode));
1061}
1062
1063static int mv88q2xxx_led_hw_control_get(struct phy_device *phydev, u8 index,
1064					unsigned long *rules)
1065{
1066	int val;
1067
1068	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_LED_FUNC_CTRL);
1069	if (val < 0)
1070		return val;
1071
1072	if (index == MV88Q2XXX_LED_INDEX_TX_ENABLE)
1073		val = FIELD_GET(MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK, val);
1074	else
1075		val = FIELD_GET(MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK, val);
1076
1077	switch (val) {
1078	case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK:
1079		*rules = BIT(TRIGGER_NETDEV_LINK);
1080		break;
1081	case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON:
1082		*rules = BIT(TRIGGER_NETDEV_LINK_1000);
1083		break;
1084	case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX:
1085		*rules = BIT(TRIGGER_NETDEV_TX);
1086		break;
1087	case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX:
1088		*rules = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
1089		break;
1090	case MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX:
1091		*rules = BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) |
1092			 BIT(TRIGGER_NETDEV_RX);
1093		break;
1094	default:
1095		*rules = 0;
1096		break;
1097	}
1098
1099	return 0;
1100}
1101
1102static struct phy_driver mv88q2xxx_driver[] = {
1103	{
1104		.phy_id			= MARVELL_PHY_ID_88Q2110,
1105		.phy_id_mask		= MARVELL_PHY_ID_MASK,
1106		.name			= "mv88q2110",
1107		.probe			= mv88q2xxx_probe,
1108		.get_features		= mv88q2xxx_get_features,
1109		.config_aneg		= mv88q2xxx_config_aneg,
1110		.config_init		= mv88q2110_config_init,
1111		.read_status		= mv88q2xxx_read_status,
1112		.soft_reset		= mv88q2xxx_soft_reset,
1113		.set_loopback		= genphy_c45_loopback,
1114		.get_sqi		= mv88q2xxx_get_sqi,
1115		.get_sqi_max		= mv88q2xxx_get_sqi_max,
1116	},
1117	{
1118		.phy_id			= MARVELL_PHY_ID_88Q2220,
1119		.phy_id_mask		= MARVELL_PHY_ID_MASK,
1120		.name			= "mv88q2220",
1121		.flags			= PHY_POLL_CABLE_TEST,
1122		.probe			= mv88q2xxx_probe,
1123		.get_features		= mv88q2xxx_get_features,
1124		.config_aneg		= mv88q2xxx_config_aneg,
1125		.aneg_done		= genphy_c45_aneg_done,
1126		.config_init		= mv88q222x_config_init,
1127		.read_status		= mv88q2xxx_read_status,
1128		.soft_reset		= mv88q2xxx_soft_reset,
1129		.config_intr		= mv88q2xxx_config_intr,
1130		.handle_interrupt	= mv88q2xxx_handle_interrupt,
1131		.set_loopback		= genphy_c45_loopback,
1132		.cable_test_start	= mv88q222x_cable_test_start,
1133		.cable_test_get_status	= mv88q222x_cable_test_get_status,
1134		.get_sqi		= mv88q2xxx_get_sqi,
1135		.get_sqi_max		= mv88q2xxx_get_sqi_max,
1136		.suspend		= mv88q2xxx_suspend,
1137		.resume			= mv88q2xxx_resume,
1138		.led_hw_is_supported	= mv88q2xxx_led_hw_is_supported,
1139		.led_hw_control_set	= mv88q2xxx_led_hw_control_set,
1140		.led_hw_control_get	= mv88q2xxx_led_hw_control_get,
1141	},
1142};
1143
1144module_phy_driver(mv88q2xxx_driver);
1145
1146static const struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
1147	{ MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
1148	{ MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK },
1149	{ /*sentinel*/ }
1150};
1151MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl);
1152
1153MODULE_DESCRIPTION("Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHY driver");
1154MODULE_LICENSE("GPL");
~/ Read-only file preview.