1fdb9bf7fSAngeloGioacchino Del Regno // SPDX-License-Identifier: GPL-2.0+ 2fdb9bf7fSAngeloGioacchino Del Regno /* 3fdb9bf7fSAngeloGioacchino Del Regno * Driver for the Airoha AN8801 Gigabit PHY. 4fdb9bf7fSAngeloGioacchino Del Regno * 5fdb9bf7fSAngeloGioacchino Del Regno * Copyright (C) 2025 Airoha Technology Corp. 6fdb9bf7fSAngeloGioacchino Del Regno * Copyright (C) 2025 Collabora Ltd. 7fdb9bf7fSAngeloGioacchino Del Regno * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 8fdb9bf7fSAngeloGioacchino Del Regno */ 9fdb9bf7fSAngeloGioacchino Del Regno 10fdb9bf7fSAngeloGioacchino Del Regno #include <linux/bitfield.h> 11fdb9bf7fSAngeloGioacchino Del Regno #include <linux/bitops.h> 12fdb9bf7fSAngeloGioacchino Del Regno #include <linux/delay.h> 13fdb9bf7fSAngeloGioacchino Del Regno #include <linux/errno.h> 14fdb9bf7fSAngeloGioacchino Del Regno #include <linux/etherdevice.h> 15fdb9bf7fSAngeloGioacchino Del Regno #include <linux/init.h> 16fdb9bf7fSAngeloGioacchino Del Regno #include <linux/minmax.h> 17fdb9bf7fSAngeloGioacchino Del Regno #include <linux/netdevice.h> 18fdb9bf7fSAngeloGioacchino Del Regno #include <linux/of.h> 19fdb9bf7fSAngeloGioacchino Del Regno #include <linux/phy.h> 20fdb9bf7fSAngeloGioacchino Del Regno #include <linux/pm_wakeirq.h> 21fdb9bf7fSAngeloGioacchino Del Regno 22fdb9bf7fSAngeloGioacchino Del Regno #include "air_phy_lib.h" 23fdb9bf7fSAngeloGioacchino Del Regno 24fdb9bf7fSAngeloGioacchino Del Regno #define AN8801R_PHY_ID 0xc0ff0421 25fdb9bf7fSAngeloGioacchino Del Regno 26fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers */ 27fdb9bf7fSAngeloGioacchino Del Regno 28fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers - Airoha Page 1 */ 29fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_REG_PHY 0x14 30fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_STATUS0 GENMASK(1, 0) 31fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_DOWNSHIFT_CTL GENMASK(3, 2) /* 2 to 5 1G auto-neg attempts (0..3) */ 32fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_DOWNSHIFT_EN BIT(4) 33fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_CTRL0 BIT(5) 34fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_STATUS1 GENMASK(8, 6) 35fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EXT_PHY_CTRL1 GENMASK(14, 9) 36fdb9bf7fSAngeloGioacchino Del Regno 37fdb9bf7fSAngeloGioacchino Del Regno /* MII Registers - Airoha Page 4 */ 38fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_ACCESS BIT(28) 39fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_EPHY_ACCESS BIT(24) 40fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PBUS_CL22_ACCESS BIT(23) 41fdb9bf7fSAngeloGioacchino Del Regno 42fdb9bf7fSAngeloGioacchino Del Regno /* BPBUS Registers */ 43fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LED_GPIO 0x54 44fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LED_ID_SEL 0x58 45fdb9bf7fSAngeloGioacchino Del Regno #define LED_ID_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3)) 46fdb9bf7fSAngeloGioacchino Del Regno #define LED_ID_GPIO_SEL_MASK(gpio) (0x7 << ((gpio) * 3)) 47fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_GPIO_MODE 0x70 48fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_PHY_IRQ_GPIO 0x7c 49fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_IRQ_GPIO_NUM_MASK GENMASK(19, 16) 50fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_IRQ_GPIO_NUM 1 51fdb9bf7fSAngeloGioacchino Del Regno 52fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_CKO 0x1a4 53fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_CKO_OUTPUT_MODE_AUTO 3 54fdb9bf7fSAngeloGioacchino Del Regno 55fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_LINK_MODE 0x5054 56fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_LINK_MODE_1000 BIT(0) 57fdb9bf7fSAngeloGioacchino Del Regno 58fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_BYPASS_PTP 0x21c004 59fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BYP_PTP_SGMII_TO_GPHY BIT(8) 60fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BYP_PTP_RGMII_TO_GPHY BIT(0) 61fdb9bf7fSAngeloGioacchino Del Regno 62fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_TXDLY_STEP 0x21c024 63fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_MASK GENMASK(2, 0) 64fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_NO_STEP 0 65fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_1 1 66fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_2 2 67fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_3 3 68fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_4 4 69fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_5 5 70fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_6 6 71fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_DELAY_STEP_7 7 72fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_TXDELAY_FORCE_MODE BIT(24) 73fdb9bf7fSAngeloGioacchino Del Regno 74fdb9bf7fSAngeloGioacchino Del Regno /* Default RGMII TX delay setting, corresponding to a 1.883ns delay */ 75fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_RGMII_TXDELAY_DEFAULT RGMII_DELAY_STEP_4 76fdb9bf7fSAngeloGioacchino Del Regno 77fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_RXDLY_STEP 0x21c02c 78fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_RXDELAY_ALIGN BIT(4) 79fdb9bf7fSAngeloGioacchino Del Regno #define RGMII_RXDELAY_FORCE_MODE BIT(24) 80fdb9bf7fSAngeloGioacchino Del Regno 81fdb9bf7fSAngeloGioacchino Del Regno /* Default RGMII RX delay setting, corresponding to a 1.992ns delay, 82fdb9bf7fSAngeloGioacchino Del Regno * when align bit is set or -0.008ns otherwise. 83fdb9bf7fSAngeloGioacchino Del Regno */ 84fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_RGMII_RXDELAY_DEFAULT RGMII_DELAY_NO_STEP 85fdb9bf7fSAngeloGioacchino Del Regno 86fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_EFIFO_CTL(x) (0x270004 + (0x100 * (x))) /* 0..2 */ 87fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_ALL_EN GENMASK(7, 0) 88fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_RX_EN BIT(0) 89fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_TX_EN BIT(1) 90fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_RX_CLK_EN BIT(2) 91fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_TX_CLK_EN BIT(3) 92fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_RX_EEE_EN BIT(4) 93fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_TX_EEE_EN BIT(5) 94fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_RX_ODD_NIBBLE_EN BIT(6) 95fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_EFIFO_TX_ODD_NIBBLE_EN BIT(7) 96fdb9bf7fSAngeloGioacchino Del Regno 97fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WOL_MAC_16_47 0x285114 98fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WOL_MAC_0_15 0x285118 99fdb9bf7fSAngeloGioacchino Del Regno 100fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKEUP_CTL1 0x285400 101fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WOL_WAKE_MAGIC_EN GENMASK(3, 1) 102fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WOL_WAKE_LNKCHG_EN BIT(4) 103fdb9bf7fSAngeloGioacchino Del Regno 104fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKEUP_CTL2 0x285404 105fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_TYPE_PULSE BIT(0) /* Set/Unset: Pulse/Static */ 106fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_POLARITY_NEG BIT(1) /* Set/Unset: Negative/Positive */ 107fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_WIDTH GENMASK(3, 2) 108fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_84MS 0 109fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_168MS 1 110fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_336MS 2 111fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_672MS 3 112fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_WAKE_OUT_EN BIT(4) 113fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PME_WAKEUP_CLR BIT(8) 114fdb9bf7fSAngeloGioacchino Del Regno 115fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKE_IRQ_EN 0x285700 116fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_BPBUS_REG_WAKE_IRQ_STS 0x285704 117fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_LNKCHG BIT(0) /* Wake on link change */ 118fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_UNIPKT BIT(1) /* Wake on unicast packet */ 119fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_MULPKT BIT(2) /* Wake on multicast packet */ 120fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_BCPKT BIT(3) /* Wake on broadcast packet */ 121fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_MAGICPKT BIT(4) /* Wake on magic packet */ 122fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_IRQ_WAKE_ALL GENMASK(4, 0) 123fdb9bf7fSAngeloGioacchino Del Regno 124fdb9bf7fSAngeloGioacchino Del Regno /* MDIO_MMD_VEND1 Registers */ 125fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_TX_PAIR_DLY_SEL_GBE 0x13 126fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_PAIR_DLY_SEL_A_GBE GENMASK(14, 12) 127fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_PAIR_DLY_SEL_B_GBE GENMASK(10, 8) 128fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_PAIR_DLY_SEL_C_GBE GENMASK(6, 4) 129fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_PAIR_DLY_SEL_D_GBE GENMASK(2, 0) 130fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_CTRL 0xd8 131fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_SAMP_PHSEL_A BIT(12) 132fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_SAMP_PHSEL_B BIT(8) 133fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_SAMP_PHSEL_C BIT(4) 134fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_SAMP_PHSEL_D BIT(0) 135fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_0 0xd9 136fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_MASK_A GENMASK(15, 8) 137fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_MASK_B GENMASK(7, 0) 138fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_1 0xda 139fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_MASK_C GENMASK(15, 8) 140fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_RXADC_REV_MASK_D GENMASK(7, 0) 141fdb9bf7fSAngeloGioacchino Del Regno 142fdb9bf7fSAngeloGioacchino Del Regno /* MDIO_MMD_VEND2 Registers */ 143fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR 0x21 144fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_MODE_MASK GENMASK(1, 0) 145fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_TIME_TEST BIT(2) 146fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_CLK_EN BIT(3) 147fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_EVT_ALL BIT(4) 148fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_EXT_CTRL BIT(15) 149fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_MODE_DISABLE 0 150fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_MODE_2LED 1 151fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_MODE_3LED_1 2 152fdb9bf7fSAngeloGioacchino Del Regno #define LED_BCR_MODE_3LED_2 3 153fdb9bf7fSAngeloGioacchino Del Regno 154fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_DUR 0x22 155fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_DUR_MASK GENMASK(15, 0) 156fdb9bf7fSAngeloGioacchino Del Regno 157fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_DUR 0x23 158fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_DUR_MASK GENMASK(15, 0) 159fdb9bf7fSAngeloGioacchino Del Regno 160fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_CTRL(i) (0x24 + ((i) * 2)) 161fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_MASK GENMASK(6, 0) 162fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_LINK_1000M BIT(0) 163fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_LINK_100M BIT(1) 164fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_LINK_10M BIT(2) 165fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_LINK_DN BIT(3) 166fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_FDX BIT(4) 167fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_HDX BIT(5) 168fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EVT_FORCE BIT(6) 169fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_POL BIT(14) 170fdb9bf7fSAngeloGioacchino Del Regno #define LED_ON_EN BIT(15) 171fdb9bf7fSAngeloGioacchino Del Regno 172fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_CTRL(i) (0x25 + ((i) * 2)) 173fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_MASK GENMASK(9, 0) 174fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_1000M_TX BIT(0) 175fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_1000M_RX BIT(1) 176fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_100M_TX BIT(2) 177fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_100M_RX BIT(3) 178fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_10M_TX BIT(4) 179fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_10M_RX BIT(5) 180fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_COLLISION BIT(6) 181fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_RX_CRC_ERR BIT(7) 182fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_RX_IDLE_ERR BIT(8) 183fdb9bf7fSAngeloGioacchino Del Regno #define LED_BLINK_EVT_FORCE BIT(9) 184fdb9bf7fSAngeloGioacchino Del Regno 185fdb9bf7fSAngeloGioacchino Del Regno #define AN8801R_NUM_LEDS 3 186fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PERIOD_SHIFT 15 187fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PERIOD_UNIT 32768 /* (1 << AN8801_PERIOD_SHIFT) */ 188fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_MAX_PERIOD_MS 2147 189fdb9bf7fSAngeloGioacchino Del Regno 190fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_REG_PHY_INTERNAL0 0x600 191fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_REG_PHY_INTERNAL1 0x601 192fdb9bf7fSAngeloGioacchino Del Regno #define AN8801_PHY_INTFUNC_MASK GENMASK(15, 0) /* PHY internal functions */ 193fdb9bf7fSAngeloGioacchino Del Regno 194fdb9bf7fSAngeloGioacchino Del Regno enum an8801r_led_fn { 195fdb9bf7fSAngeloGioacchino Del Regno AN8801R_LED_FN_NONE, 196fdb9bf7fSAngeloGioacchino Del Regno AN8801R_LED_FN_LINK, 197fdb9bf7fSAngeloGioacchino Del Regno AN8801R_LED_FN_ACTIVITY, 198fdb9bf7fSAngeloGioacchino Del Regno AN8801R_LED_FN_MAX, 199fdb9bf7fSAngeloGioacchino Del Regno }; 200fdb9bf7fSAngeloGioacchino Del Regno 201fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv { 202fdb9bf7fSAngeloGioacchino Del Regno bool wake_magic_enabled; 203fdb9bf7fSAngeloGioacchino Del Regno bool wake_lnkchg_enabled; 204fdb9bf7fSAngeloGioacchino Del Regno }; 205fdb9bf7fSAngeloGioacchino Del Regno 206fdb9bf7fSAngeloGioacchino Del Regno static const unsigned long an8801r_led_trig = BIT(TRIGGER_NETDEV_LINK) | 207fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_LINK_10) | 208fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_LINK_100) | 209fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_LINK_1000) | 210fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_RX) | 211fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_RX_ERR) | 212fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_TX); 213fdb9bf7fSAngeloGioacchino Del Regno 214fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_rmw(struct phy_device *phydev, 215fdb9bf7fSAngeloGioacchino Del Regno u32 addr, u32 mask, u32 set) 216fdb9bf7fSAngeloGioacchino Del Regno { 217fdb9bf7fSAngeloGioacchino Del Regno return air_phy_buckpbus_reg_modify(phydev, 218fdb9bf7fSAngeloGioacchino Del Regno addr | AN8801_PBUS_ACCESS, 219fdb9bf7fSAngeloGioacchino Del Regno mask, set); 220fdb9bf7fSAngeloGioacchino Del Regno } 221fdb9bf7fSAngeloGioacchino Del Regno 222fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev, 223fdb9bf7fSAngeloGioacchino Del Regno u32 addr, u32 mask) 224fdb9bf7fSAngeloGioacchino Del Regno { 225fdb9bf7fSAngeloGioacchino Del Regno return air_phy_buckpbus_reg_modify(phydev, 226fdb9bf7fSAngeloGioacchino Del Regno addr | AN8801_PBUS_ACCESS, 227fdb9bf7fSAngeloGioacchino Del Regno mask, mask); 228fdb9bf7fSAngeloGioacchino Del Regno } 229fdb9bf7fSAngeloGioacchino Del Regno 230fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev, 231fdb9bf7fSAngeloGioacchino Del Regno u32 addr, u32 mask) 232fdb9bf7fSAngeloGioacchino Del Regno { 233fdb9bf7fSAngeloGioacchino Del Regno return air_phy_buckpbus_reg_modify(phydev, 234fdb9bf7fSAngeloGioacchino Del Regno addr | AN8801_PBUS_ACCESS, 235fdb9bf7fSAngeloGioacchino Del Regno mask, 0); 236fdb9bf7fSAngeloGioacchino Del Regno } 237fdb9bf7fSAngeloGioacchino Del Regno 238fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr, 239fdb9bf7fSAngeloGioacchino Del Regno u32 data) 240fdb9bf7fSAngeloGioacchino Del Regno { 241fdb9bf7fSAngeloGioacchino Del Regno return air_phy_buckpbus_reg_write(phydev, 242fdb9bf7fSAngeloGioacchino Del Regno addr | AN8801_PBUS_ACCESS, 243fdb9bf7fSAngeloGioacchino Del Regno data); 244fdb9bf7fSAngeloGioacchino Del Regno } 245fdb9bf7fSAngeloGioacchino Del Regno 246fdb9bf7fSAngeloGioacchino Del Regno static int an8801_buckpbus_reg_read(struct phy_device *phydev, u32 addr, 247fdb9bf7fSAngeloGioacchino Del Regno u32 *data) 248fdb9bf7fSAngeloGioacchino Del Regno { 249fdb9bf7fSAngeloGioacchino Del Regno return air_phy_buckpbus_reg_read(phydev, 250fdb9bf7fSAngeloGioacchino Del Regno addr | AN8801_PBUS_ACCESS, 251fdb9bf7fSAngeloGioacchino Del Regno data); 252fdb9bf7fSAngeloGioacchino Del Regno } 253fdb9bf7fSAngeloGioacchino Del Regno 254fdb9bf7fSAngeloGioacchino Del Regno static u32 an8801r_led_blink_ms_to_hw(unsigned long req_ms) 255fdb9bf7fSAngeloGioacchino Del Regno { 256fdb9bf7fSAngeloGioacchino Del Regno u32 req_ns, regval; 257fdb9bf7fSAngeloGioacchino Del Regno 258fdb9bf7fSAngeloGioacchino Del Regno if (req_ms > AN8801_MAX_PERIOD_MS) 259fdb9bf7fSAngeloGioacchino Del Regno req_ms = AN8801_MAX_PERIOD_MS; 260fdb9bf7fSAngeloGioacchino Del Regno 261fdb9bf7fSAngeloGioacchino Del Regno req_ns = req_ms * NSEC_PER_MSEC; 262fdb9bf7fSAngeloGioacchino Del Regno 263fdb9bf7fSAngeloGioacchino Del Regno /* Round to the nearest period unit... */ 264fdb9bf7fSAngeloGioacchino Del Regno regval = req_ns + (AN8801_PERIOD_UNIT / 2); 265fdb9bf7fSAngeloGioacchino Del Regno 266fdb9bf7fSAngeloGioacchino Del Regno /* ...and now divide by the full period */ 267fdb9bf7fSAngeloGioacchino Del Regno regval >>= AN8801_PERIOD_SHIFT; 268fdb9bf7fSAngeloGioacchino Del Regno 269fdb9bf7fSAngeloGioacchino Del Regno return regval; 270fdb9bf7fSAngeloGioacchino Del Regno } 271fdb9bf7fSAngeloGioacchino Del Regno 272fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_blink_set(struct phy_device *phydev, u8 index, 273fdb9bf7fSAngeloGioacchino Del Regno unsigned long *delay_on, 274fdb9bf7fSAngeloGioacchino Del Regno unsigned long *delay_off) 275fdb9bf7fSAngeloGioacchino Del Regno { 276fdb9bf7fSAngeloGioacchino Del Regno u32 hw_delay_on, hw_delay_off; 277fdb9bf7fSAngeloGioacchino Del Regno u16 blink_dur; 278fdb9bf7fSAngeloGioacchino Del Regno bool blink; 279fdb9bf7fSAngeloGioacchino Del Regno int ret; 280fdb9bf7fSAngeloGioacchino Del Regno 281fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 282fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 283fdb9bf7fSAngeloGioacchino Del Regno 284fdb9bf7fSAngeloGioacchino Del Regno if (delay_on && delay_off) { 285fdb9bf7fSAngeloGioacchino Del Regno blink = true; 286fdb9bf7fSAngeloGioacchino Del Regno 287fdb9bf7fSAngeloGioacchino Del Regno if (*delay_on == 0 || *delay_off == 0) { 288fdb9bf7fSAngeloGioacchino Del Regno *delay_on = 64; 289fdb9bf7fSAngeloGioacchino Del Regno *delay_off = 64; 290fdb9bf7fSAngeloGioacchino Del Regno } 291fdb9bf7fSAngeloGioacchino Del Regno 292fdb9bf7fSAngeloGioacchino Del Regno hw_delay_on = an8801r_led_blink_ms_to_hw(*delay_on); 293fdb9bf7fSAngeloGioacchino Del Regno hw_delay_off = an8801r_led_blink_ms_to_hw(*delay_off); 294fdb9bf7fSAngeloGioacchino Del Regno } else { 295fdb9bf7fSAngeloGioacchino Del Regno blink = false; 296fdb9bf7fSAngeloGioacchino Del Regno } 297fdb9bf7fSAngeloGioacchino Del Regno 298fdb9bf7fSAngeloGioacchino Del Regno if (blink) { 299fdb9bf7fSAngeloGioacchino Del Regno blink_dur = (u16)min(hw_delay_on + hw_delay_off, 300fdb9bf7fSAngeloGioacchino Del Regno LED_BLINK_DUR_MASK); 301fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR, 302fdb9bf7fSAngeloGioacchino Del Regno blink_dur); 303fdb9bf7fSAngeloGioacchino Del Regno if (ret) 304fdb9bf7fSAngeloGioacchino Del Regno goto error; 305fdb9bf7fSAngeloGioacchino Del Regno 306fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR, 307fdb9bf7fSAngeloGioacchino Del Regno hw_delay_on); 308fdb9bf7fSAngeloGioacchino Del Regno if (ret) 309fdb9bf7fSAngeloGioacchino Del Regno goto error; 310fdb9bf7fSAngeloGioacchino Del Regno } 311fdb9bf7fSAngeloGioacchino Del Regno 312fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), 313fdb9bf7fSAngeloGioacchino Del Regno LED_BLINK_EVT_MASK, 314fdb9bf7fSAngeloGioacchino Del Regno blink ? LED_BLINK_EVT_FORCE : 0); 315fdb9bf7fSAngeloGioacchino Del Regno if (ret) 316fdb9bf7fSAngeloGioacchino Del Regno return ret; 317fdb9bf7fSAngeloGioacchino Del Regno 318fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 319fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EVT_MASK, 320fdb9bf7fSAngeloGioacchino Del Regno 0); 321fdb9bf7fSAngeloGioacchino Del Regno if (ret) 322fdb9bf7fSAngeloGioacchino Del Regno return ret; 323fdb9bf7fSAngeloGioacchino Del Regno 324fdb9bf7fSAngeloGioacchino Del Regno return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 325fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EN, blink ? LED_ON_EN : 0); 326fdb9bf7fSAngeloGioacchino Del Regno 327fdb9bf7fSAngeloGioacchino Del Regno error: 328fdb9bf7fSAngeloGioacchino Del Regno phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 329fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EN, 0); 330fdb9bf7fSAngeloGioacchino Del Regno return ret; 331fdb9bf7fSAngeloGioacchino Del Regno } 332fdb9bf7fSAngeloGioacchino Del Regno 333fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_brightness_set(struct phy_device *phydev, u8 index, 334fdb9bf7fSAngeloGioacchino Del Regno enum led_brightness value) 335fdb9bf7fSAngeloGioacchino Del Regno { 336fdb9bf7fSAngeloGioacchino Del Regno int ret; 337fdb9bf7fSAngeloGioacchino Del Regno 338fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 339fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 340fdb9bf7fSAngeloGioacchino Del Regno 341fdb9bf7fSAngeloGioacchino Del Regno /* Disable blink first if previously enabled */ 342fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), 343fdb9bf7fSAngeloGioacchino Del Regno LED_BLINK_EVT_MASK, 0); 344fdb9bf7fSAngeloGioacchino Del Regno if (ret) 345fdb9bf7fSAngeloGioacchino Del Regno return ret; 346fdb9bf7fSAngeloGioacchino Del Regno 347fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 348fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EVT_MASK, 349fdb9bf7fSAngeloGioacchino Del Regno (value == LED_OFF) ? 0 : LED_ON_EVT_FORCE); 350fdb9bf7fSAngeloGioacchino Del Regno if (ret) 351fdb9bf7fSAngeloGioacchino Del Regno return ret; 352fdb9bf7fSAngeloGioacchino Del Regno 353fdb9bf7fSAngeloGioacchino Del Regno return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 354fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EN, (value == LED_OFF) ? 0 : LED_ON_EN); 355fdb9bf7fSAngeloGioacchino Del Regno } 356fdb9bf7fSAngeloGioacchino Del Regno 357fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_control_get(struct phy_device *phydev, u8 index, 358fdb9bf7fSAngeloGioacchino Del Regno unsigned long *rules) 359fdb9bf7fSAngeloGioacchino Del Regno { 360fdb9bf7fSAngeloGioacchino Del Regno int on, blink; 361fdb9bf7fSAngeloGioacchino Del Regno 362fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 363fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 364fdb9bf7fSAngeloGioacchino Del Regno 365fdb9bf7fSAngeloGioacchino Del Regno on = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index)); 366fdb9bf7fSAngeloGioacchino Del Regno if (on < 0) 367fdb9bf7fSAngeloGioacchino Del Regno return on; 368fdb9bf7fSAngeloGioacchino Del Regno 369fdb9bf7fSAngeloGioacchino Del Regno blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index)); 370fdb9bf7fSAngeloGioacchino Del Regno if (blink < 0) 371fdb9bf7fSAngeloGioacchino Del Regno return blink; 372fdb9bf7fSAngeloGioacchino Del Regno 373fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_ON_EVT_LINK_10M, on)) 374fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_LINK_10, rules); 375fdb9bf7fSAngeloGioacchino Del Regno 376fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_ON_EVT_LINK_100M, on)) 377fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_LINK_100, rules); 378fdb9bf7fSAngeloGioacchino Del Regno 379fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_ON_EVT_LINK_1000M, on)) 380fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_LINK_1000, rules); 381fdb9bf7fSAngeloGioacchino Del Regno 382fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_ON_EVT_LINK_10M, on) && 383fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_ON_EVT_LINK_100M, on) && 384fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_ON_EVT_LINK_1000M, on)) 385fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_LINK, rules); 386fdb9bf7fSAngeloGioacchino Del Regno 387fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_BLINK_EVT_10M_RX, blink) || 388fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_BLINK_EVT_100M_RX, blink) || 389fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_BLINK_EVT_1000M_RX, blink)) 390fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_RX, rules); 391fdb9bf7fSAngeloGioacchino Del Regno 392fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_BLINK_EVT_10M_TX, blink) || 393fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_BLINK_EVT_100M_TX, blink) || 394fdb9bf7fSAngeloGioacchino Del Regno FIELD_GET(LED_BLINK_EVT_1000M_TX, blink)) 395fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_TX, rules); 396fdb9bf7fSAngeloGioacchino Del Regno 397fdb9bf7fSAngeloGioacchino Del Regno if (FIELD_GET(LED_BLINK_EVT_RX_CRC_ERR, blink)) 398fdb9bf7fSAngeloGioacchino Del Regno __set_bit(TRIGGER_NETDEV_RX_ERR, rules); 399fdb9bf7fSAngeloGioacchino Del Regno 400fdb9bf7fSAngeloGioacchino Del Regno return 0; 401fdb9bf7fSAngeloGioacchino Del Regno } 402fdb9bf7fSAngeloGioacchino Del Regno 403fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_trig_to_hw(unsigned long rules, u16 *on, u16 *blink) 404fdb9bf7fSAngeloGioacchino Del Regno { 405fdb9bf7fSAngeloGioacchino Del Regno /* All combinations of the supported triggers are allowed */ 406fdb9bf7fSAngeloGioacchino Del Regno if (rules & ~an8801r_led_trig) 407fdb9bf7fSAngeloGioacchino Del Regno return -EOPNOTSUPP; 408fdb9bf7fSAngeloGioacchino Del Regno 409fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) 410fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_10M; 411fdb9bf7fSAngeloGioacchino Del Regno 412fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) 413fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_100M; 414fdb9bf7fSAngeloGioacchino Del Regno 415fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) 416fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_1000M; 417fdb9bf7fSAngeloGioacchino Del Regno 418fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_LINK, &rules)) { 419fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_10M; 420fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_100M; 421fdb9bf7fSAngeloGioacchino Del Regno *on |= LED_ON_EVT_LINK_1000M; 422fdb9bf7fSAngeloGioacchino Del Regno } 423fdb9bf7fSAngeloGioacchino Del Regno 424fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_RX, &rules)) { 425fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_10M_RX; 426fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_100M_RX; 427fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_1000M_RX; 428fdb9bf7fSAngeloGioacchino Del Regno } 429fdb9bf7fSAngeloGioacchino Del Regno 430fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_TX, &rules)) { 431fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_10M_TX; 432fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_100M_TX; 433fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_1000M_TX; 434fdb9bf7fSAngeloGioacchino Del Regno } 435fdb9bf7fSAngeloGioacchino Del Regno 436fdb9bf7fSAngeloGioacchino Del Regno if (test_bit(TRIGGER_NETDEV_RX_ERR, &rules)) 437fdb9bf7fSAngeloGioacchino Del Regno *blink |= LED_BLINK_EVT_RX_CRC_ERR; 438fdb9bf7fSAngeloGioacchino Del Regno 439fdb9bf7fSAngeloGioacchino Del Regno return 0; 440fdb9bf7fSAngeloGioacchino Del Regno } 441fdb9bf7fSAngeloGioacchino Del Regno 442fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_is_supported(struct phy_device *phydev, u8 index, 443fdb9bf7fSAngeloGioacchino Del Regno unsigned long rules) 444fdb9bf7fSAngeloGioacchino Del Regno { 445fdb9bf7fSAngeloGioacchino Del Regno u16 on = 0, blink = 0; 446fdb9bf7fSAngeloGioacchino Del Regno 447fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 448fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 449fdb9bf7fSAngeloGioacchino Del Regno 450fdb9bf7fSAngeloGioacchino Del Regno return an8801r_led_trig_to_hw(rules, &on, &blink); 451fdb9bf7fSAngeloGioacchino Del Regno } 452fdb9bf7fSAngeloGioacchino Del Regno 453fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_hw_control_set(struct phy_device *phydev, u8 index, 454fdb9bf7fSAngeloGioacchino Del Regno unsigned long rules) 455fdb9bf7fSAngeloGioacchino Del Regno { 456fdb9bf7fSAngeloGioacchino Del Regno u16 on = 0, blink = 0; 457fdb9bf7fSAngeloGioacchino Del Regno int ret; 458fdb9bf7fSAngeloGioacchino Del Regno 459fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 460fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 461fdb9bf7fSAngeloGioacchino Del Regno 462fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_led_trig_to_hw(rules, &on, &blink); 463fdb9bf7fSAngeloGioacchino Del Regno if (ret) 464fdb9bf7fSAngeloGioacchino Del Regno return ret; 465fdb9bf7fSAngeloGioacchino Del Regno 466fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 467fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EVT_MASK, on); 468fdb9bf7fSAngeloGioacchino Del Regno if (ret) 469fdb9bf7fSAngeloGioacchino Del Regno return ret; 470fdb9bf7fSAngeloGioacchino Del Regno 471fdb9bf7fSAngeloGioacchino Del Regno ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index), 472fdb9bf7fSAngeloGioacchino Del Regno LED_BLINK_EVT_MASK, blink); 473fdb9bf7fSAngeloGioacchino Del Regno if (ret) 474fdb9bf7fSAngeloGioacchino Del Regno return ret; 475fdb9bf7fSAngeloGioacchino Del Regno 476fdb9bf7fSAngeloGioacchino Del Regno return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 477fdb9bf7fSAngeloGioacchino Del Regno LED_ON_EN, (on | blink) ? LED_ON_EN : 0); 478fdb9bf7fSAngeloGioacchino Del Regno } 479fdb9bf7fSAngeloGioacchino Del Regno 480fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_polarity_set(struct phy_device *phydev, int index, 481fdb9bf7fSAngeloGioacchino Del Regno unsigned long modes) 482fdb9bf7fSAngeloGioacchino Del Regno { 483fdb9bf7fSAngeloGioacchino Del Regno bool active_high = true; 484fdb9bf7fSAngeloGioacchino Del Regno unsigned long mode; 485fdb9bf7fSAngeloGioacchino Del Regno 486fdb9bf7fSAngeloGioacchino Del Regno if (index >= AN8801R_NUM_LEDS) 487fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 488fdb9bf7fSAngeloGioacchino Del Regno 489fdb9bf7fSAngeloGioacchino Del Regno for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { 490fdb9bf7fSAngeloGioacchino Del Regno switch (mode) { 491fdb9bf7fSAngeloGioacchino Del Regno case PHY_LED_ACTIVE_HIGH: 492fdb9bf7fSAngeloGioacchino Del Regno break; 493fdb9bf7fSAngeloGioacchino Del Regno case PHY_LED_ACTIVE_LOW: 494fdb9bf7fSAngeloGioacchino Del Regno active_high = false; 495fdb9bf7fSAngeloGioacchino Del Regno break; 496fdb9bf7fSAngeloGioacchino Del Regno default: 497fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 498fdb9bf7fSAngeloGioacchino Del Regno } 499fdb9bf7fSAngeloGioacchino Del Regno } 500fdb9bf7fSAngeloGioacchino Del Regno 501fdb9bf7fSAngeloGioacchino Del Regno return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index), 502fdb9bf7fSAngeloGioacchino Del Regno LED_ON_POL, active_high ? LED_ON_POL : 0); 503fdb9bf7fSAngeloGioacchino Del Regno } 504fdb9bf7fSAngeloGioacchino Del Regno 505fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_led_init(struct phy_device *phydev, u8 *led_cfg) 506fdb9bf7fSAngeloGioacchino Del Regno { 507fdb9bf7fSAngeloGioacchino Del Regno int led_id, ret; 508fdb9bf7fSAngeloGioacchino Del Regno 509fdb9bf7fSAngeloGioacchino Del Regno /* Set LED BCR Enable */ 510fdb9bf7fSAngeloGioacchino Del Regno ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, LED_BCR, 511fdb9bf7fSAngeloGioacchino Del Regno LED_BCR_EXT_CTRL | LED_BCR_CLK_EN); 512fdb9bf7fSAngeloGioacchino Del Regno if (ret) 513fdb9bf7fSAngeloGioacchino Del Regno return ret; 514fdb9bf7fSAngeloGioacchino Del Regno 515fdb9bf7fSAngeloGioacchino Del Regno for (led_id = 0; led_id < AN8801R_NUM_LEDS; led_id++) { 516fdb9bf7fSAngeloGioacchino Del Regno unsigned long led_trigger = 0; 517fdb9bf7fSAngeloGioacchino Del Regno u32 led_gpio = led_id + 1; 518fdb9bf7fSAngeloGioacchino Del Regno 519fdb9bf7fSAngeloGioacchino Del Regno switch (led_cfg[led_id]) { 520fdb9bf7fSAngeloGioacchino Del Regno case AN8801R_LED_FN_LINK: 521fdb9bf7fSAngeloGioacchino Del Regno led_trigger = BIT(TRIGGER_NETDEV_LINK); 522fdb9bf7fSAngeloGioacchino Del Regno break; 523fdb9bf7fSAngeloGioacchino Del Regno case AN8801R_LED_FN_ACTIVITY: 524fdb9bf7fSAngeloGioacchino Del Regno led_trigger = BIT(TRIGGER_NETDEV_RX) | 525fdb9bf7fSAngeloGioacchino Del Regno BIT(TRIGGER_NETDEV_TX); 526fdb9bf7fSAngeloGioacchino Del Regno break; 527fdb9bf7fSAngeloGioacchino Del Regno default: 528fdb9bf7fSAngeloGioacchino Del Regno led_trigger = 0; 529fdb9bf7fSAngeloGioacchino Del Regno break; 530fdb9bf7fSAngeloGioacchino Del Regno } 531fdb9bf7fSAngeloGioacchino Del Regno 532fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 533fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_LED_GPIO, 534fdb9bf7fSAngeloGioacchino Del Regno BIT(led_gpio)); 535fdb9bf7fSAngeloGioacchino Del Regno if (ret) 536fdb9bf7fSAngeloGioacchino Del Regno return ret; 537fdb9bf7fSAngeloGioacchino Del Regno 538fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_rmw(phydev, 539fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_LED_ID_SEL, 540fdb9bf7fSAngeloGioacchino Del Regno LED_ID_GPIO_SEL_MASK(led_gpio), 541fdb9bf7fSAngeloGioacchino Del Regno LED_ID_GPIO_SEL(led_id, 542fdb9bf7fSAngeloGioacchino Del Regno led_gpio)); 543fdb9bf7fSAngeloGioacchino Del Regno if (ret) 544fdb9bf7fSAngeloGioacchino Del Regno return ret; 545fdb9bf7fSAngeloGioacchino Del Regno 546fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_clear_bits(phydev, 547fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_GPIO_MODE, 548fdb9bf7fSAngeloGioacchino Del Regno BIT(led_gpio)); 549fdb9bf7fSAngeloGioacchino Del Regno if (ret) 550fdb9bf7fSAngeloGioacchino Del Regno return ret; 551fdb9bf7fSAngeloGioacchino Del Regno 552fdb9bf7fSAngeloGioacchino Del Regno if (!led_trigger) 553fdb9bf7fSAngeloGioacchino Del Regno continue; 554fdb9bf7fSAngeloGioacchino Del Regno 555fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_led_hw_control_set(phydev, led_id, led_trigger); 556fdb9bf7fSAngeloGioacchino Del Regno if (ret) 557fdb9bf7fSAngeloGioacchino Del Regno return ret; 558fdb9bf7fSAngeloGioacchino Del Regno } 559fdb9bf7fSAngeloGioacchino Del Regno 560fdb9bf7fSAngeloGioacchino Del Regno return ret; 561fdb9bf7fSAngeloGioacchino Del Regno } 562fdb9bf7fSAngeloGioacchino Del Regno 563fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_reset_wake(struct phy_device *phydev) 564fdb9bf7fSAngeloGioacchino Del Regno { 565fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv *priv = phydev->priv; 566fdb9bf7fSAngeloGioacchino Del Regno u32 reg_val = 0; 567fdb9bf7fSAngeloGioacchino Del Regno int ret; 568fdb9bf7fSAngeloGioacchino Del Regno 569fdb9bf7fSAngeloGioacchino Del Regno /* Enable wakeup clear and disable wake up output */ 570fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2, 571fdb9bf7fSAngeloGioacchino Del Regno AN8801_PME_WAKEUP_CLR | 572fdb9bf7fSAngeloGioacchino Del Regno AN8801_WAKE_OUT_POLARITY_NEG); 573fdb9bf7fSAngeloGioacchino Del Regno if (ret) 574fdb9bf7fSAngeloGioacchino Del Regno return ret; 575fdb9bf7fSAngeloGioacchino Del Regno 576fdb9bf7fSAngeloGioacchino Del Regno /* Clear WAKEUP_CTL1 register before enabling the wakeup events 577fdb9bf7fSAngeloGioacchino Del Regno * again 578fdb9bf7fSAngeloGioacchino Del Regno */ 579fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, 580fdb9bf7fSAngeloGioacchino Del Regno 0); 581fdb9bf7fSAngeloGioacchino Del Regno if (ret) 582fdb9bf7fSAngeloGioacchino Del Regno return ret; 583fdb9bf7fSAngeloGioacchino Del Regno 584fdb9bf7fSAngeloGioacchino Del Regno if (priv->wake_magic_enabled) 585fdb9bf7fSAngeloGioacchino Del Regno reg_val |= AN8801_WOL_WAKE_MAGIC_EN; 586fdb9bf7fSAngeloGioacchino Del Regno 587fdb9bf7fSAngeloGioacchino Del Regno if (priv->wake_lnkchg_enabled) 588fdb9bf7fSAngeloGioacchino Del Regno reg_val |= AN8801_WOL_WAKE_LNKCHG_EN; 589fdb9bf7fSAngeloGioacchino Del Regno 590fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, 591fdb9bf7fSAngeloGioacchino Del Regno reg_val); 592fdb9bf7fSAngeloGioacchino Del Regno if (ret) 593fdb9bf7fSAngeloGioacchino Del Regno return ret; 594fdb9bf7fSAngeloGioacchino Del Regno 595fdb9bf7fSAngeloGioacchino Del Regno /* Disable wake up clear and re-enable wake up output */ 596fdb9bf7fSAngeloGioacchino Del Regno return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2, 597fdb9bf7fSAngeloGioacchino Del Regno AN8801_WAKE_OUT_POLARITY_NEG | 598fdb9bf7fSAngeloGioacchino Del Regno AN8801_WAKE_OUT_EN); 599fdb9bf7fSAngeloGioacchino Del Regno } 600fdb9bf7fSAngeloGioacchino Del Regno 601fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_ack_interrupt(struct phy_device *phydev) 602fdb9bf7fSAngeloGioacchino Del Regno { 603fdb9bf7fSAngeloGioacchino Del Regno int ret; 604fdb9bf7fSAngeloGioacchino Del Regno 605fdb9bf7fSAngeloGioacchino Del Regno /* Reset wake status */ 606fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_reset_wake(phydev); 607fdb9bf7fSAngeloGioacchino Del Regno if (ret) 608fdb9bf7fSAngeloGioacchino Del Regno return ret; 609fdb9bf7fSAngeloGioacchino Del Regno 610fdb9bf7fSAngeloGioacchino Del Regno /* Clear the interrupts by writing the reg */ 611fdb9bf7fSAngeloGioacchino Del Regno return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS, 612fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_ALL); 613fdb9bf7fSAngeloGioacchino Del Regno } 614fdb9bf7fSAngeloGioacchino Del Regno 615fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_config_intr(struct phy_device *phydev) 616fdb9bf7fSAngeloGioacchino Del Regno { 617fdb9bf7fSAngeloGioacchino Del Regno int ret; 618fdb9bf7fSAngeloGioacchino Del Regno 619fdb9bf7fSAngeloGioacchino Del Regno if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 620fdb9bf7fSAngeloGioacchino Del Regno u32 val = FIELD_PREP(AN8801_PHY_IRQ_GPIO_NUM_MASK, 621fdb9bf7fSAngeloGioacchino Del Regno AN8801_PHY_IRQ_GPIO_NUM); 622fdb9bf7fSAngeloGioacchino Del Regno 623fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, 624fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_PHY_IRQ_GPIO, 625fdb9bf7fSAngeloGioacchino Del Regno val); 626fdb9bf7fSAngeloGioacchino Del Regno if (ret) 627fdb9bf7fSAngeloGioacchino Del Regno return ret; 628fdb9bf7fSAngeloGioacchino Del Regno 629fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 630fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 631fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_LNKCHG); 632fdb9bf7fSAngeloGioacchino Del Regno if (ret) 633fdb9bf7fSAngeloGioacchino Del Regno return ret; 634fdb9bf7fSAngeloGioacchino Del Regno 635fdb9bf7fSAngeloGioacchino Del Regno } else { 636fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, 637fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_PHY_IRQ_GPIO, 638fdb9bf7fSAngeloGioacchino Del Regno 0); 639fdb9bf7fSAngeloGioacchino Del Regno if (ret) 640fdb9bf7fSAngeloGioacchino Del Regno return ret; 641fdb9bf7fSAngeloGioacchino Del Regno 642fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_clear_bits(phydev, 643fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 644fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_LNKCHG); 645fdb9bf7fSAngeloGioacchino Del Regno if (ret) 646fdb9bf7fSAngeloGioacchino Del Regno return ret; 647fdb9bf7fSAngeloGioacchino Del Regno } 648fdb9bf7fSAngeloGioacchino Del Regno 649fdb9bf7fSAngeloGioacchino Del Regno return an8801r_ack_interrupt(phydev); 650fdb9bf7fSAngeloGioacchino Del Regno } 651fdb9bf7fSAngeloGioacchino Del Regno 652fdb9bf7fSAngeloGioacchino Del Regno static irqreturn_t an8801r_handle_interrupt(struct phy_device *phydev) 653fdb9bf7fSAngeloGioacchino Del Regno { 654fdb9bf7fSAngeloGioacchino Del Regno u32 irq_status = 0; 655fdb9bf7fSAngeloGioacchino Del Regno bool irq_handled = false; 656fdb9bf7fSAngeloGioacchino Del Regno int ret; 657fdb9bf7fSAngeloGioacchino Del Regno 658fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS, 659fdb9bf7fSAngeloGioacchino Del Regno &irq_status); 660fdb9bf7fSAngeloGioacchino Del Regno if (ret) 661fdb9bf7fSAngeloGioacchino Del Regno return IRQ_NONE; 662fdb9bf7fSAngeloGioacchino Del Regno 663fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_ack_interrupt(phydev); 664fdb9bf7fSAngeloGioacchino Del Regno if (ret) 665fdb9bf7fSAngeloGioacchino Del Regno return IRQ_NONE; 666fdb9bf7fSAngeloGioacchino Del Regno 667fdb9bf7fSAngeloGioacchino Del Regno if (irq_status & AN8801_IRQ_WAKE_MAGICPKT) { 668fdb9bf7fSAngeloGioacchino Del Regno pm_wakeup_event(&phydev->mdio.dev, 0); 669fdb9bf7fSAngeloGioacchino Del Regno irq_handled = true; 670fdb9bf7fSAngeloGioacchino Del Regno } 671fdb9bf7fSAngeloGioacchino Del Regno 672fdb9bf7fSAngeloGioacchino Del Regno if (irq_status & AN8801_IRQ_WAKE_LNKCHG) { 673fdb9bf7fSAngeloGioacchino Del Regno phy_trigger_machine(phydev); 674fdb9bf7fSAngeloGioacchino Del Regno irq_handled = true; 675fdb9bf7fSAngeloGioacchino Del Regno } 676fdb9bf7fSAngeloGioacchino Del Regno 677fdb9bf7fSAngeloGioacchino Del Regno return irq_handled ? IRQ_HANDLED : IRQ_NONE; 678fdb9bf7fSAngeloGioacchino Del Regno } 679fdb9bf7fSAngeloGioacchino Del Regno 680fdb9bf7fSAngeloGioacchino Del Regno static void an8801r_get_wol(struct phy_device *phydev, 681fdb9bf7fSAngeloGioacchino Del Regno struct ethtool_wolinfo *wol) 682fdb9bf7fSAngeloGioacchino Del Regno { 683fdb9bf7fSAngeloGioacchino Del Regno u32 reg_val; 684fdb9bf7fSAngeloGioacchino Del Regno int ret; 685fdb9bf7fSAngeloGioacchino Del Regno 686fdb9bf7fSAngeloGioacchino Del Regno /* If the PHY is not capable of waking the system, then WoL can not 687fdb9bf7fSAngeloGioacchino Del Regno * be supported. 688fdb9bf7fSAngeloGioacchino Del Regno */ 689fdb9bf7fSAngeloGioacchino Del Regno if (!device_can_wakeup(&phydev->mdio.dev)) { 690fdb9bf7fSAngeloGioacchino Del Regno wol->supported = 0; 691fdb9bf7fSAngeloGioacchino Del Regno return; 692fdb9bf7fSAngeloGioacchino Del Regno } 693fdb9bf7fSAngeloGioacchino Del Regno 694fdb9bf7fSAngeloGioacchino Del Regno wol->supported = WAKE_MAGIC; 695fdb9bf7fSAngeloGioacchino Del Regno wol->wolopts = 0; 696fdb9bf7fSAngeloGioacchino Del Regno 697fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1, 698fdb9bf7fSAngeloGioacchino Del Regno ®_val); 699fdb9bf7fSAngeloGioacchino Del Regno if (ret) 700fdb9bf7fSAngeloGioacchino Del Regno return; 701fdb9bf7fSAngeloGioacchino Del Regno 702fdb9bf7fSAngeloGioacchino Del Regno if (reg_val & AN8801_WOL_WAKE_MAGIC_EN) 703fdb9bf7fSAngeloGioacchino Del Regno wol->wolopts |= WAKE_MAGIC; 704fdb9bf7fSAngeloGioacchino Del Regno else 705fdb9bf7fSAngeloGioacchino Del Regno wol->wolopts &= ~WAKE_MAGIC; 706fdb9bf7fSAngeloGioacchino Del Regno } 707fdb9bf7fSAngeloGioacchino Del Regno 708fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_set_wol(struct phy_device *phydev, 709fdb9bf7fSAngeloGioacchino Del Regno struct ethtool_wolinfo *wol) 710fdb9bf7fSAngeloGioacchino Del Regno { 711fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv *priv = phydev->priv; 712fdb9bf7fSAngeloGioacchino Del Regno struct net_device *attach_dev; 713fdb9bf7fSAngeloGioacchino Del Regno const u8 *macaddr; 714fdb9bf7fSAngeloGioacchino Del Regno u32 reg_val; 715fdb9bf7fSAngeloGioacchino Del Regno int ret; 716fdb9bf7fSAngeloGioacchino Del Regno 717fdb9bf7fSAngeloGioacchino Del Regno if (!device_can_wakeup(&phydev->mdio.dev)) 718fdb9bf7fSAngeloGioacchino Del Regno return -EOPNOTSUPP; 719fdb9bf7fSAngeloGioacchino Del Regno 720fdb9bf7fSAngeloGioacchino Del Regno if (wol->wolopts & ~WAKE_MAGIC) 721fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 722fdb9bf7fSAngeloGioacchino Del Regno 723fdb9bf7fSAngeloGioacchino Del Regno if (wol->wolopts & WAKE_MAGIC) { 724fdb9bf7fSAngeloGioacchino Del Regno attach_dev = phydev->attached_dev; 725fdb9bf7fSAngeloGioacchino Del Regno if (!attach_dev) 726fdb9bf7fSAngeloGioacchino Del Regno return -ENODEV; 727fdb9bf7fSAngeloGioacchino Del Regno 728fdb9bf7fSAngeloGioacchino Del Regno macaddr = (const u8 *)attach_dev->dev_addr; 729fdb9bf7fSAngeloGioacchino Del Regno if (!is_valid_ether_addr(macaddr)) 730fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 731fdb9bf7fSAngeloGioacchino Del Regno 732fdb9bf7fSAngeloGioacchino Del Regno /* MAC bits 16..47 */ 733fdb9bf7fSAngeloGioacchino Del Regno reg_val = (macaddr[2] << 24) | (macaddr[3] << 16); 734fdb9bf7fSAngeloGioacchino Del Regno reg_val |= (macaddr[4] << 8) | (macaddr[5]); 735fdb9bf7fSAngeloGioacchino Del Regno 736fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, 737fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WOL_MAC_16_47, 738fdb9bf7fSAngeloGioacchino Del Regno reg_val); 739fdb9bf7fSAngeloGioacchino Del Regno if (ret) 740fdb9bf7fSAngeloGioacchino Del Regno return ret; 741fdb9bf7fSAngeloGioacchino Del Regno 742fdb9bf7fSAngeloGioacchino Del Regno /* MAC bits 0..15 */ 743fdb9bf7fSAngeloGioacchino Del Regno reg_val = (macaddr[0] << 8) | (macaddr[1]); 744fdb9bf7fSAngeloGioacchino Del Regno 745fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, 746fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WOL_MAC_0_15, 747fdb9bf7fSAngeloGioacchino Del Regno reg_val); 748fdb9bf7fSAngeloGioacchino Del Regno if (ret) 749fdb9bf7fSAngeloGioacchino Del Regno return ret; 750fdb9bf7fSAngeloGioacchino Del Regno 751fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 752fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKEUP_CTL1, 753fdb9bf7fSAngeloGioacchino Del Regno AN8801_WOL_WAKE_MAGIC_EN); 754fdb9bf7fSAngeloGioacchino Del Regno if (ret) 755fdb9bf7fSAngeloGioacchino Del Regno return ret; 756fdb9bf7fSAngeloGioacchino Del Regno 757fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 758fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 759fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_MAGICPKT); 760fdb9bf7fSAngeloGioacchino Del Regno if (ret) 761fdb9bf7fSAngeloGioacchino Del Regno return ret; 762fdb9bf7fSAngeloGioacchino Del Regno 763fdb9bf7fSAngeloGioacchino Del Regno } else { 764fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_clear_bits(phydev, 765fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKEUP_CTL1, 766fdb9bf7fSAngeloGioacchino Del Regno AN8801_WOL_WAKE_MAGIC_EN); 767fdb9bf7fSAngeloGioacchino Del Regno if (ret) 768fdb9bf7fSAngeloGioacchino Del Regno return ret; 769fdb9bf7fSAngeloGioacchino Del Regno 770fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_clear_bits(phydev, 771fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 772fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_MAGICPKT); 773fdb9bf7fSAngeloGioacchino Del Regno if (ret) 774fdb9bf7fSAngeloGioacchino Del Regno return ret; 775fdb9bf7fSAngeloGioacchino Del Regno } 776fdb9bf7fSAngeloGioacchino Del Regno 777fdb9bf7fSAngeloGioacchino Del Regno priv->wake_magic_enabled = !!(wol->wolopts & WAKE_MAGIC); 778fdb9bf7fSAngeloGioacchino Del Regno 779fdb9bf7fSAngeloGioacchino Del Regno return device_set_wakeup_enable(&phydev->mdio.dev, 780fdb9bf7fSAngeloGioacchino Del Regno priv->wake_magic_enabled); 781fdb9bf7fSAngeloGioacchino Del Regno } 782fdb9bf7fSAngeloGioacchino Del Regno 783fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_of_init_leds(struct phy_device *phydev, u8 *led_cfg) 784fdb9bf7fSAngeloGioacchino Del Regno { 785fdb9bf7fSAngeloGioacchino Del Regno struct device *dev = &phydev->mdio.dev; 786fdb9bf7fSAngeloGioacchino Del Regno struct device_node *np = dev->of_node; 787fdb9bf7fSAngeloGioacchino Del Regno struct device_node *leds; 788fdb9bf7fSAngeloGioacchino Del Regno u32 function_enum_idx; 789fdb9bf7fSAngeloGioacchino Del Regno int ret = 0; 790fdb9bf7fSAngeloGioacchino Del Regno 791fdb9bf7fSAngeloGioacchino Del Regno if (!np) 792fdb9bf7fSAngeloGioacchino Del Regno return 0; 793fdb9bf7fSAngeloGioacchino Del Regno 794fdb9bf7fSAngeloGioacchino Del Regno /* If devicetree is present, leds configuration is required */ 795fdb9bf7fSAngeloGioacchino Del Regno leds = of_get_child_by_name(np, "leds"); 796fdb9bf7fSAngeloGioacchino Del Regno if (!leds) 797fdb9bf7fSAngeloGioacchino Del Regno return 0; 798fdb9bf7fSAngeloGioacchino Del Regno 799fdb9bf7fSAngeloGioacchino Del Regno for_each_available_child_of_node_scoped(leds, led) { 800fdb9bf7fSAngeloGioacchino Del Regno u32 led_idx; 801fdb9bf7fSAngeloGioacchino Del Regno 802fdb9bf7fSAngeloGioacchino Del Regno ret = of_property_read_u32(led, "reg", &led_idx); 803fdb9bf7fSAngeloGioacchino Del Regno if (ret) 804fdb9bf7fSAngeloGioacchino Del Regno goto out; 805fdb9bf7fSAngeloGioacchino Del Regno 806fdb9bf7fSAngeloGioacchino Del Regno if (led_idx >= AN8801R_NUM_LEDS) { 807fdb9bf7fSAngeloGioacchino Del Regno ret = -EINVAL; 808fdb9bf7fSAngeloGioacchino Del Regno goto out; 809fdb9bf7fSAngeloGioacchino Del Regno } 810fdb9bf7fSAngeloGioacchino Del Regno 811fdb9bf7fSAngeloGioacchino Del Regno ret = of_property_read_u32(led, "function-enumerator", 812fdb9bf7fSAngeloGioacchino Del Regno &function_enum_idx); 813fdb9bf7fSAngeloGioacchino Del Regno if (ret) { 814fdb9bf7fSAngeloGioacchino Del Regno function_enum_idx = AN8801R_LED_FN_NONE; 815fdb9bf7fSAngeloGioacchino Del Regno ret = 0; 816fdb9bf7fSAngeloGioacchino Del Regno } 817fdb9bf7fSAngeloGioacchino Del Regno 818fdb9bf7fSAngeloGioacchino Del Regno if (function_enum_idx >= AN8801R_LED_FN_MAX) { 819fdb9bf7fSAngeloGioacchino Del Regno ret = -EINVAL; 820fdb9bf7fSAngeloGioacchino Del Regno goto out; 821fdb9bf7fSAngeloGioacchino Del Regno } 822fdb9bf7fSAngeloGioacchino Del Regno 823fdb9bf7fSAngeloGioacchino Del Regno led_cfg[led_idx] = function_enum_idx; 824fdb9bf7fSAngeloGioacchino Del Regno } 825fdb9bf7fSAngeloGioacchino Del Regno out: 826fdb9bf7fSAngeloGioacchino Del Regno of_node_put(leds); 827fdb9bf7fSAngeloGioacchino Del Regno return ret; 828fdb9bf7fSAngeloGioacchino Del Regno } 829fdb9bf7fSAngeloGioacchino Del Regno 830fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_rxdelay(struct phy_device *phydev, bool enable, 831fdb9bf7fSAngeloGioacchino Del Regno u16 delay_steps) 832fdb9bf7fSAngeloGioacchino Del Regno { 833fdb9bf7fSAngeloGioacchino Del Regno u32 reg_val; 834fdb9bf7fSAngeloGioacchino Del Regno 835fdb9bf7fSAngeloGioacchino Del Regno if (delay_steps > RGMII_DELAY_STEP_MASK) 836fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 837fdb9bf7fSAngeloGioacchino Del Regno 838fdb9bf7fSAngeloGioacchino Del Regno if (enable) { 839fdb9bf7fSAngeloGioacchino Del Regno /* Set force mode bit to enable RX delay insertion */ 840fdb9bf7fSAngeloGioacchino Del Regno reg_val = delay_steps | RGMII_RXDELAY_FORCE_MODE; 841fdb9bf7fSAngeloGioacchino Del Regno 842fdb9bf7fSAngeloGioacchino Del Regno /* Set align bit to add extra offset for RX delay */ 843fdb9bf7fSAngeloGioacchino Del Regno reg_val |= RGMII_RXDELAY_ALIGN; 844fdb9bf7fSAngeloGioacchino Del Regno } else { 845fdb9bf7fSAngeloGioacchino Del Regno reg_val = 0; 846fdb9bf7fSAngeloGioacchino Del Regno } 847fdb9bf7fSAngeloGioacchino Del Regno 848fdb9bf7fSAngeloGioacchino Del Regno return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP, 849fdb9bf7fSAngeloGioacchino Del Regno reg_val); 850fdb9bf7fSAngeloGioacchino Del Regno } 851fdb9bf7fSAngeloGioacchino Del Regno 852fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_txdelay(struct phy_device *phydev, bool enable, 853fdb9bf7fSAngeloGioacchino Del Regno u16 delay_steps) 854fdb9bf7fSAngeloGioacchino Del Regno { 855fdb9bf7fSAngeloGioacchino Del Regno u32 reg_val; 856fdb9bf7fSAngeloGioacchino Del Regno 857fdb9bf7fSAngeloGioacchino Del Regno if (delay_steps > RGMII_DELAY_STEP_MASK) 858fdb9bf7fSAngeloGioacchino Del Regno return -EINVAL; 859fdb9bf7fSAngeloGioacchino Del Regno 860fdb9bf7fSAngeloGioacchino Del Regno if (enable) { 861fdb9bf7fSAngeloGioacchino Del Regno /* Set force mode bit to enable TX delay insertion */ 862fdb9bf7fSAngeloGioacchino Del Regno reg_val = delay_steps | RGMII_TXDELAY_FORCE_MODE; 863fdb9bf7fSAngeloGioacchino Del Regno } else { 864fdb9bf7fSAngeloGioacchino Del Regno reg_val = 0; 865fdb9bf7fSAngeloGioacchino Del Regno } 866fdb9bf7fSAngeloGioacchino Del Regno 867fdb9bf7fSAngeloGioacchino Del Regno return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP, 868fdb9bf7fSAngeloGioacchino Del Regno reg_val); 869fdb9bf7fSAngeloGioacchino Del Regno } 870fdb9bf7fSAngeloGioacchino Del Regno 871fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_rgmii_delay_config(struct phy_device *phydev) 872fdb9bf7fSAngeloGioacchino Del Regno { 873fdb9bf7fSAngeloGioacchino Del Regno bool enable_delay; 874fdb9bf7fSAngeloGioacchino Del Regno u16 delay_step; 875fdb9bf7fSAngeloGioacchino Del Regno int ret; 876fdb9bf7fSAngeloGioacchino Del Regno 877fdb9bf7fSAngeloGioacchino Del Regno if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 878fdb9bf7fSAngeloGioacchino Del Regno phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 879fdb9bf7fSAngeloGioacchino Del Regno enable_delay = true; 880fdb9bf7fSAngeloGioacchino Del Regno delay_step = AN8801_RGMII_TXDELAY_DEFAULT; 881fdb9bf7fSAngeloGioacchino Del Regno } else { 882fdb9bf7fSAngeloGioacchino Del Regno enable_delay = false; 883fdb9bf7fSAngeloGioacchino Del Regno delay_step = RGMII_DELAY_NO_STEP; 884fdb9bf7fSAngeloGioacchino Del Regno } 885fdb9bf7fSAngeloGioacchino Del Regno 886fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_rgmii_txdelay(phydev, enable_delay, delay_step); 887fdb9bf7fSAngeloGioacchino Del Regno if (ret) 888fdb9bf7fSAngeloGioacchino Del Regno return ret; 889fdb9bf7fSAngeloGioacchino Del Regno 890fdb9bf7fSAngeloGioacchino Del Regno if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 891fdb9bf7fSAngeloGioacchino Del Regno phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 892fdb9bf7fSAngeloGioacchino Del Regno enable_delay = true; 893fdb9bf7fSAngeloGioacchino Del Regno delay_step = AN8801_RGMII_RXDELAY_DEFAULT; 894fdb9bf7fSAngeloGioacchino Del Regno } else { 895fdb9bf7fSAngeloGioacchino Del Regno enable_delay = false; 896fdb9bf7fSAngeloGioacchino Del Regno delay_step = RGMII_DELAY_NO_STEP; 897fdb9bf7fSAngeloGioacchino Del Regno } 898fdb9bf7fSAngeloGioacchino Del Regno 899fdb9bf7fSAngeloGioacchino Del Regno return an8801r_rgmii_rxdelay(phydev, enable_delay, delay_step); 900fdb9bf7fSAngeloGioacchino Del Regno } 901fdb9bf7fSAngeloGioacchino Del Regno 902fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_config_init(struct phy_device *phydev) 903fdb9bf7fSAngeloGioacchino Del Regno { 904fdb9bf7fSAngeloGioacchino Del Regno u8 led_default_function[AN8801R_NUM_LEDS] = { 0 }; 905fdb9bf7fSAngeloGioacchino Del Regno int ret; 906fdb9bf7fSAngeloGioacchino Del Regno 907fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_of_init_leds(phydev, led_default_function); 908fdb9bf7fSAngeloGioacchino Del Regno if (ret) 909fdb9bf7fSAngeloGioacchino Del Regno return ret; 910fdb9bf7fSAngeloGioacchino Del Regno 911fdb9bf7fSAngeloGioacchino Del Regno /* Disable Low Power Mode (LPM) */ 912fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0, 913fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x1e)); 914fdb9bf7fSAngeloGioacchino Del Regno if (ret) 915fdb9bf7fSAngeloGioacchino Del Regno return ret; 916fdb9bf7fSAngeloGioacchino Del Regno 917fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1, 918fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x2)); 919fdb9bf7fSAngeloGioacchino Del Regno if (ret) 920fdb9bf7fSAngeloGioacchino Del Regno return ret; 921fdb9bf7fSAngeloGioacchino Del Regno 922fdb9bf7fSAngeloGioacchino Del Regno /* Set the PHY to perform auto-downshift after 3 auto-negotiation 923fdb9bf7fSAngeloGioacchino Del Regno * attempts 924fdb9bf7fSAngeloGioacchino Del Regno */ 925fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_paged(phydev, AIR_PHY_PAGE_EXTENDED_1, 926fdb9bf7fSAngeloGioacchino Del Regno AN8801_EXT_REG_PHY, 927fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_EXT_PHY_CTRL1, 0x1d) | 928fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_EXT_PHY_DOWNSHIFT_CTL, 1) | 929fdb9bf7fSAngeloGioacchino Del Regno AN8801_EXT_PHY_DOWNSHIFT_EN); 930fdb9bf7fSAngeloGioacchino Del Regno if (ret < 0) 931fdb9bf7fSAngeloGioacchino Del Regno return ret; 932fdb9bf7fSAngeloGioacchino Del Regno 933fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP, 934fdb9bf7fSAngeloGioacchino Del Regno AN8801_BYP_PTP_RGMII_TO_GPHY); 935fdb9bf7fSAngeloGioacchino Del Regno if (ret) 936fdb9bf7fSAngeloGioacchino Del Regno return ret; 937fdb9bf7fSAngeloGioacchino Del Regno 938fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0), 939fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_RX_EN | 940fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_TX_EN | 941fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_RX_CLK_EN | 942fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_TX_CLK_EN | 943fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_RX_EEE_EN | 944fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_TX_EEE_EN); 945fdb9bf7fSAngeloGioacchino Del Regno if (ret) 946fdb9bf7fSAngeloGioacchino Del Regno return ret; 947fdb9bf7fSAngeloGioacchino Del Regno 948fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1), 949fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_ALL_EN); 950fdb9bf7fSAngeloGioacchino Del Regno if (ret) 951fdb9bf7fSAngeloGioacchino Del Regno return ret; 952fdb9bf7fSAngeloGioacchino Del Regno 953fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2), 954fdb9bf7fSAngeloGioacchino Del Regno AN8801_EFIFO_ALL_EN); 955fdb9bf7fSAngeloGioacchino Del Regno if (ret) 956fdb9bf7fSAngeloGioacchino Del Regno return ret; 957fdb9bf7fSAngeloGioacchino Del Regno 958fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 959fdb9bf7fSAngeloGioacchino Del Regno AN8801_PHY_TX_PAIR_DLY_SEL_GBE, 960fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_A_GBE, 4) | 961fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_C_GBE, 4)); 962fdb9bf7fSAngeloGioacchino Del Regno if (ret) 963fdb9bf7fSAngeloGioacchino Del Regno return ret; 964fdb9bf7fSAngeloGioacchino Del Regno 965fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_CTRL, 966fdb9bf7fSAngeloGioacchino Del Regno AN8801_PHY_RXADC_SAMP_PHSEL_A | 967fdb9bf7fSAngeloGioacchino Del Regno AN8801_PHY_RXADC_SAMP_PHSEL_C); 968fdb9bf7fSAngeloGioacchino Del Regno if (ret) 969fdb9bf7fSAngeloGioacchino Del Regno return ret; 970fdb9bf7fSAngeloGioacchino Del Regno 971fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_0, 972fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_A, 1)); 973fdb9bf7fSAngeloGioacchino Del Regno if (ret) 974fdb9bf7fSAngeloGioacchino Del Regno return ret; 975fdb9bf7fSAngeloGioacchino Del Regno 976fdb9bf7fSAngeloGioacchino Del Regno ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_1, 977fdb9bf7fSAngeloGioacchino Del Regno FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_C, 1)); 978fdb9bf7fSAngeloGioacchino Del Regno if (ret) 979fdb9bf7fSAngeloGioacchino Del Regno return ret; 980fdb9bf7fSAngeloGioacchino Del Regno 981fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_rgmii_delay_config(phydev); 982fdb9bf7fSAngeloGioacchino Del Regno if (ret) 983fdb9bf7fSAngeloGioacchino Del Regno return ret; 984fdb9bf7fSAngeloGioacchino Del Regno 985fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_CKO, 986fdb9bf7fSAngeloGioacchino Del Regno AN8801_CKO_OUTPUT_MODE_AUTO); 987fdb9bf7fSAngeloGioacchino Del Regno if (ret) 988fdb9bf7fSAngeloGioacchino Del Regno return ret; 989fdb9bf7fSAngeloGioacchino Del Regno 990fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_led_init(phydev, led_default_function); 991fdb9bf7fSAngeloGioacchino Del Regno if (ret) { 992fdb9bf7fSAngeloGioacchino Del Regno phydev_err(phydev, "Cannot initialize LEDs: %d\n", ret); 993fdb9bf7fSAngeloGioacchino Del Regno return ret; 994fdb9bf7fSAngeloGioacchino Del Regno } 995fdb9bf7fSAngeloGioacchino Del Regno 996fdb9bf7fSAngeloGioacchino Del Regno return 0; 997fdb9bf7fSAngeloGioacchino Del Regno } 998fdb9bf7fSAngeloGioacchino Del Regno 999*f6465e36SLouis-Alexis Eyraud static int an8801r_read_status(struct phy_device *phydev) 1000*f6465e36SLouis-Alexis Eyraud { 1001*f6465e36SLouis-Alexis Eyraud int prev_speed, ret; 1002*f6465e36SLouis-Alexis Eyraud u32 val; 1003*f6465e36SLouis-Alexis Eyraud 1004*f6465e36SLouis-Alexis Eyraud prev_speed = phydev->speed; 1005*f6465e36SLouis-Alexis Eyraud 1006*f6465e36SLouis-Alexis Eyraud ret = genphy_read_status(phydev); 1007*f6465e36SLouis-Alexis Eyraud if (ret) 1008*f6465e36SLouis-Alexis Eyraud return ret; 1009*f6465e36SLouis-Alexis Eyraud 1010*f6465e36SLouis-Alexis Eyraud if (!phydev->link) { 1011*f6465e36SLouis-Alexis Eyraud phydev->speed = SPEED_UNKNOWN; 1012*f6465e36SLouis-Alexis Eyraud return 0; 1013*f6465e36SLouis-Alexis Eyraud } 1014*f6465e36SLouis-Alexis Eyraud 1015*f6465e36SLouis-Alexis Eyraud if (prev_speed != phydev->speed) { 1016*f6465e36SLouis-Alexis Eyraud /* Ensure that PHY switches to 1G speed when available, 1017*f6465e36SLouis-Alexis Eyraud * by configuring the function mode for either 1G or 100M/10M 1018*f6465e36SLouis-Alexis Eyraud * operation. 1019*f6465e36SLouis-Alexis Eyraud * Therefore, set the link mode register, after read_status 1020*f6465e36SLouis-Alexis Eyraud * determines the link speed. 1021*f6465e36SLouis-Alexis Eyraud */ 1022*f6465e36SLouis-Alexis Eyraud val = phydev->speed == SPEED_1000 ? 1023*f6465e36SLouis-Alexis Eyraud AN8801_BPBUS_LINK_MODE_1000 : 0; 1024*f6465e36SLouis-Alexis Eyraud 1025*f6465e36SLouis-Alexis Eyraud return an8801_buckpbus_reg_rmw(phydev, 1026*f6465e36SLouis-Alexis Eyraud AN8801_BPBUS_REG_LINK_MODE, 1027*f6465e36SLouis-Alexis Eyraud AN8801_BPBUS_LINK_MODE_1000, 1028*f6465e36SLouis-Alexis Eyraud val); 1029*f6465e36SLouis-Alexis Eyraud } 1030*f6465e36SLouis-Alexis Eyraud 1031*f6465e36SLouis-Alexis Eyraud return 0; 1032*f6465e36SLouis-Alexis Eyraud } 1033*f6465e36SLouis-Alexis Eyraud 1034fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_probe(struct phy_device *phydev) 1035fdb9bf7fSAngeloGioacchino Del Regno { 1036fdb9bf7fSAngeloGioacchino Del Regno struct device *dev = &phydev->mdio.dev; 1037fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv *priv; 1038fdb9bf7fSAngeloGioacchino Del Regno 1039fdb9bf7fSAngeloGioacchino Del Regno priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 1040fdb9bf7fSAngeloGioacchino Del Regno if (!priv) 1041fdb9bf7fSAngeloGioacchino Del Regno return -ENOMEM; 1042fdb9bf7fSAngeloGioacchino Del Regno 1043fdb9bf7fSAngeloGioacchino Del Regno priv->wake_lnkchg_enabled = true; 1044fdb9bf7fSAngeloGioacchino Del Regno 1045fdb9bf7fSAngeloGioacchino Del Regno phydev->priv = priv; 1046fdb9bf7fSAngeloGioacchino Del Regno 1047fdb9bf7fSAngeloGioacchino Del Regno /* Mark this PHY as wakeup capable and register the interrupt as a 1048fdb9bf7fSAngeloGioacchino Del Regno * wakeup IRQ if the PHY is marked as a wakeup source in devicetree, 1049fdb9bf7fSAngeloGioacchino Del Regno * and the interrupt is valid. 1050fdb9bf7fSAngeloGioacchino Del Regno */ 1051fdb9bf7fSAngeloGioacchino Del Regno if (of_property_read_bool(dev->of_node, "wakeup-source") && 1052fdb9bf7fSAngeloGioacchino Del Regno phy_interrupt_is_valid(phydev)) { 1053fdb9bf7fSAngeloGioacchino Del Regno device_set_wakeup_capable(dev, true); 1054fdb9bf7fSAngeloGioacchino Del Regno devm_pm_set_wake_irq(dev, phydev->irq); 1055fdb9bf7fSAngeloGioacchino Del Regno } 1056fdb9bf7fSAngeloGioacchino Del Regno 1057fdb9bf7fSAngeloGioacchino Del Regno return 0; 1058fdb9bf7fSAngeloGioacchino Del Regno } 1059fdb9bf7fSAngeloGioacchino Del Regno 1060fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_suspend(struct phy_device *phydev) 1061fdb9bf7fSAngeloGioacchino Del Regno { 1062fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv *priv = phydev->priv; 1063fdb9bf7fSAngeloGioacchino Del Regno int ret; 1064fdb9bf7fSAngeloGioacchino Del Regno 1065fdb9bf7fSAngeloGioacchino Del Regno /* If the PHY may wake up by a Wake-on-LAN (WOL) event, disable the link 1066fdb9bf7fSAngeloGioacchino Del Regno * interrupt to only keep the WOL magic interrupt enabled 1067fdb9bf7fSAngeloGioacchino Del Regno */ 1068fdb9bf7fSAngeloGioacchino Del Regno if (device_may_wakeup(&phydev->mdio.dev)) { 1069fdb9bf7fSAngeloGioacchino Del Regno priv->wake_lnkchg_enabled = false; 1070fdb9bf7fSAngeloGioacchino Del Regno 1071fdb9bf7fSAngeloGioacchino Del Regno if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 1072fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_clear_bits(phydev, 1073fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 1074fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_LNKCHG); 1075fdb9bf7fSAngeloGioacchino Del Regno if (ret) 1076fdb9bf7fSAngeloGioacchino Del Regno return ret; 1077fdb9bf7fSAngeloGioacchino Del Regno } 1078fdb9bf7fSAngeloGioacchino Del Regno 1079fdb9bf7fSAngeloGioacchino Del Regno /* Reset WOL status */ 1080fdb9bf7fSAngeloGioacchino Del Regno ret = an8801r_reset_wake(phydev); 1081fdb9bf7fSAngeloGioacchino Del Regno if (ret) 1082fdb9bf7fSAngeloGioacchino Del Regno return ret; 1083fdb9bf7fSAngeloGioacchino Del Regno } 1084fdb9bf7fSAngeloGioacchino Del Regno 1085fdb9bf7fSAngeloGioacchino Del Regno if (!phydev->wol_enabled) 1086fdb9bf7fSAngeloGioacchino Del Regno return genphy_suspend(phydev); 1087fdb9bf7fSAngeloGioacchino Del Regno 1088fdb9bf7fSAngeloGioacchino Del Regno return 0; 1089fdb9bf7fSAngeloGioacchino Del Regno } 1090fdb9bf7fSAngeloGioacchino Del Regno 1091fdb9bf7fSAngeloGioacchino Del Regno static int an8801r_resume(struct phy_device *phydev) 1092fdb9bf7fSAngeloGioacchino Del Regno { 1093fdb9bf7fSAngeloGioacchino Del Regno struct an8801r_priv *priv = phydev->priv; 1094fdb9bf7fSAngeloGioacchino Del Regno int ret; 1095fdb9bf7fSAngeloGioacchino Del Regno 1096fdb9bf7fSAngeloGioacchino Del Regno ret = genphy_resume(phydev); 1097fdb9bf7fSAngeloGioacchino Del Regno if (ret) 1098fdb9bf7fSAngeloGioacchino Del Regno return ret; 1099fdb9bf7fSAngeloGioacchino Del Regno 1100fdb9bf7fSAngeloGioacchino Del Regno /* Restore the interrupt enable so phylib can receive link 1101fdb9bf7fSAngeloGioacchino Del Regno * state interrupts. 1102fdb9bf7fSAngeloGioacchino Del Regno */ 1103fdb9bf7fSAngeloGioacchino Del Regno if (device_may_wakeup(&phydev->mdio.dev)) { 1104fdb9bf7fSAngeloGioacchino Del Regno priv->wake_lnkchg_enabled = true; 1105fdb9bf7fSAngeloGioacchino Del Regno 1106fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 1107fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKEUP_CTL1, 1108fdb9bf7fSAngeloGioacchino Del Regno AN8801_WOL_WAKE_LNKCHG_EN); 1109fdb9bf7fSAngeloGioacchino Del Regno if (ret) 1110fdb9bf7fSAngeloGioacchino Del Regno return ret; 1111fdb9bf7fSAngeloGioacchino Del Regno 1112fdb9bf7fSAngeloGioacchino Del Regno if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 1113fdb9bf7fSAngeloGioacchino Del Regno ret = an8801_buckpbus_reg_set_bits(phydev, 1114fdb9bf7fSAngeloGioacchino Del Regno AN8801_BPBUS_REG_WAKE_IRQ_EN, 1115fdb9bf7fSAngeloGioacchino Del Regno AN8801_IRQ_WAKE_LNKCHG); 1116fdb9bf7fSAngeloGioacchino Del Regno } 1117fdb9bf7fSAngeloGioacchino Del Regno } 1118fdb9bf7fSAngeloGioacchino Del Regno 1119fdb9bf7fSAngeloGioacchino Del Regno return ret; 1120fdb9bf7fSAngeloGioacchino Del Regno } 1121fdb9bf7fSAngeloGioacchino Del Regno 1122fdb9bf7fSAngeloGioacchino Del Regno static struct phy_driver airoha_driver[] = { 1123fdb9bf7fSAngeloGioacchino Del Regno { 1124fdb9bf7fSAngeloGioacchino Del Regno PHY_ID_MATCH_MODEL(AN8801R_PHY_ID), 1125fdb9bf7fSAngeloGioacchino Del Regno .name = "Airoha AN8801R", 1126fdb9bf7fSAngeloGioacchino Del Regno .probe = an8801r_probe, 1127fdb9bf7fSAngeloGioacchino Del Regno .config_init = an8801r_config_init, 1128fdb9bf7fSAngeloGioacchino Del Regno .suspend = an8801r_suspend, 1129fdb9bf7fSAngeloGioacchino Del Regno .resume = an8801r_resume, 1130fdb9bf7fSAngeloGioacchino Del Regno .config_aneg = genphy_config_aneg, 1131*f6465e36SLouis-Alexis Eyraud .read_status = an8801r_read_status, 1132fdb9bf7fSAngeloGioacchino Del Regno .config_intr = an8801r_config_intr, 1133fdb9bf7fSAngeloGioacchino Del Regno .handle_interrupt = an8801r_handle_interrupt, 1134fdb9bf7fSAngeloGioacchino Del Regno .set_wol = an8801r_set_wol, 1135fdb9bf7fSAngeloGioacchino Del Regno .get_wol = an8801r_get_wol, 1136fdb9bf7fSAngeloGioacchino Del Regno .read_page = air_phy_read_page, 1137fdb9bf7fSAngeloGioacchino Del Regno .write_page = air_phy_write_page, 1138fdb9bf7fSAngeloGioacchino Del Regno .flags = PHY_ALWAYS_CALL_SUSPEND, 1139fdb9bf7fSAngeloGioacchino Del Regno .led_brightness_set = an8801r_led_brightness_set, 1140fdb9bf7fSAngeloGioacchino Del Regno .led_blink_set = an8801r_led_blink_set, 1141fdb9bf7fSAngeloGioacchino Del Regno .led_hw_is_supported = an8801r_led_hw_is_supported, 1142fdb9bf7fSAngeloGioacchino Del Regno .led_hw_control_set = an8801r_led_hw_control_set, 1143fdb9bf7fSAngeloGioacchino Del Regno .led_hw_control_get = an8801r_led_hw_control_get, 1144fdb9bf7fSAngeloGioacchino Del Regno .led_polarity_set = an8801r_led_polarity_set, 1145fdb9bf7fSAngeloGioacchino Del Regno } }; 1146fdb9bf7fSAngeloGioacchino Del Regno module_phy_driver(airoha_driver); 1147fdb9bf7fSAngeloGioacchino Del Regno 1148fdb9bf7fSAngeloGioacchino Del Regno static struct mdio_device_id __maybe_unused an8801_tbl[] = { 1149fdb9bf7fSAngeloGioacchino Del Regno { PHY_ID_MATCH_MODEL(AN8801R_PHY_ID) }, 1150fdb9bf7fSAngeloGioacchino Del Regno { } 1151fdb9bf7fSAngeloGioacchino Del Regno }; 1152fdb9bf7fSAngeloGioacchino Del Regno MODULE_DEVICE_TABLE(mdio, an8801_tbl); 1153fdb9bf7fSAngeloGioacchino Del Regno 1154fdb9bf7fSAngeloGioacchino Del Regno MODULE_DESCRIPTION("Airoha AN8801 PHY driver"); 1155fdb9bf7fSAngeloGioacchino Del Regno MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); 1156fdb9bf7fSAngeloGioacchino Del Regno MODULE_LICENSE("GPL"); 1157