Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'add-en8811h-phy-driver-and-devicetree-binding-doc'

Eric Woudstra says:

====================
Add en8811h phy driver and devicetree binding doc

This patch series adds the driver and the devicetree binding documentation
for the Airoha en8811h PHY.
====================

Link: https://lore.kernel.org/r/20240326162305.303598-1-ericwouds@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+1148
+56
Documentation/devicetree/bindings/net/airoha,en8811h.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/airoha,en8811h.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Airoha EN8811H PHY 8 + 9 + maintainers: 10 + - Eric Woudstra <ericwouds@gmail.com> 11 + 12 + description: 13 + The Airoha EN8811H PHY has the ability to reverse polarity 14 + on the lines to and/or from the MAC. It is reversed by 15 + the booleans in the devicetree node of the phy. 16 + 17 + allOf: 18 + - $ref: ethernet-phy.yaml# 19 + 20 + properties: 21 + compatible: 22 + enum: 23 + - ethernet-phy-id03a2.a411 24 + 25 + reg: 26 + maxItems: 1 27 + 28 + airoha,pnswap-rx: 29 + type: boolean 30 + description: 31 + Reverse rx polarity of the SERDES. This is the receiving 32 + side of the lines from the MAC towards the EN881H. 33 + 34 + airoha,pnswap-tx: 35 + type: boolean 36 + description: 37 + Reverse tx polarity of SERDES. This is the transmitting 38 + side of the lines from EN8811H towards the MAC. 39 + 40 + required: 41 + - reg 42 + 43 + unevaluatedProperties: false 44 + 45 + examples: 46 + - | 47 + mdio { 48 + #address-cells = <1>; 49 + #size-cells = <0>; 50 + 51 + ethernet-phy@1 { 52 + compatible = "ethernet-phy-id03a2.a411"; 53 + reg = <1>; 54 + airoha,pnswap-rx; 55 + }; 56 + };
+5
drivers/net/phy/Kconfig
··· 76 76 77 77 comment "MII PHY device drivers" 78 78 79 + config AIR_EN8811H_PHY 80 + tristate "Airoha EN8811H 2.5 Gigabit PHY" 81 + help 82 + Currently supports the Airoha EN8811H PHY. 83 + 79 84 config AMD_PHY 80 85 tristate "AMD and Altima PHYs" 81 86 help
+1
drivers/net/phy/Makefile
··· 34 34 35 35 obj-$(CONFIG_ADIN_PHY) += adin.o 36 36 obj-$(CONFIG_ADIN1100_PHY) += adin1100.o 37 + obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o 37 38 obj-$(CONFIG_AMD_PHY) += amd.o 38 39 obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ 39 40 ifdef CONFIG_AX88796B_RUST_PHY
+1086
drivers/net/phy/air_en8811h.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Driver for the Airoha EN8811H 2.5 Gigabit PHY. 4 + * 5 + * Limitations of the EN8811H: 6 + * - Only full duplex supported 7 + * - Forced speed (AN off) is not supported by hardware (100Mbps) 8 + * 9 + * Source originated from airoha's en8811h.c and en8811h.h v1.2.1 10 + * 11 + * Copyright (C) 2023 Airoha Technology Corp. 12 + */ 13 + 14 + #include <linux/phy.h> 15 + #include <linux/firmware.h> 16 + #include <linux/property.h> 17 + #include <linux/wordpart.h> 18 + #include <asm/unaligned.h> 19 + 20 + #define EN8811H_PHY_ID 0x03a2a411 21 + 22 + #define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" 23 + #define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" 24 + 25 + #define AIR_FW_ADDR_DM 0x00000000 26 + #define AIR_FW_ADDR_DSP 0x00100000 27 + 28 + /* MII Registers */ 29 + #define AIR_AUX_CTRL_STATUS 0x1d 30 + #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) 31 + #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4 32 + #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 33 + #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc 34 + 35 + #define AIR_EXT_PAGE_ACCESS 0x1f 36 + #define AIR_PHY_PAGE_STANDARD 0x0000 37 + #define AIR_PHY_PAGE_EXTENDED_4 0x0004 38 + 39 + /* MII Registers Page 4*/ 40 + #define AIR_BPBUS_MODE 0x10 41 + #define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 42 + #define AIR_BPBUS_MODE_ADDR_INCR BIT(15) 43 + #define AIR_BPBUS_WR_ADDR_HIGH 0x11 44 + #define AIR_BPBUS_WR_ADDR_LOW 0x12 45 + #define AIR_BPBUS_WR_DATA_HIGH 0x13 46 + #define AIR_BPBUS_WR_DATA_LOW 0x14 47 + #define AIR_BPBUS_RD_ADDR_HIGH 0x15 48 + #define AIR_BPBUS_RD_ADDR_LOW 0x16 49 + #define AIR_BPBUS_RD_DATA_HIGH 0x17 50 + #define AIR_BPBUS_RD_DATA_LOW 0x18 51 + 52 + /* Registers on MDIO_MMD_VEND1 */ 53 + #define EN8811H_PHY_FW_STATUS 0x8009 54 + #define EN8811H_PHY_READY 0x02 55 + 56 + #define AIR_PHY_MCU_CMD_1 0x800c 57 + #define AIR_PHY_MCU_CMD_1_MODE1 0x0 58 + #define AIR_PHY_MCU_CMD_2 0x800d 59 + #define AIR_PHY_MCU_CMD_2_MODE1 0x0 60 + #define AIR_PHY_MCU_CMD_3 0x800e 61 + #define AIR_PHY_MCU_CMD_3_MODE1 0x1101 62 + #define AIR_PHY_MCU_CMD_3_DOCMD 0x1100 63 + #define AIR_PHY_MCU_CMD_4 0x800f 64 + #define AIR_PHY_MCU_CMD_4_MODE1 0x0002 65 + #define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4 66 + 67 + /* Registers on MDIO_MMD_VEND2 */ 68 + #define AIR_PHY_LED_BCR 0x021 69 + #define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0) 70 + #define AIR_PHY_LED_BCR_TIME_TEST BIT(2) 71 + #define AIR_PHY_LED_BCR_CLK_EN BIT(3) 72 + #define AIR_PHY_LED_BCR_EXT_CTRL BIT(15) 73 + 74 + #define AIR_PHY_LED_DUR_ON 0x022 75 + 76 + #define AIR_PHY_LED_DUR_BLINK 0x023 77 + 78 + #define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2)) 79 + #define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8)) 80 + #define AIR_PHY_LED_ON_LINK1000 BIT(0) 81 + #define AIR_PHY_LED_ON_LINK100 BIT(1) 82 + #define AIR_PHY_LED_ON_LINK10 BIT(2) 83 + #define AIR_PHY_LED_ON_LINKDOWN BIT(3) 84 + #define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */ 85 + #define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */ 86 + #define AIR_PHY_LED_ON_FORCE_ON BIT(6) 87 + #define AIR_PHY_LED_ON_LINK2500 BIT(8) 88 + #define AIR_PHY_LED_ON_POLARITY BIT(14) 89 + #define AIR_PHY_LED_ON_ENABLE BIT(15) 90 + 91 + #define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2)) 92 + #define AIR_PHY_LED_BLINK_1000TX BIT(0) 93 + #define AIR_PHY_LED_BLINK_1000RX BIT(1) 94 + #define AIR_PHY_LED_BLINK_100TX BIT(2) 95 + #define AIR_PHY_LED_BLINK_100RX BIT(3) 96 + #define AIR_PHY_LED_BLINK_10TX BIT(4) 97 + #define AIR_PHY_LED_BLINK_10RX BIT(5) 98 + #define AIR_PHY_LED_BLINK_COLLISION BIT(6) 99 + #define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7) 100 + #define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) 101 + #define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9) 102 + #define AIR_PHY_LED_BLINK_2500TX BIT(10) 103 + #define AIR_PHY_LED_BLINK_2500RX BIT(11) 104 + 105 + /* Registers on BUCKPBUS */ 106 + #define EN8811H_2P5G_LPA 0x3b30 107 + #define EN8811H_2P5G_LPA_2P5G BIT(0) 108 + 109 + #define EN8811H_FW_VERSION 0x3b3c 110 + 111 + #define EN8811H_POLARITY 0xca0f8 112 + #define EN8811H_POLARITY_TX_NORMAL BIT(0) 113 + #define EN8811H_POLARITY_RX_REVERSE BIT(1) 114 + 115 + #define EN8811H_GPIO_OUTPUT 0xcf8b8 116 + #define EN8811H_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5)) 117 + 118 + #define EN8811H_FW_CTRL_1 0x0f0018 119 + #define EN8811H_FW_CTRL_1_START 0x0 120 + #define EN8811H_FW_CTRL_1_FINISH 0x1 121 + #define EN8811H_FW_CTRL_2 0x800000 122 + #define EN8811H_FW_CTRL_2_LOADING BIT(11) 123 + 124 + /* Led definitions */ 125 + #define EN8811H_LED_COUNT 3 126 + 127 + /* Default LED setup: 128 + * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx 129 + * GPIO4 <-> LED1 On: Link detected at 2500 or 1000 Mbps 130 + * GPIO3 <-> LED2 On: Link detected at 2500 or 100 Mbps 131 + */ 132 + #define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK) | \ 133 + BIT(TRIGGER_NETDEV_RX) | \ 134 + BIT(TRIGGER_NETDEV_TX)) 135 + #define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \ 136 + BIT(TRIGGER_NETDEV_LINK_1000)) 137 + #define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \ 138 + BIT(TRIGGER_NETDEV_LINK_100)) 139 + 140 + struct led { 141 + unsigned long rules; 142 + unsigned long state; 143 + }; 144 + 145 + struct en8811h_priv { 146 + u32 firmware_version; 147 + bool mcu_needs_restart; 148 + struct led led[EN8811H_LED_COUNT]; 149 + }; 150 + 151 + enum { 152 + AIR_PHY_LED_STATE_FORCE_ON, 153 + AIR_PHY_LED_STATE_FORCE_BLINK, 154 + }; 155 + 156 + enum { 157 + AIR_PHY_LED_DUR_BLINK_32MS, 158 + AIR_PHY_LED_DUR_BLINK_64MS, 159 + AIR_PHY_LED_DUR_BLINK_128MS, 160 + AIR_PHY_LED_DUR_BLINK_256MS, 161 + AIR_PHY_LED_DUR_BLINK_512MS, 162 + AIR_PHY_LED_DUR_BLINK_1024MS, 163 + }; 164 + 165 + enum { 166 + AIR_LED_DISABLE, 167 + AIR_LED_ENABLE, 168 + }; 169 + 170 + enum { 171 + AIR_ACTIVE_LOW, 172 + AIR_ACTIVE_HIGH, 173 + }; 174 + 175 + enum { 176 + AIR_LED_MODE_DISABLE, 177 + AIR_LED_MODE_USER_DEFINE, 178 + }; 179 + 180 + #define AIR_PHY_LED_DUR_UNIT 1024 181 + #define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS) 182 + 183 + static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) | 184 + BIT(TRIGGER_NETDEV_LINK) | 185 + BIT(TRIGGER_NETDEV_LINK_10) | 186 + BIT(TRIGGER_NETDEV_LINK_100) | 187 + BIT(TRIGGER_NETDEV_LINK_1000) | 188 + BIT(TRIGGER_NETDEV_LINK_2500) | 189 + BIT(TRIGGER_NETDEV_RX) | 190 + BIT(TRIGGER_NETDEV_TX); 191 + 192 + static int air_phy_read_page(struct phy_device *phydev) 193 + { 194 + return __phy_read(phydev, AIR_EXT_PAGE_ACCESS); 195 + } 196 + 197 + static int air_phy_write_page(struct phy_device *phydev, int page) 198 + { 199 + return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page); 200 + } 201 + 202 + static int __air_buckpbus_reg_write(struct phy_device *phydev, 203 + u32 pbus_address, u32 pbus_data) 204 + { 205 + int ret; 206 + 207 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); 208 + if (ret < 0) 209 + return ret; 210 + 211 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, 212 + upper_16_bits(pbus_address)); 213 + if (ret < 0) 214 + return ret; 215 + 216 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, 217 + lower_16_bits(pbus_address)); 218 + if (ret < 0) 219 + return ret; 220 + 221 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, 222 + upper_16_bits(pbus_data)); 223 + if (ret < 0) 224 + return ret; 225 + 226 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, 227 + lower_16_bits(pbus_data)); 228 + if (ret < 0) 229 + return ret; 230 + 231 + return 0; 232 + } 233 + 234 + static int air_buckpbus_reg_write(struct phy_device *phydev, 235 + u32 pbus_address, u32 pbus_data) 236 + { 237 + int saved_page; 238 + int ret = 0; 239 + 240 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); 241 + 242 + if (saved_page >= 0) { 243 + ret = __air_buckpbus_reg_write(phydev, pbus_address, 244 + pbus_data); 245 + if (ret < 0) 246 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, 247 + pbus_address, ret); 248 + } 249 + 250 + return phy_restore_page(phydev, saved_page, ret); 251 + } 252 + 253 + static int __air_buckpbus_reg_read(struct phy_device *phydev, 254 + u32 pbus_address, u32 *pbus_data) 255 + { 256 + int pbus_data_low, pbus_data_high; 257 + int ret; 258 + 259 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); 260 + if (ret < 0) 261 + return ret; 262 + 263 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, 264 + upper_16_bits(pbus_address)); 265 + if (ret < 0) 266 + return ret; 267 + 268 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, 269 + lower_16_bits(pbus_address)); 270 + if (ret < 0) 271 + return ret; 272 + 273 + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); 274 + if (pbus_data_high < 0) 275 + return ret; 276 + 277 + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); 278 + if (pbus_data_low < 0) 279 + return ret; 280 + 281 + *pbus_data = pbus_data_low | (pbus_data_high << 16); 282 + return 0; 283 + } 284 + 285 + static int air_buckpbus_reg_read(struct phy_device *phydev, 286 + u32 pbus_address, u32 *pbus_data) 287 + { 288 + int saved_page; 289 + int ret = 0; 290 + 291 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); 292 + 293 + if (saved_page >= 0) { 294 + ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); 295 + if (ret < 0) 296 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, 297 + pbus_address, ret); 298 + } 299 + 300 + return phy_restore_page(phydev, saved_page, ret); 301 + } 302 + 303 + static int __air_buckpbus_reg_modify(struct phy_device *phydev, 304 + u32 pbus_address, u32 mask, u32 set) 305 + { 306 + int pbus_data_low, pbus_data_high; 307 + u32 pbus_data_old, pbus_data_new; 308 + int ret; 309 + 310 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); 311 + if (ret < 0) 312 + return ret; 313 + 314 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, 315 + upper_16_bits(pbus_address)); 316 + if (ret < 0) 317 + return ret; 318 + 319 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, 320 + lower_16_bits(pbus_address)); 321 + if (ret < 0) 322 + return ret; 323 + 324 + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); 325 + if (pbus_data_high < 0) 326 + return ret; 327 + 328 + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); 329 + if (pbus_data_low < 0) 330 + return ret; 331 + 332 + pbus_data_old = pbus_data_low | (pbus_data_high << 16); 333 + pbus_data_new = (pbus_data_old & ~mask) | set; 334 + if (pbus_data_new == pbus_data_old) 335 + return 0; 336 + 337 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, 338 + upper_16_bits(pbus_address)); 339 + if (ret < 0) 340 + return ret; 341 + 342 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, 343 + lower_16_bits(pbus_address)); 344 + if (ret < 0) 345 + return ret; 346 + 347 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, 348 + upper_16_bits(pbus_data_new)); 349 + if (ret < 0) 350 + return ret; 351 + 352 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, 353 + lower_16_bits(pbus_data_new)); 354 + if (ret < 0) 355 + return ret; 356 + 357 + return 0; 358 + } 359 + 360 + static int air_buckpbus_reg_modify(struct phy_device *phydev, 361 + u32 pbus_address, u32 mask, u32 set) 362 + { 363 + int saved_page; 364 + int ret = 0; 365 + 366 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); 367 + 368 + if (saved_page >= 0) { 369 + ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, 370 + set); 371 + if (ret < 0) 372 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, 373 + pbus_address, ret); 374 + } 375 + 376 + return phy_restore_page(phydev, saved_page, ret); 377 + } 378 + 379 + static int __air_write_buf(struct phy_device *phydev, u32 address, 380 + const struct firmware *fw) 381 + { 382 + unsigned int offset; 383 + int ret; 384 + u16 val; 385 + 386 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR); 387 + if (ret < 0) 388 + return ret; 389 + 390 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, 391 + upper_16_bits(address)); 392 + if (ret < 0) 393 + return ret; 394 + 395 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, 396 + lower_16_bits(address)); 397 + if (ret < 0) 398 + return ret; 399 + 400 + for (offset = 0; offset < fw->size; offset += 4) { 401 + val = get_unaligned_le16(&fw->data[offset + 2]); 402 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val); 403 + if (ret < 0) 404 + return ret; 405 + 406 + val = get_unaligned_le16(&fw->data[offset]); 407 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val); 408 + if (ret < 0) 409 + return ret; 410 + } 411 + 412 + return 0; 413 + } 414 + 415 + static int air_write_buf(struct phy_device *phydev, u32 address, 416 + const struct firmware *fw) 417 + { 418 + int saved_page; 419 + int ret = 0; 420 + 421 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); 422 + 423 + if (saved_page >= 0) { 424 + ret = __air_write_buf(phydev, address, fw); 425 + if (ret < 0) 426 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, 427 + address, ret); 428 + } 429 + 430 + return phy_restore_page(phydev, saved_page, ret); 431 + } 432 + 433 + static int en8811h_wait_mcu_ready(struct phy_device *phydev) 434 + { 435 + int ret, reg_value; 436 + 437 + /* Because of mdio-lock, may have to wait for multiple loads */ 438 + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 439 + EN8811H_PHY_FW_STATUS, reg_value, 440 + reg_value == EN8811H_PHY_READY, 441 + 20000, 7500000, true); 442 + if (ret) { 443 + phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value); 444 + return -ENODEV; 445 + } 446 + 447 + return 0; 448 + } 449 + 450 + static int en8811h_load_firmware(struct phy_device *phydev) 451 + { 452 + struct en8811h_priv *priv = phydev->priv; 453 + struct device *dev = &phydev->mdio.dev; 454 + const struct firmware *fw1, *fw2; 455 + int ret; 456 + 457 + ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev); 458 + if (ret < 0) 459 + return ret; 460 + 461 + ret = request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev); 462 + if (ret < 0) 463 + goto en8811h_load_firmware_rel1; 464 + 465 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 466 + EN8811H_FW_CTRL_1_START); 467 + if (ret < 0) 468 + goto en8811h_load_firmware_out; 469 + 470 + ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, 471 + EN8811H_FW_CTRL_2_LOADING, 472 + EN8811H_FW_CTRL_2_LOADING); 473 + if (ret < 0) 474 + goto en8811h_load_firmware_out; 475 + 476 + ret = air_write_buf(phydev, AIR_FW_ADDR_DM, fw1); 477 + if (ret < 0) 478 + goto en8811h_load_firmware_out; 479 + 480 + ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, fw2); 481 + if (ret < 0) 482 + goto en8811h_load_firmware_out; 483 + 484 + ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, 485 + EN8811H_FW_CTRL_2_LOADING, 0); 486 + if (ret < 0) 487 + goto en8811h_load_firmware_out; 488 + 489 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 490 + EN8811H_FW_CTRL_1_FINISH); 491 + if (ret < 0) 492 + goto en8811h_load_firmware_out; 493 + 494 + ret = en8811h_wait_mcu_ready(phydev); 495 + 496 + air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, 497 + &priv->firmware_version); 498 + phydev_info(phydev, "MD32 firmware version: %08x\n", 499 + priv->firmware_version); 500 + 501 + en8811h_load_firmware_out: 502 + release_firmware(fw2); 503 + 504 + en8811h_load_firmware_rel1: 505 + release_firmware(fw1); 506 + 507 + if (ret < 0) 508 + phydev_err(phydev, "Load firmware failed: %d\n", ret); 509 + 510 + return ret; 511 + } 512 + 513 + static int en8811h_restart_mcu(struct phy_device *phydev) 514 + { 515 + int ret; 516 + 517 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 518 + EN8811H_FW_CTRL_1_START); 519 + if (ret < 0) 520 + return ret; 521 + 522 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 523 + EN8811H_FW_CTRL_1_FINISH); 524 + if (ret < 0) 525 + return ret; 526 + 527 + return en8811h_wait_mcu_ready(phydev); 528 + } 529 + 530 + static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on) 531 + { 532 + struct en8811h_priv *priv = phydev->priv; 533 + bool changed; 534 + 535 + if (index >= EN8811H_LED_COUNT) 536 + return -EINVAL; 537 + 538 + if (on) 539 + changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_ON, 540 + &priv->led[index].state); 541 + else 542 + changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_ON, 543 + &priv->led[index].state); 544 + 545 + changed |= (priv->led[index].rules != 0); 546 + 547 + if (changed) 548 + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, 549 + AIR_PHY_LED_ON(index), 550 + AIR_PHY_LED_ON_MASK, 551 + on ? AIR_PHY_LED_ON_FORCE_ON : 0); 552 + 553 + return 0; 554 + } 555 + 556 + static int air_hw_led_blink_set(struct phy_device *phydev, u8 index, 557 + bool blinking) 558 + { 559 + struct en8811h_priv *priv = phydev->priv; 560 + bool changed; 561 + 562 + if (index >= EN8811H_LED_COUNT) 563 + return -EINVAL; 564 + 565 + if (blinking) 566 + changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_BLINK, 567 + &priv->led[index].state); 568 + else 569 + changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, 570 + &priv->led[index].state); 571 + 572 + changed |= (priv->led[index].rules != 0); 573 + 574 + if (changed) 575 + return phy_write_mmd(phydev, MDIO_MMD_VEND2, 576 + AIR_PHY_LED_BLINK(index), 577 + blinking ? 578 + AIR_PHY_LED_BLINK_FORCE_BLINK : 0); 579 + else 580 + return 0; 581 + } 582 + 583 + static int air_led_blink_set(struct phy_device *phydev, u8 index, 584 + unsigned long *delay_on, 585 + unsigned long *delay_off) 586 + { 587 + struct en8811h_priv *priv = phydev->priv; 588 + bool blinking = false; 589 + int err; 590 + 591 + if (index >= EN8811H_LED_COUNT) 592 + return -EINVAL; 593 + 594 + if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { 595 + blinking = true; 596 + *delay_on = 50; 597 + *delay_off = 50; 598 + } 599 + 600 + err = air_hw_led_blink_set(phydev, index, blinking); 601 + if (err) 602 + return err; 603 + 604 + /* led-blink set, so switch led-on off */ 605 + err = air_hw_led_on_set(phydev, index, false); 606 + if (err) 607 + return err; 608 + 609 + /* hw-control is off*/ 610 + if (!!test_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state)) 611 + priv->led[index].rules = 0; 612 + 613 + return 0; 614 + } 615 + 616 + static int air_led_brightness_set(struct phy_device *phydev, u8 index, 617 + enum led_brightness value) 618 + { 619 + struct en8811h_priv *priv = phydev->priv; 620 + int err; 621 + 622 + if (index >= EN8811H_LED_COUNT) 623 + return -EINVAL; 624 + 625 + /* led-on set, so switch led-blink off */ 626 + err = air_hw_led_blink_set(phydev, index, false); 627 + if (err) 628 + return err; 629 + 630 + err = air_hw_led_on_set(phydev, index, (value != LED_OFF)); 631 + if (err) 632 + return err; 633 + 634 + /* hw-control is off */ 635 + if (!!test_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state)) 636 + priv->led[index].rules = 0; 637 + 638 + return 0; 639 + } 640 + 641 + static int air_led_hw_control_get(struct phy_device *phydev, u8 index, 642 + unsigned long *rules) 643 + { 644 + struct en8811h_priv *priv = phydev->priv; 645 + 646 + if (index >= EN8811H_LED_COUNT) 647 + return -EINVAL; 648 + 649 + *rules = priv->led[index].rules; 650 + 651 + return 0; 652 + }; 653 + 654 + static int air_led_hw_control_set(struct phy_device *phydev, u8 index, 655 + unsigned long rules) 656 + { 657 + struct en8811h_priv *priv = phydev->priv; 658 + u16 on = 0, blink = 0; 659 + int ret; 660 + 661 + if (index >= EN8811H_LED_COUNT) 662 + return -EINVAL; 663 + 664 + priv->led[index].rules = rules; 665 + 666 + if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) 667 + on |= AIR_PHY_LED_ON_FDX; 668 + 669 + if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) 670 + on |= AIR_PHY_LED_ON_LINK10; 671 + 672 + if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) 673 + on |= AIR_PHY_LED_ON_LINK100; 674 + 675 + if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) 676 + on |= AIR_PHY_LED_ON_LINK1000; 677 + 678 + if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) 679 + on |= AIR_PHY_LED_ON_LINK2500; 680 + 681 + if (rules & BIT(TRIGGER_NETDEV_RX)) { 682 + blink |= AIR_PHY_LED_BLINK_10RX | 683 + AIR_PHY_LED_BLINK_100RX | 684 + AIR_PHY_LED_BLINK_1000RX | 685 + AIR_PHY_LED_BLINK_2500RX; 686 + } 687 + 688 + if (rules & BIT(TRIGGER_NETDEV_TX)) { 689 + blink |= AIR_PHY_LED_BLINK_10TX | 690 + AIR_PHY_LED_BLINK_100TX | 691 + AIR_PHY_LED_BLINK_1000TX | 692 + AIR_PHY_LED_BLINK_2500TX; 693 + } 694 + 695 + if (blink || on) { 696 + /* switch hw-control on, so led-on and led-blink are off */ 697 + clear_bit(AIR_PHY_LED_STATE_FORCE_ON, 698 + &priv->led[index].state); 699 + clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, 700 + &priv->led[index].state); 701 + } else { 702 + priv->led[index].rules = 0; 703 + } 704 + 705 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), 706 + AIR_PHY_LED_ON_MASK, on); 707 + 708 + if (ret < 0) 709 + return ret; 710 + 711 + return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index), 712 + blink); 713 + }; 714 + 715 + static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol) 716 + { 717 + int val = 0; 718 + int err; 719 + 720 + if (index >= EN8811H_LED_COUNT) 721 + return -EINVAL; 722 + 723 + if (state == AIR_LED_ENABLE) 724 + val |= AIR_PHY_LED_ON_ENABLE; 725 + else 726 + val &= ~AIR_PHY_LED_ON_ENABLE; 727 + 728 + if (pol == AIR_ACTIVE_HIGH) 729 + val |= AIR_PHY_LED_ON_POLARITY; 730 + else 731 + val &= ~AIR_PHY_LED_ON_POLARITY; 732 + 733 + err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), 734 + AIR_PHY_LED_ON_ENABLE | 735 + AIR_PHY_LED_ON_POLARITY, val); 736 + 737 + if (err < 0) 738 + return err; 739 + 740 + return 0; 741 + } 742 + 743 + static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode) 744 + { 745 + struct en8811h_priv *priv = phydev->priv; 746 + int ret, i; 747 + 748 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK, 749 + dur); 750 + if (ret < 0) 751 + return ret; 752 + 753 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON, 754 + dur >> 1); 755 + if (ret < 0) 756 + return ret; 757 + 758 + switch (mode) { 759 + case AIR_LED_MODE_DISABLE: 760 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, 761 + AIR_PHY_LED_BCR_EXT_CTRL | 762 + AIR_PHY_LED_BCR_MODE_MASK, 0); 763 + if (ret < 0) 764 + return ret; 765 + break; 766 + case AIR_LED_MODE_USER_DEFINE: 767 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, 768 + AIR_PHY_LED_BCR_EXT_CTRL | 769 + AIR_PHY_LED_BCR_CLK_EN, 770 + AIR_PHY_LED_BCR_EXT_CTRL | 771 + AIR_PHY_LED_BCR_CLK_EN); 772 + if (ret < 0) 773 + return ret; 774 + break; 775 + default: 776 + phydev_err(phydev, "LED mode %d is not supported\n", mode); 777 + return -EINVAL; 778 + } 779 + 780 + for (i = 0; i < num; ++i) { 781 + ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH); 782 + if (ret < 0) { 783 + phydev_err(phydev, "LED%d init failed: %d\n", i, ret); 784 + return ret; 785 + } 786 + air_led_hw_control_set(phydev, i, priv->led[i].rules); 787 + } 788 + 789 + return 0; 790 + } 791 + 792 + static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index, 793 + unsigned long rules) 794 + { 795 + if (index >= EN8811H_LED_COUNT) 796 + return -EINVAL; 797 + 798 + /* All combinations of the supported triggers are allowed */ 799 + if (rules & ~en8811h_led_trig) 800 + return -EOPNOTSUPP; 801 + 802 + return 0; 803 + }; 804 + 805 + static int en8811h_probe(struct phy_device *phydev) 806 + { 807 + struct en8811h_priv *priv; 808 + int ret; 809 + 810 + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv), 811 + GFP_KERNEL); 812 + if (!priv) 813 + return -ENOMEM; 814 + phydev->priv = priv; 815 + 816 + ret = en8811h_load_firmware(phydev); 817 + if (ret < 0) 818 + return ret; 819 + 820 + /* mcu has just restarted after firmware load */ 821 + priv->mcu_needs_restart = false; 822 + 823 + priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; 824 + priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; 825 + priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; 826 + 827 + /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ 828 + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; 829 + 830 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, 831 + AIR_LED_MODE_DISABLE); 832 + if (ret < 0) { 833 + phydev_err(phydev, "Failed to disable leds: %d\n", ret); 834 + return ret; 835 + } 836 + 837 + /* Configure led gpio pins as output */ 838 + ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT, 839 + EN8811H_GPIO_OUTPUT_345, 840 + EN8811H_GPIO_OUTPUT_345); 841 + if (ret < 0) 842 + return ret; 843 + 844 + return 0; 845 + } 846 + 847 + static int en8811h_config_init(struct phy_device *phydev) 848 + { 849 + struct en8811h_priv *priv = phydev->priv; 850 + struct device *dev = &phydev->mdio.dev; 851 + u32 pbus_value; 852 + int ret; 853 + 854 + /* If restart happened in .probe(), no need to restart now */ 855 + if (priv->mcu_needs_restart) { 856 + ret = en8811h_restart_mcu(phydev); 857 + if (ret < 0) 858 + return ret; 859 + } else { 860 + /* Next calls to .config_init() mcu needs to restart */ 861 + priv->mcu_needs_restart = true; 862 + } 863 + 864 + /* Select mode 1, the only mode supported. 865 + * Configures the SerDes for 2500Base-X with rate adaptation 866 + */ 867 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1, 868 + AIR_PHY_MCU_CMD_1_MODE1); 869 + if (ret < 0) 870 + return ret; 871 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2, 872 + AIR_PHY_MCU_CMD_2_MODE1); 873 + if (ret < 0) 874 + return ret; 875 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, 876 + AIR_PHY_MCU_CMD_3_MODE1); 877 + if (ret < 0) 878 + return ret; 879 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, 880 + AIR_PHY_MCU_CMD_4_MODE1); 881 + if (ret < 0) 882 + return ret; 883 + 884 + /* Serdes polarity */ 885 + pbus_value = 0; 886 + if (device_property_read_bool(dev, "airoha,pnswap-rx")) 887 + pbus_value |= EN8811H_POLARITY_RX_REVERSE; 888 + else 889 + pbus_value &= ~EN8811H_POLARITY_RX_REVERSE; 890 + if (device_property_read_bool(dev, "airoha,pnswap-tx")) 891 + pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; 892 + else 893 + pbus_value |= EN8811H_POLARITY_TX_NORMAL; 894 + ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, 895 + EN8811H_POLARITY_RX_REVERSE | 896 + EN8811H_POLARITY_TX_NORMAL, pbus_value); 897 + if (ret < 0) 898 + return ret; 899 + 900 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, 901 + AIR_LED_MODE_USER_DEFINE); 902 + if (ret < 0) { 903 + phydev_err(phydev, "Failed to initialize leds: %d\n", ret); 904 + return ret; 905 + } 906 + 907 + return 0; 908 + } 909 + 910 + static int en8811h_get_features(struct phy_device *phydev) 911 + { 912 + linkmode_set_bit_array(phy_basic_ports_array, 913 + ARRAY_SIZE(phy_basic_ports_array), 914 + phydev->supported); 915 + 916 + return genphy_c45_pma_read_abilities(phydev); 917 + } 918 + 919 + static int en8811h_get_rate_matching(struct phy_device *phydev, 920 + phy_interface_t iface) 921 + { 922 + return RATE_MATCH_PAUSE; 923 + } 924 + 925 + static int en8811h_config_aneg(struct phy_device *phydev) 926 + { 927 + bool changed = false; 928 + int ret; 929 + u32 adv; 930 + 931 + if (phydev->autoneg == AUTONEG_DISABLE) { 932 + phydev_warn(phydev, "Disabling autoneg is not supported\n"); 933 + return -EINVAL; 934 + } 935 + 936 + adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); 937 + 938 + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, 939 + MDIO_AN_10GBT_CTRL_ADV2_5G, adv); 940 + if (ret < 0) 941 + return ret; 942 + if (ret > 0) 943 + changed = true; 944 + 945 + return __genphy_config_aneg(phydev, changed); 946 + } 947 + 948 + static int en8811h_read_status(struct phy_device *phydev) 949 + { 950 + struct en8811h_priv *priv = phydev->priv; 951 + u32 pbus_value; 952 + int ret, val; 953 + 954 + ret = genphy_update_link(phydev); 955 + if (ret) 956 + return ret; 957 + 958 + phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED; 959 + phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; 960 + phydev->speed = SPEED_UNKNOWN; 961 + phydev->duplex = DUPLEX_UNKNOWN; 962 + phydev->pause = 0; 963 + phydev->asym_pause = 0; 964 + phydev->rate_matching = RATE_MATCH_PAUSE; 965 + 966 + ret = genphy_read_master_slave(phydev); 967 + if (ret < 0) 968 + return ret; 969 + 970 + ret = genphy_read_lpa(phydev); 971 + if (ret < 0) 972 + return ret; 973 + 974 + /* Get link partner 2.5GBASE-T ability from vendor register */ 975 + ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value); 976 + if (ret < 0) 977 + return ret; 978 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 979 + phydev->lp_advertising, 980 + pbus_value & EN8811H_2P5G_LPA_2P5G); 981 + 982 + if (phydev->autoneg_complete) 983 + phy_resolve_aneg_pause(phydev); 984 + 985 + if (!phydev->link) 986 + return 0; 987 + 988 + /* Get real speed from vendor register */ 989 + val = phy_read(phydev, AIR_AUX_CTRL_STATUS); 990 + if (val < 0) 991 + return val; 992 + switch (val & AIR_AUX_CTRL_STATUS_SPEED_MASK) { 993 + case AIR_AUX_CTRL_STATUS_SPEED_2500: 994 + phydev->speed = SPEED_2500; 995 + break; 996 + case AIR_AUX_CTRL_STATUS_SPEED_1000: 997 + phydev->speed = SPEED_1000; 998 + break; 999 + case AIR_AUX_CTRL_STATUS_SPEED_100: 1000 + phydev->speed = SPEED_100; 1001 + break; 1002 + } 1003 + 1004 + /* Firmware before version 24011202 has no vendor register 2P5G_LPA. 1005 + * Assume link partner advertised it if connected at 2500Mbps. 1006 + */ 1007 + if (priv->firmware_version < 0x24011202) { 1008 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 1009 + phydev->lp_advertising, 1010 + phydev->speed == SPEED_2500); 1011 + } 1012 + 1013 + /* Only supports full duplex */ 1014 + phydev->duplex = DUPLEX_FULL; 1015 + 1016 + return 0; 1017 + } 1018 + 1019 + static int en8811h_clear_intr(struct phy_device *phydev) 1020 + { 1021 + int ret; 1022 + 1023 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3, 1024 + AIR_PHY_MCU_CMD_3_DOCMD); 1025 + if (ret < 0) 1026 + return ret; 1027 + 1028 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4, 1029 + AIR_PHY_MCU_CMD_4_INTCLR); 1030 + if (ret < 0) 1031 + return ret; 1032 + 1033 + return 0; 1034 + } 1035 + 1036 + static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev) 1037 + { 1038 + int ret; 1039 + 1040 + ret = en8811h_clear_intr(phydev); 1041 + if (ret < 0) { 1042 + phy_error(phydev); 1043 + return IRQ_NONE; 1044 + } 1045 + 1046 + phy_trigger_machine(phydev); 1047 + 1048 + return IRQ_HANDLED; 1049 + } 1050 + 1051 + static struct phy_driver en8811h_driver[] = { 1052 + { 1053 + PHY_ID_MATCH_MODEL(EN8811H_PHY_ID), 1054 + .name = "Airoha EN8811H", 1055 + .probe = en8811h_probe, 1056 + .get_features = en8811h_get_features, 1057 + .config_init = en8811h_config_init, 1058 + .get_rate_matching = en8811h_get_rate_matching, 1059 + .config_aneg = en8811h_config_aneg, 1060 + .read_status = en8811h_read_status, 1061 + .config_intr = en8811h_clear_intr, 1062 + .handle_interrupt = en8811h_handle_interrupt, 1063 + .led_hw_is_supported = en8811h_led_hw_is_supported, 1064 + .read_page = air_phy_read_page, 1065 + .write_page = air_phy_write_page, 1066 + .led_blink_set = air_led_blink_set, 1067 + .led_brightness_set = air_led_brightness_set, 1068 + .led_hw_control_set = air_led_hw_control_set, 1069 + .led_hw_control_get = air_led_hw_control_get, 1070 + } }; 1071 + 1072 + module_phy_driver(en8811h_driver); 1073 + 1074 + static struct mdio_device_id __maybe_unused en8811h_tbl[] = { 1075 + { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, 1076 + { } 1077 + }; 1078 + 1079 + MODULE_DEVICE_TABLE(mdio, en8811h_tbl); 1080 + MODULE_FIRMWARE(EN8811H_MD32_DM); 1081 + MODULE_FIRMWARE(EN8811H_MD32_DSP); 1082 + 1083 + MODULE_DESCRIPTION("Airoha EN8811H PHY drivers"); 1084 + MODULE_AUTHOR("Airoha"); 1085 + MODULE_AUTHOR("Eric Woudstra <ericwouds@gmail.com>"); 1086 + MODULE_LICENSE("GPL");