brintos

brintos / linux-shallow public Read only

0
0
Text · 18.5 KiB · 5048304 Raw
664 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <linux/phy.h>4#include <linux/module.h>5 6#include "qcom.h"7 8/* ADC threshold */9#define QCA808X_PHY_DEBUG_ADC_THRESHOLD		0x2c8010#define QCA808X_ADC_THRESHOLD_MASK		GENMASK(7, 0)11#define QCA808X_ADC_THRESHOLD_80MV		012#define QCA808X_ADC_THRESHOLD_100MV		0xf013#define QCA808X_ADC_THRESHOLD_200MV		0x0f14#define QCA808X_ADC_THRESHOLD_300MV		0xff15 16/* CLD control */17#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7		0x800718#define QCA808X_8023AZ_AFE_CTRL_MASK		GENMASK(8, 4)19#define QCA808X_8023AZ_AFE_EN			0x9020 21/* AZ control */22#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL	0x800823#define QCA808X_MMD3_AZ_TRAINING_VAL		0x1c3224 25#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB	0x801426#define QCA808X_MSE_THRESHOLD_20DB_VALUE	0x52927 28#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB	0x800E29#define QCA808X_MSE_THRESHOLD_17DB_VALUE	0x34130 31#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB	0x801E32#define QCA808X_MSE_THRESHOLD_27DB_VALUE	0x41933 34#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB	0x802035#define QCA808X_MSE_THRESHOLD_28DB_VALUE	0x34136 37#define QCA808X_PHY_MMD7_TOP_OPTION1		0x901c38#define QCA808X_TOP_OPTION1_DATA		0x039 40#define QCA808X_PHY_MMD3_DEBUG_1		0xa10041#define QCA808X_MMD3_DEBUG_1_VALUE		0x920342#define QCA808X_PHY_MMD3_DEBUG_2		0xa10143#define QCA808X_MMD3_DEBUG_2_VALUE		0x48ad44#define QCA808X_PHY_MMD3_DEBUG_3		0xa10345#define QCA808X_MMD3_DEBUG_3_VALUE		0x169846#define QCA808X_PHY_MMD3_DEBUG_4		0xa10547#define QCA808X_MMD3_DEBUG_4_VALUE		0x800148#define QCA808X_PHY_MMD3_DEBUG_5		0xa10649#define QCA808X_MMD3_DEBUG_5_VALUE		0x111150#define QCA808X_PHY_MMD3_DEBUG_6		0xa01151#define QCA808X_MMD3_DEBUG_6_VALUE		0x5f8552 53/* master/slave seed config */54#define QCA808X_PHY_DEBUG_LOCAL_SEED		955#define QCA808X_MASTER_SLAVE_SEED_ENABLE	BIT(1)56#define QCA808X_MASTER_SLAVE_SEED_CFG		GENMASK(12, 2)57#define QCA808X_MASTER_SLAVE_SEED_RANGE		0x3258 59/* Hibernation yields lower power consumpiton in contrast with normal operation mode.60 * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.61 */62#define QCA808X_DBG_AN_TEST			0xb63#define QCA808X_HIBERNATION_EN			BIT(15)64 65#define QCA808X_MMD7_LED2_CTRL			0x807466#define QCA808X_MMD7_LED2_FORCE_CTRL		0x807567#define QCA808X_MMD7_LED1_CTRL			0x807668#define QCA808X_MMD7_LED1_FORCE_CTRL		0x807769#define QCA808X_MMD7_LED0_CTRL			0x807870#define QCA808X_MMD7_LED_CTRL(x)		(0x8078 - ((x) * 2))71 72#define QCA808X_MMD7_LED0_FORCE_CTRL		0x807973#define QCA808X_MMD7_LED_FORCE_CTRL(x)		(0x8079 - ((x) * 2))74 75#define QCA808X_MMD7_LED_POLARITY_CTRL		0x901a76/* QSDK sets by default 0x46 to this reg that sets BIT 6 for77 * LED to active high. It's not clear what BIT 3 and BIT 4 does.78 */79#define QCA808X_LED_ACTIVE_HIGH			BIT(6)80 81/* QCA808X 1G chip type */82#define QCA808X_PHY_MMD7_CHIP_TYPE		0x901d83#define QCA808X_PHY_CHIP_TYPE_1G		BIT(0)84 85#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL	0x907286#define QCA8081_PHY_FIFO_RSTN			BIT(11)87 88#define QCA8081_PHY_ID				0x004dd10189 90MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");91MODULE_AUTHOR("Matus Ujhelyi");92MODULE_LICENSE("GPL");93 94struct qca808x_priv {95	int led_polarity_mode;96};97 98static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)99{100	int ret;101 102	/* Enable fast retrain */103	ret = genphy_c45_fast_retrain(phydev, true);104	if (ret)105		return ret;106 107	phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,108		      QCA808X_TOP_OPTION1_DATA);109	phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,110		      QCA808X_MSE_THRESHOLD_20DB_VALUE);111	phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,112		      QCA808X_MSE_THRESHOLD_17DB_VALUE);113	phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,114		      QCA808X_MSE_THRESHOLD_27DB_VALUE);115	phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,116		      QCA808X_MSE_THRESHOLD_28DB_VALUE);117	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,118		      QCA808X_MMD3_DEBUG_1_VALUE);119	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,120		      QCA808X_MMD3_DEBUG_4_VALUE);121	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,122		      QCA808X_MMD3_DEBUG_5_VALUE);123	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,124		      QCA808X_MMD3_DEBUG_3_VALUE);125	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,126		      QCA808X_MMD3_DEBUG_6_VALUE);127	phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,128		      QCA808X_MMD3_DEBUG_2_VALUE);129 130	return 0;131}132 133static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)134{135	u16 seed_value;136 137	if (!enable)138		return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,139				QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);140 141	seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);142	return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,143			QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,144			FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |145			QCA808X_MASTER_SLAVE_SEED_ENABLE);146}147 148static bool qca808x_is_prefer_master(struct phy_device *phydev)149{150	return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||151		(phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);152}153 154static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)155{156	return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);157}158 159static bool qca808x_is_1g_only(struct phy_device *phydev)160{161	int ret;162 163	ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);164	if (ret < 0)165		return true;166 167	return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);168}169 170static void qca808x_fill_possible_interfaces(struct phy_device *phydev)171{172	unsigned long *possible = phydev->possible_interfaces;173 174	__set_bit(PHY_INTERFACE_MODE_SGMII, possible);175 176	if (!qca808x_is_1g_only(phydev))177		__set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);178}179 180static int qca808x_probe(struct phy_device *phydev)181{182	struct device *dev = &phydev->mdio.dev;183	struct qca808x_priv *priv;184 185	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);186	if (!priv)187		return -ENOMEM;188 189	/* Init LED polarity mode to -1 */190	priv->led_polarity_mode = -1;191 192	phydev->priv = priv;193 194	return 0;195}196 197static int qca808x_config_init(struct phy_device *phydev)198{199	struct qca808x_priv *priv = phydev->priv;200	int ret;201 202	/* Default to LED Active High if active-low not in DT */203	if (priv->led_polarity_mode == -1) {204		ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN,205				       QCA808X_MMD7_LED_POLARITY_CTRL,206				       QCA808X_LED_ACTIVE_HIGH);207		if (ret)208			return ret;209	}210 211	/* Active adc&vga on 802.3az for the link 1000M and 100M */212	ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,213			     QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);214	if (ret)215		return ret;216 217	/* Adjust the threshold on 802.3az for the link 1000M */218	ret = phy_write_mmd(phydev, MDIO_MMD_PCS,219			    QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,220			    QCA808X_MMD3_AZ_TRAINING_VAL);221	if (ret)222		return ret;223 224	if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {225		/* Config the fast retrain for the link 2500M */226		ret = qca808x_phy_fast_retrain_config(phydev);227		if (ret)228			return ret;229 230		ret = genphy_read_master_slave(phydev);231		if (ret < 0)232			return ret;233 234		if (!qca808x_is_prefer_master(phydev)) {235			/* Enable seed and configure lower ramdom seed to make phy236			 * linked as slave mode.237			 */238			ret = qca808x_phy_ms_seed_enable(phydev, true);239			if (ret)240				return ret;241		}242	}243 244	qca808x_fill_possible_interfaces(phydev);245 246	/* Configure adc threshold as 100mv for the link 10M */247	return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,248				     QCA808X_ADC_THRESHOLD_MASK,249				     QCA808X_ADC_THRESHOLD_100MV);250}251 252static int qca808x_read_status(struct phy_device *phydev)253{254	struct at803x_ss_mask ss_mask = { 0 };255	int ret;256 257	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);258	if (ret < 0)259		return ret;260 261	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,262			 ret & MDIO_AN_10GBT_STAT_LP2_5G);263 264	ret = genphy_read_status(phydev);265	if (ret)266		return ret;267 268	/* qca8081 takes the different bits for speed value from at803x */269	ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;270	ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);271	ret = at803x_read_specific_status(phydev, ss_mask);272	if (ret < 0)273		return ret;274 275	if (phydev->link) {276		if (phydev->speed == SPEED_2500)277			phydev->interface = PHY_INTERFACE_MODE_2500BASEX;278		else279			phydev->interface = PHY_INTERFACE_MODE_SGMII;280	} else {281		/* generate seed as a lower random value to make PHY linked as SLAVE easily,282		 * except for master/slave configuration fault detected or the master mode283		 * preferred.284		 *285		 * the reason for not putting this code into the function link_change_notify is286		 * the corner case where the link partner is also the qca8081 PHY and the seed287		 * value is configured as the same value, the link can't be up and no link change288		 * occurs.289		 */290		if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {291			if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||292			    qca808x_is_prefer_master(phydev)) {293				qca808x_phy_ms_seed_enable(phydev, false);294			} else {295				qca808x_phy_ms_seed_enable(phydev, true);296			}297		}298	}299 300	return 0;301}302 303static int qca808x_soft_reset(struct phy_device *phydev)304{305	int ret;306 307	ret = genphy_soft_reset(phydev);308	if (ret < 0)309		return ret;310 311	if (qca808x_has_fast_retrain_or_slave_seed(phydev))312		ret = qca808x_phy_ms_seed_enable(phydev, true);313 314	return ret;315}316 317static int qca808x_cable_test_start(struct phy_device *phydev)318{319	int ret;320 321	/* perform CDT with the following configs:322	 * 1. disable hibernation.323	 * 2. force PHY working in MDI mode.324	 * 3. for PHY working in 1000BaseT.325	 * 4. configure the threshold.326	 */327 328	ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);329	if (ret < 0)330		return ret;331 332	ret = at803x_config_mdix(phydev, ETH_TP_MDI);333	if (ret < 0)334		return ret;335 336	/* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */337	phydev->duplex = DUPLEX_FULL;338	phydev->speed = SPEED_1000;339	ret = genphy_c45_pma_setup_forced(phydev);340	if (ret < 0)341		return ret;342 343	ret = genphy_setup_forced(phydev);344	if (ret < 0)345		return ret;346 347	/* configure the thresholds for open, short, pair ok test */348	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);349	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);350	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);351	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);352	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);353	phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);354 355	return 0;356}357 358static int qca808x_get_features(struct phy_device *phydev)359{360	int ret;361 362	ret = genphy_c45_pma_read_abilities(phydev);363	if (ret)364		return ret;365 366	/* The autoneg ability is not existed in bit3 of MMD7.1,367	 * but it is supported by qca808x PHY, so we add it here368	 * manually.369	 */370	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);371 372	/* As for the qca8081 1G version chip, the 2500baseT ability is also373	 * existed in the bit0 of MMD1.21, we need to remove it manually if374	 * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.375	 */376	if (qca808x_is_1g_only(phydev))377		linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);378 379	return 0;380}381 382static int qca808x_config_aneg(struct phy_device *phydev)383{384	int phy_ctrl = 0;385	int ret;386 387	ret = at803x_prepare_config_aneg(phydev);388	if (ret)389		return ret;390 391	/* The reg MII_BMCR also needs to be configured for force mode, the392	 * genphy_config_aneg is also needed.393	 */394	if (phydev->autoneg == AUTONEG_DISABLE)395		genphy_c45_pma_setup_forced(phydev);396 397	if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))398		phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;399 400	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,401				     MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);402	if (ret < 0)403		return ret;404 405	return __genphy_config_aneg(phydev, ret);406}407 408static void qca808x_link_change_notify(struct phy_device *phydev)409{410	/* Assert interface sgmii fifo on link down, deassert it on link up,411	 * the interface device address is always phy address added by 1.412	 */413	mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,414				   MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,415				   QCA8081_PHY_FIFO_RSTN,416				   phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);417}418 419static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,420				    u16 *offload_trigger)421{422	/* Parsing specific to netdev trigger */423	if (test_bit(TRIGGER_NETDEV_TX, &rules))424		*offload_trigger |= QCA808X_LED_TX_BLINK;425	if (test_bit(TRIGGER_NETDEV_RX, &rules))426		*offload_trigger |= QCA808X_LED_RX_BLINK;427	if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))428		*offload_trigger |= QCA808X_LED_SPEED10_ON;429	if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))430		*offload_trigger |= QCA808X_LED_SPEED100_ON;431	if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))432		*offload_trigger |= QCA808X_LED_SPEED1000_ON;433	if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))434		*offload_trigger |= QCA808X_LED_SPEED2500_ON;435	if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))436		*offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;437	if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))438		*offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;439 440	if (rules && !*offload_trigger)441		return -EOPNOTSUPP;442 443	/* Enable BLINK_CHECK_BYPASS by default to make the LED444	 * blink even with duplex or speed mode not enabled.445	 */446	*offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;447 448	return 0;449}450 451static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)452{453	u16 reg;454 455	if (index > 2)456		return -EINVAL;457 458	reg = QCA808X_MMD7_LED_FORCE_CTRL(index);459	return qca808x_led_reg_hw_control_enable(phydev, reg);460}461 462static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,463				       unsigned long rules)464{465	u16 offload_trigger = 0;466 467	if (index > 2)468		return -EINVAL;469 470	return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);471}472 473static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,474				      unsigned long rules)475{476	u16 reg, offload_trigger = 0;477	int ret;478 479	if (index > 2)480		return -EINVAL;481 482	reg = QCA808X_MMD7_LED_CTRL(index);483 484	ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);485	if (ret)486		return ret;487 488	ret = qca808x_led_hw_control_enable(phydev, index);489	if (ret)490		return ret;491 492	return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,493			      QCA808X_LED_PATTERN_MASK,494			      offload_trigger);495}496 497static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)498{499	u16 reg;500 501	if (index > 2)502		return false;503 504	reg = QCA808X_MMD7_LED_FORCE_CTRL(index);505	return qca808x_led_reg_hw_control_status(phydev, reg);506}507 508static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,509				      unsigned long *rules)510{511	u16 reg;512	int val;513 514	if (index > 2)515		return -EINVAL;516 517	/* Check if we have hw control enabled */518	if (qca808x_led_hw_control_status(phydev, index))519		return -EINVAL;520 521	reg = QCA808X_MMD7_LED_CTRL(index);522 523	val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);524	if (val & QCA808X_LED_TX_BLINK)525		set_bit(TRIGGER_NETDEV_TX, rules);526	if (val & QCA808X_LED_RX_BLINK)527		set_bit(TRIGGER_NETDEV_RX, rules);528	if (val & QCA808X_LED_SPEED10_ON)529		set_bit(TRIGGER_NETDEV_LINK_10, rules);530	if (val & QCA808X_LED_SPEED100_ON)531		set_bit(TRIGGER_NETDEV_LINK_100, rules);532	if (val & QCA808X_LED_SPEED1000_ON)533		set_bit(TRIGGER_NETDEV_LINK_1000, rules);534	if (val & QCA808X_LED_SPEED2500_ON)535		set_bit(TRIGGER_NETDEV_LINK_2500, rules);536	if (val & QCA808X_LED_HALF_DUPLEX_ON)537		set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);538	if (val & QCA808X_LED_FULL_DUPLEX_ON)539		set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);540 541	return 0;542}543 544static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)545{546	u16 reg;547 548	if (index > 2)549		return -EINVAL;550 551	reg = QCA808X_MMD7_LED_CTRL(index);552 553	return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,554				  QCA808X_LED_PATTERN_MASK);555}556 557static int qca808x_led_brightness_set(struct phy_device *phydev,558				      u8 index, enum led_brightness value)559{560	u16 reg;561	int ret;562 563	if (index > 2)564		return -EINVAL;565 566	if (!value) {567		ret = qca808x_led_hw_control_reset(phydev, index);568		if (ret)569			return ret;570	}571 572	reg = QCA808X_MMD7_LED_FORCE_CTRL(index);573	return qca808x_led_reg_brightness_set(phydev, reg, value);574}575 576static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,577				 unsigned long *delay_on,578				 unsigned long *delay_off)579{580	u16 reg;581 582	if (index > 2)583		return -EINVAL;584 585	reg = QCA808X_MMD7_LED_FORCE_CTRL(index);586	return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);587}588 589static int qca808x_led_polarity_set(struct phy_device *phydev, int index,590				    unsigned long modes)591{592	struct qca808x_priv *priv = phydev->priv;593	bool active_low = false;594	u32 mode;595 596	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {597		switch (mode) {598		case PHY_LED_ACTIVE_LOW:599			active_low = true;600			break;601		default:602			return -EINVAL;603		}604	}605 606	/* PHY polarity is global and can't be set per LED.607	 * To detect this, check if last requested polarity mode608	 * match the new one.609	 */610	if (priv->led_polarity_mode >= 0 &&611	    priv->led_polarity_mode != active_low) {612		phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");613		return -EINVAL;614	}615 616	/* Save the last PHY polarity mode */617	priv->led_polarity_mode = active_low;618 619	return phy_modify_mmd(phydev, MDIO_MMD_AN,620			      QCA808X_MMD7_LED_POLARITY_CTRL,621			      QCA808X_LED_ACTIVE_HIGH,622			      active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);623}624 625static struct phy_driver qca808x_driver[] = {626{627	/* Qualcomm QCA8081 */628	PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),629	.name			= "Qualcomm QCA8081",630	.flags			= PHY_POLL_CABLE_TEST,631	.probe			= qca808x_probe,632	.config_intr		= at803x_config_intr,633	.handle_interrupt	= at803x_handle_interrupt,634	.get_tunable		= at803x_get_tunable,635	.set_tunable		= at803x_set_tunable,636	.set_wol		= at803x_set_wol,637	.get_wol		= at803x_get_wol,638	.get_features		= qca808x_get_features,639	.config_aneg		= qca808x_config_aneg,640	.suspend		= genphy_suspend,641	.resume			= genphy_resume,642	.read_status		= qca808x_read_status,643	.config_init		= qca808x_config_init,644	.soft_reset		= qca808x_soft_reset,645	.cable_test_start	= qca808x_cable_test_start,646	.cable_test_get_status	= qca808x_cable_test_get_status,647	.link_change_notify	= qca808x_link_change_notify,648	.led_brightness_set	= qca808x_led_brightness_set,649	.led_blink_set		= qca808x_led_blink_set,650	.led_hw_is_supported	= qca808x_led_hw_is_supported,651	.led_hw_control_set	= qca808x_led_hw_control_set,652	.led_hw_control_get	= qca808x_led_hw_control_get,653	.led_polarity_set	= qca808x_led_polarity_set,654}, };655 656module_phy_driver(qca808x_driver);657 658static struct mdio_device_id __maybe_unused qca808x_tbl[] = {659	{ PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },660	{ }661};662 663MODULE_DEVICE_TABLE(mdio, qca808x_tbl);664