qca808x.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/phy.h>
  3. #include <linux/module.h>
  4. #include "qcom.h"
  5. /* ADC threshold */
  6. #define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
  7. #define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
  8. #define QCA808X_ADC_THRESHOLD_80MV 0
  9. #define QCA808X_ADC_THRESHOLD_100MV 0xf0
  10. #define QCA808X_ADC_THRESHOLD_200MV 0x0f
  11. #define QCA808X_ADC_THRESHOLD_300MV 0xff
  12. /* CLD control */
  13. #define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
  14. #define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
  15. #define QCA808X_8023AZ_AFE_EN 0x90
  16. /* AZ control */
  17. #define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
  18. #define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
  19. #define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
  20. #define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
  21. #define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
  22. #define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
  23. #define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
  24. #define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
  25. #define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
  26. #define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
  27. #define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
  28. #define QCA808X_TOP_OPTION1_DATA 0x0
  29. #define QCA808X_PHY_MMD3_DEBUG_1 0xa100
  30. #define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
  31. #define QCA808X_PHY_MMD3_DEBUG_2 0xa101
  32. #define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
  33. #define QCA808X_PHY_MMD3_DEBUG_3 0xa103
  34. #define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
  35. #define QCA808X_PHY_MMD3_DEBUG_4 0xa105
  36. #define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
  37. #define QCA808X_PHY_MMD3_DEBUG_5 0xa106
  38. #define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
  39. #define QCA808X_PHY_MMD3_DEBUG_6 0xa011
  40. #define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
  41. /* master/slave seed config */
  42. #define QCA808X_PHY_DEBUG_LOCAL_SEED 9
  43. #define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1)
  44. #define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2)
  45. #define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32
  46. /* Hibernation yields lower power consumpiton in contrast with normal operation mode.
  47. * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
  48. */
  49. #define QCA808X_DBG_AN_TEST 0xb
  50. #define QCA808X_HIBERNATION_EN BIT(15)
  51. #define QCA808X_MMD7_LED2_CTRL 0x8074
  52. #define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
  53. #define QCA808X_MMD7_LED1_CTRL 0x8076
  54. #define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077
  55. #define QCA808X_MMD7_LED0_CTRL 0x8078
  56. #define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
  57. #define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
  58. #define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
  59. #define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
  60. /* QSDK sets by default 0x46 to this reg that sets BIT 6 for
  61. * LED to active high. It's not clear what BIT 3 and BIT 4 does.
  62. */
  63. #define QCA808X_LED_ACTIVE_HIGH BIT(6)
  64. /* QCA808X 1G chip type */
  65. #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
  66. #define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
  67. #define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
  68. #define QCA8081_PHY_FIFO_RSTN BIT(11)
  69. #define QCA8081_PHY_ID 0x004dd101
  70. MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver");
  71. MODULE_AUTHOR("Matus Ujhelyi");
  72. MODULE_LICENSE("GPL");
  73. struct qca808x_priv {
  74. int led_polarity_mode;
  75. };
  76. static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
  77. {
  78. int ret;
  79. /* Enable fast retrain */
  80. ret = genphy_c45_fast_retrain(phydev, true);
  81. if (ret)
  82. return ret;
  83. phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
  84. QCA808X_TOP_OPTION1_DATA);
  85. phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
  86. QCA808X_MSE_THRESHOLD_20DB_VALUE);
  87. phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
  88. QCA808X_MSE_THRESHOLD_17DB_VALUE);
  89. phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
  90. QCA808X_MSE_THRESHOLD_27DB_VALUE);
  91. phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
  92. QCA808X_MSE_THRESHOLD_28DB_VALUE);
  93. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
  94. QCA808X_MMD3_DEBUG_1_VALUE);
  95. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
  96. QCA808X_MMD3_DEBUG_4_VALUE);
  97. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
  98. QCA808X_MMD3_DEBUG_5_VALUE);
  99. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
  100. QCA808X_MMD3_DEBUG_3_VALUE);
  101. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
  102. QCA808X_MMD3_DEBUG_6_VALUE);
  103. phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
  104. QCA808X_MMD3_DEBUG_2_VALUE);
  105. return 0;
  106. }
  107. static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
  108. {
  109. u16 seed_value;
  110. if (!enable)
  111. return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
  112. QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
  113. seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
  114. return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
  115. QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
  116. FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
  117. QCA808X_MASTER_SLAVE_SEED_ENABLE);
  118. }
  119. static bool qca808x_is_prefer_master(struct phy_device *phydev)
  120. {
  121. return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
  122. (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
  123. }
  124. static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
  125. {
  126. return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
  127. }
  128. static bool qca808x_is_1g_only(struct phy_device *phydev)
  129. {
  130. int ret;
  131. ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
  132. if (ret < 0)
  133. return true;
  134. return !!(QCA808X_PHY_CHIP_TYPE_1G & ret);
  135. }
  136. static void qca808x_fill_possible_interfaces(struct phy_device *phydev)
  137. {
  138. unsigned long *possible = phydev->possible_interfaces;
  139. __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
  140. if (!qca808x_is_1g_only(phydev))
  141. __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
  142. }
  143. static int qca808x_probe(struct phy_device *phydev)
  144. {
  145. struct device *dev = &phydev->mdio.dev;
  146. struct qca808x_priv *priv;
  147. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  148. if (!priv)
  149. return -ENOMEM;
  150. /* Init LED polarity mode to -1 */
  151. priv->led_polarity_mode = -1;
  152. phydev->priv = priv;
  153. return 0;
  154. }
  155. static int qca808x_config_init(struct phy_device *phydev)
  156. {
  157. struct qca808x_priv *priv = phydev->priv;
  158. int ret;
  159. /* Default to LED Active High if active-low not in DT */
  160. if (priv->led_polarity_mode == -1) {
  161. ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN,
  162. QCA808X_MMD7_LED_POLARITY_CTRL,
  163. QCA808X_LED_ACTIVE_HIGH);
  164. if (ret)
  165. return ret;
  166. }
  167. /* Active adc&vga on 802.3az for the link 1000M and 100M */
  168. ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
  169. QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
  170. if (ret)
  171. return ret;
  172. /* Adjust the threshold on 802.3az for the link 1000M */
  173. ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
  174. QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
  175. QCA808X_MMD3_AZ_TRAINING_VAL);
  176. if (ret)
  177. return ret;
  178. if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
  179. /* Config the fast retrain for the link 2500M */
  180. ret = qca808x_phy_fast_retrain_config(phydev);
  181. if (ret)
  182. return ret;
  183. ret = genphy_read_master_slave(phydev);
  184. if (ret < 0)
  185. return ret;
  186. if (!qca808x_is_prefer_master(phydev)) {
  187. /* Enable seed and configure lower ramdom seed to make phy
  188. * linked as slave mode.
  189. */
  190. ret = qca808x_phy_ms_seed_enable(phydev, true);
  191. if (ret)
  192. return ret;
  193. }
  194. }
  195. qca808x_fill_possible_interfaces(phydev);
  196. /* Configure adc threshold as 100mv for the link 10M */
  197. return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
  198. QCA808X_ADC_THRESHOLD_MASK,
  199. QCA808X_ADC_THRESHOLD_100MV);
  200. }
  201. static int qca808x_read_status(struct phy_device *phydev)
  202. {
  203. struct at803x_ss_mask ss_mask = { 0 };
  204. int ret;
  205. ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
  206. if (ret < 0)
  207. return ret;
  208. linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
  209. ret & MDIO_AN_10GBT_STAT_LP2_5G);
  210. ret = genphy_read_status(phydev);
  211. if (ret)
  212. return ret;
  213. /* qca8081 takes the different bits for speed value from at803x */
  214. ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
  215. ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
  216. ret = at803x_read_specific_status(phydev, ss_mask);
  217. if (ret < 0)
  218. return ret;
  219. if (phydev->link) {
  220. if (phydev->speed == SPEED_2500)
  221. phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
  222. else
  223. phydev->interface = PHY_INTERFACE_MODE_SGMII;
  224. } else {
  225. /* generate seed as a lower random value to make PHY linked as SLAVE easily,
  226. * except for master/slave configuration fault detected or the master mode
  227. * preferred.
  228. *
  229. * the reason for not putting this code into the function link_change_notify is
  230. * the corner case where the link partner is also the qca8081 PHY and the seed
  231. * value is configured as the same value, the link can't be up and no link change
  232. * occurs.
  233. */
  234. if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
  235. if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
  236. qca808x_is_prefer_master(phydev)) {
  237. qca808x_phy_ms_seed_enable(phydev, false);
  238. } else {
  239. qca808x_phy_ms_seed_enable(phydev, true);
  240. }
  241. }
  242. }
  243. return 0;
  244. }
  245. static int qca808x_soft_reset(struct phy_device *phydev)
  246. {
  247. int ret;
  248. ret = genphy_soft_reset(phydev);
  249. if (ret < 0)
  250. return ret;
  251. if (qca808x_has_fast_retrain_or_slave_seed(phydev))
  252. ret = qca808x_phy_ms_seed_enable(phydev, true);
  253. return ret;
  254. }
  255. static int qca808x_cable_test_start(struct phy_device *phydev)
  256. {
  257. int ret;
  258. /* perform CDT with the following configs:
  259. * 1. disable hibernation.
  260. * 2. force PHY working in MDI mode.
  261. * 3. for PHY working in 1000BaseT.
  262. * 4. configure the threshold.
  263. */
  264. ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0);
  265. if (ret < 0)
  266. return ret;
  267. ret = at803x_config_mdix(phydev, ETH_TP_MDI);
  268. if (ret < 0)
  269. return ret;
  270. /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
  271. phydev->duplex = DUPLEX_FULL;
  272. phydev->speed = SPEED_1000;
  273. ret = genphy_c45_pma_setup_forced(phydev);
  274. if (ret < 0)
  275. return ret;
  276. ret = genphy_setup_forced(phydev);
  277. if (ret < 0)
  278. return ret;
  279. /* configure the thresholds for open, short, pair ok test */
  280. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
  281. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
  282. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
  283. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
  284. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
  285. phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
  286. return 0;
  287. }
  288. static int qca808x_get_features(struct phy_device *phydev)
  289. {
  290. int ret;
  291. ret = genphy_c45_pma_read_abilities(phydev);
  292. if (ret)
  293. return ret;
  294. /* The autoneg ability is not existed in bit3 of MMD7.1,
  295. * but it is supported by qca808x PHY, so we add it here
  296. * manually.
  297. */
  298. linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
  299. /* As for the qca8081 1G version chip, the 2500baseT ability is also
  300. * existed in the bit0 of MMD1.21, we need to remove it manually if
  301. * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
  302. */
  303. if (qca808x_is_1g_only(phydev))
  304. linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
  305. return 0;
  306. }
  307. static int qca808x_config_aneg(struct phy_device *phydev)
  308. {
  309. int phy_ctrl = 0;
  310. int ret;
  311. ret = at803x_prepare_config_aneg(phydev);
  312. if (ret)
  313. return ret;
  314. /* The reg MII_BMCR also needs to be configured for force mode, the
  315. * genphy_config_aneg is also needed.
  316. */
  317. if (phydev->autoneg == AUTONEG_DISABLE)
  318. genphy_c45_pma_setup_forced(phydev);
  319. if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
  320. phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
  321. ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
  322. MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
  323. if (ret < 0)
  324. return ret;
  325. return __genphy_config_aneg(phydev, ret);
  326. }
  327. static void qca808x_link_change_notify(struct phy_device *phydev)
  328. {
  329. /* Assert interface sgmii fifo on link down, deassert it on link up,
  330. * the interface device address is always phy address added by 1.
  331. */
  332. mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
  333. MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
  334. QCA8081_PHY_FIFO_RSTN,
  335. phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
  336. }
  337. static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
  338. u16 *offload_trigger)
  339. {
  340. /* Parsing specific to netdev trigger */
  341. if (test_bit(TRIGGER_NETDEV_TX, &rules))
  342. *offload_trigger |= QCA808X_LED_TX_BLINK;
  343. if (test_bit(TRIGGER_NETDEV_RX, &rules))
  344. *offload_trigger |= QCA808X_LED_RX_BLINK;
  345. if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
  346. *offload_trigger |= QCA808X_LED_SPEED10_ON;
  347. if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
  348. *offload_trigger |= QCA808X_LED_SPEED100_ON;
  349. if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
  350. *offload_trigger |= QCA808X_LED_SPEED1000_ON;
  351. if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
  352. *offload_trigger |= QCA808X_LED_SPEED2500_ON;
  353. if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
  354. *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
  355. if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
  356. *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
  357. if (rules && !*offload_trigger)
  358. return -EOPNOTSUPP;
  359. /* Enable BLINK_CHECK_BYPASS by default to make the LED
  360. * blink even with duplex or speed mode not enabled.
  361. */
  362. *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
  363. return 0;
  364. }
  365. static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index)
  366. {
  367. u16 reg;
  368. if (index > 2)
  369. return -EINVAL;
  370. reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
  371. return qca808x_led_reg_hw_control_enable(phydev, reg);
  372. }
  373. static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
  374. unsigned long rules)
  375. {
  376. u16 offload_trigger = 0;
  377. if (index > 2)
  378. return -EINVAL;
  379. return qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
  380. }
  381. static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index,
  382. unsigned long rules)
  383. {
  384. u16 reg, offload_trigger = 0;
  385. int ret;
  386. if (index > 2)
  387. return -EINVAL;
  388. reg = QCA808X_MMD7_LED_CTRL(index);
  389. ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger);
  390. if (ret)
  391. return ret;
  392. ret = qca808x_led_hw_control_enable(phydev, index);
  393. if (ret)
  394. return ret;
  395. return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
  396. QCA808X_LED_PATTERN_MASK,
  397. offload_trigger);
  398. }
  399. static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
  400. {
  401. u16 reg;
  402. if (index > 2)
  403. return false;
  404. reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
  405. return qca808x_led_reg_hw_control_status(phydev, reg);
  406. }
  407. static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
  408. unsigned long *rules)
  409. {
  410. u16 reg;
  411. int val;
  412. if (index > 2)
  413. return -EINVAL;
  414. /* Check if we have hw control enabled */
  415. if (qca808x_led_hw_control_status(phydev, index))
  416. return -EINVAL;
  417. reg = QCA808X_MMD7_LED_CTRL(index);
  418. val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
  419. if (val & QCA808X_LED_TX_BLINK)
  420. set_bit(TRIGGER_NETDEV_TX, rules);
  421. if (val & QCA808X_LED_RX_BLINK)
  422. set_bit(TRIGGER_NETDEV_RX, rules);
  423. if (val & QCA808X_LED_SPEED10_ON)
  424. set_bit(TRIGGER_NETDEV_LINK_10, rules);
  425. if (val & QCA808X_LED_SPEED100_ON)
  426. set_bit(TRIGGER_NETDEV_LINK_100, rules);
  427. if (val & QCA808X_LED_SPEED1000_ON)
  428. set_bit(TRIGGER_NETDEV_LINK_1000, rules);
  429. if (val & QCA808X_LED_SPEED2500_ON)
  430. set_bit(TRIGGER_NETDEV_LINK_2500, rules);
  431. if (val & QCA808X_LED_HALF_DUPLEX_ON)
  432. set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
  433. if (val & QCA808X_LED_FULL_DUPLEX_ON)
  434. set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
  435. return 0;
  436. }
  437. static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index)
  438. {
  439. u16 reg;
  440. if (index > 2)
  441. return -EINVAL;
  442. reg = QCA808X_MMD7_LED_CTRL(index);
  443. return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
  444. QCA808X_LED_PATTERN_MASK);
  445. }
  446. static int qca808x_led_brightness_set(struct phy_device *phydev,
  447. u8 index, enum led_brightness value)
  448. {
  449. u16 reg;
  450. int ret;
  451. if (index > 2)
  452. return -EINVAL;
  453. if (!value) {
  454. ret = qca808x_led_hw_control_reset(phydev, index);
  455. if (ret)
  456. return ret;
  457. }
  458. reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
  459. return qca808x_led_reg_brightness_set(phydev, reg, value);
  460. }
  461. static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
  462. unsigned long *delay_on,
  463. unsigned long *delay_off)
  464. {
  465. u16 reg;
  466. if (index > 2)
  467. return -EINVAL;
  468. reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
  469. return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
  470. }
  471. static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
  472. unsigned long modes)
  473. {
  474. struct qca808x_priv *priv = phydev->priv;
  475. bool active_low = false;
  476. u32 mode;
  477. for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
  478. switch (mode) {
  479. case PHY_LED_ACTIVE_LOW:
  480. active_low = true;
  481. break;
  482. default:
  483. return -EINVAL;
  484. }
  485. }
  486. /* PHY polarity is global and can't be set per LED.
  487. * To detect this, check if last requested polarity mode
  488. * match the new one.
  489. */
  490. if (priv->led_polarity_mode >= 0 &&
  491. priv->led_polarity_mode != active_low) {
  492. phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n");
  493. return -EINVAL;
  494. }
  495. /* Save the last PHY polarity mode */
  496. priv->led_polarity_mode = active_low;
  497. return phy_modify_mmd(phydev, MDIO_MMD_AN,
  498. QCA808X_MMD7_LED_POLARITY_CTRL,
  499. QCA808X_LED_ACTIVE_HIGH,
  500. active_low ? 0 : QCA808X_LED_ACTIVE_HIGH);
  501. }
  502. static struct phy_driver qca808x_driver[] = {
  503. {
  504. /* Qualcomm QCA8081 */
  505. PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
  506. .name = "Qualcomm QCA8081",
  507. .flags = PHY_POLL_CABLE_TEST,
  508. .probe = qca808x_probe,
  509. .config_intr = at803x_config_intr,
  510. .handle_interrupt = at803x_handle_interrupt,
  511. .get_tunable = at803x_get_tunable,
  512. .set_tunable = at803x_set_tunable,
  513. .set_wol = at8031_set_wol,
  514. .get_wol = at803x_get_wol,
  515. .get_features = qca808x_get_features,
  516. .config_aneg = qca808x_config_aneg,
  517. .suspend = genphy_suspend,
  518. .resume = genphy_resume,
  519. .read_status = qca808x_read_status,
  520. .config_init = qca808x_config_init,
  521. .soft_reset = qca808x_soft_reset,
  522. .cable_test_start = qca808x_cable_test_start,
  523. .cable_test_get_status = qca808x_cable_test_get_status,
  524. .link_change_notify = qca808x_link_change_notify,
  525. .led_brightness_set = qca808x_led_brightness_set,
  526. .led_blink_set = qca808x_led_blink_set,
  527. .led_hw_is_supported = qca808x_led_hw_is_supported,
  528. .led_hw_control_set = qca808x_led_hw_control_set,
  529. .led_hw_control_get = qca808x_led_hw_control_get,
  530. .led_polarity_set = qca808x_led_polarity_set,
  531. }, };
  532. module_phy_driver(qca808x_driver);
  533. static struct mdio_device_id __maybe_unused qca808x_tbl[] = {
  534. { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
  535. { }
  536. };
  537. MODULE_DEVICE_TABLE(mdio, qca808x_tbl);