as21xxx.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Aeonsemi AS21XXxX PHY Driver
  4. *
  5. * Author: Christian Marangi <ansuelsmth@gmail.com>
  6. */
  7. #include <linux/bitfield.h>
  8. #include <linux/firmware.h>
  9. #include <linux/module.h>
  10. #include <linux/of.h>
  11. #include <linux/phy.h>
  12. #define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3
  13. #define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4
  14. #define VEND1_GLB_REG_CPU_CTRL 0xe
  15. #define VEND1_GLB_CPU_CTRL_MASK GENMASK(4, 0)
  16. #define VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8)
  17. #define VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \
  18. BIT(_n))
  19. #define VEND1_FW_START_ADDR 0x100
  20. #define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101
  21. #define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102
  22. #define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103
  23. #define VEND1_PTP_CLK 0x142
  24. #define VEND1_PTP_CLK_EN BIT(6)
  25. /* 5 LED at step of 0x20
  26. * FE: Fast-Ethernet (10/100)
  27. * GE: Gigabit-Ethernet (1000)
  28. * NG: New-Generation (2500/5000/10000)
  29. */
  30. #define VEND1_LED_REG(_n) (0x1800 + ((_n) * 0x10))
  31. #define VEND1_LED_REG_A_EVENT GENMASK(15, 11)
  32. #define VEND1_LED_CONF 0x1881
  33. #define VEND1_LED_CONFG_BLINK GENMASK(7, 0)
  34. #define VEND1_SPEED_STATUS 0x4002
  35. #define VEND1_SPEED_MASK GENMASK(7, 0)
  36. #define VEND1_SPEED_10000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3)
  37. #define VEND1_SPEED_5000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5)
  38. #define VEND1_SPEED_2500 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9)
  39. #define VEND1_SPEED_1000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10)
  40. #define VEND1_SPEED_100 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20)
  41. #define VEND1_SPEED_10 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0)
  42. #define VEND1_IPC_CMD 0x5801
  43. #define AEON_IPC_CMD_PARITY BIT(15)
  44. #define AEON_IPC_CMD_SIZE GENMASK(10, 6)
  45. #define AEON_IPC_CMD_OPCODE GENMASK(5, 0)
  46. #define IPC_CMD_NOOP 0x0 /* Do nothing */
  47. #define IPC_CMD_INFO 0x1 /* Get Firmware Version */
  48. #define IPC_CMD_SYS_CPU 0x2 /* SYS_CPU */
  49. #define IPC_CMD_BULK_DATA 0xa /* Pass bulk data in ipc registers. */
  50. #define IPC_CMD_BULK_WRITE 0xc /* Write bulk data to memory */
  51. #define IPC_CMD_CFG_PARAM 0x1a /* Write config parameters to memory */
  52. #define IPC_CMD_NG_TESTMODE 0x1b /* Set NG test mode and tone */
  53. #define IPC_CMD_TEMP_MON 0x15 /* Temperature monitoring function */
  54. #define IPC_CMD_SET_LED 0x23 /* Set led */
  55. #define VEND1_IPC_STS 0x5802
  56. #define AEON_IPC_STS_PARITY BIT(15)
  57. #define AEON_IPC_STS_SIZE GENMASK(14, 10)
  58. #define AEON_IPC_STS_OPCODE GENMASK(9, 4)
  59. #define AEON_IPC_STS_STATUS GENMASK(3, 0)
  60. #define AEON_IPC_STS_STATUS_RCVD FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1)
  61. #define AEON_IPC_STS_STATUS_PROCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2)
  62. #define AEON_IPC_STS_STATUS_SUCCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4)
  63. #define AEON_IPC_STS_STATUS_ERROR FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8)
  64. #define AEON_IPC_STS_STATUS_BUSY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe)
  65. #define AEON_IPC_STS_STATUS_READY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf)
  66. #define VEND1_IPC_DATA0 0x5808
  67. #define VEND1_IPC_DATA1 0x5809
  68. #define VEND1_IPC_DATA2 0x580a
  69. #define VEND1_IPC_DATA3 0x580b
  70. #define VEND1_IPC_DATA4 0x580c
  71. #define VEND1_IPC_DATA5 0x580d
  72. #define VEND1_IPC_DATA6 0x580e
  73. #define VEND1_IPC_DATA7 0x580f
  74. #define VEND1_IPC_DATA(_n) (VEND1_IPC_DATA0 + (_n))
  75. /* Sub command of CMD_INFO */
  76. #define IPC_INFO_VERSION 0x1
  77. /* Sub command of CMD_SYS_CPU */
  78. #define IPC_SYS_CPU_REBOOT 0x3
  79. #define IPC_SYS_CPU_IMAGE_OFST 0x4
  80. #define IPC_SYS_CPU_IMAGE_CHECK 0x5
  81. #define IPC_SYS_CPU_PHY_ENABLE 0x6
  82. /* Sub command of CMD_CFG_PARAM */
  83. #define IPC_CFG_PARAM_DIRECT 0x4
  84. /* CFG DIRECT sub command */
  85. #define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL 0x1
  86. #define IPC_CFG_PARAM_DIRECT_CU_AN 0x2
  87. #define IPC_CFG_PARAM_DIRECT_SDS_PCS 0x3
  88. #define IPC_CFG_PARAM_DIRECT_AUTO_EEE 0x4
  89. #define IPC_CFG_PARAM_DIRECT_SDS_PMA 0x5
  90. #define IPC_CFG_PARAM_DIRECT_DPC_RA 0x6
  91. #define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7
  92. #define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8
  93. #define IPC_CFG_PARAM_DIRECT_WDT 0x9
  94. #define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10
  95. #define IPC_CFG_PARAM_DIRECT_TEMP_MON 0x11
  96. #define IPC_CFG_PARAM_DIRECT_WOL 0x12
  97. /* Sub command of CMD_TEMP_MON */
  98. #define IPC_CMD_TEMP_MON_GET 0x4
  99. #define AS21XXX_MDIO_AN_C22 0xffe0
  100. #define PHY_ID_AS21XXX 0x75009410
  101. /* AS21xxx ID Legend
  102. * AS21x1xxB1
  103. * ^ ^^
  104. * | |J: Supports SyncE/PTP
  105. * | |P: No SyncE/PTP support
  106. * | 1: Supports 2nd Serdes
  107. * | 2: Not 2nd Serdes support
  108. * 0: 10G, 5G, 2.5G
  109. * 5: 5G, 2.5G
  110. * 2: 2.5G
  111. */
  112. #define PHY_ID_AS21011JB1 0x75009402
  113. #define PHY_ID_AS21011PB1 0x75009412
  114. #define PHY_ID_AS21010JB1 0x75009422
  115. #define PHY_ID_AS21010PB1 0x75009432
  116. #define PHY_ID_AS21511JB1 0x75009442
  117. #define PHY_ID_AS21511PB1 0x75009452
  118. #define PHY_ID_AS21510JB1 0x75009462
  119. #define PHY_ID_AS21510PB1 0x75009472
  120. #define PHY_ID_AS21210JB1 0x75009482
  121. #define PHY_ID_AS21210PB1 0x75009492
  122. #define PHY_VENDOR_AEONSEMI 0x75009400
  123. #define AEON_MAX_LEDS 5
  124. #define AEON_IPC_DELAY 10000
  125. #define AEON_IPC_TIMEOUT (AEON_IPC_DELAY * 100)
  126. #define AEON_IPC_DATA_NUM_REGISTERS 8
  127. #define AEON_IPC_DATA_MAX (AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16))
  128. #define AEON_BOOT_ADDR 0x1000
  129. #define AEON_CPU_BOOT_ADDR 0x2000
  130. #define AEON_CPU_CTRL_FW_LOAD (BIT(4) | BIT(2) | BIT(1) | BIT(0))
  131. #define AEON_CPU_CTRL_FW_START BIT(0)
  132. enum as21xxx_led_event {
  133. VEND1_LED_REG_A_EVENT_ON_10 = 0x0,
  134. VEND1_LED_REG_A_EVENT_ON_100,
  135. VEND1_LED_REG_A_EVENT_ON_1000,
  136. VEND1_LED_REG_A_EVENT_ON_2500,
  137. VEND1_LED_REG_A_EVENT_ON_5000,
  138. VEND1_LED_REG_A_EVENT_ON_10000,
  139. VEND1_LED_REG_A_EVENT_ON_FE_GE,
  140. VEND1_LED_REG_A_EVENT_ON_NG,
  141. VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX,
  142. VEND1_LED_REG_A_EVENT_ON_COLLISION,
  143. VEND1_LED_REG_A_EVENT_BLINK_TX,
  144. VEND1_LED_REG_A_EVENT_BLINK_RX,
  145. VEND1_LED_REG_A_EVENT_BLINK_ACT,
  146. VEND1_LED_REG_A_EVENT_ON_LINK,
  147. VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT,
  148. VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX,
  149. VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT,
  150. VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT,
  151. VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE,
  152. VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION,
  153. VEND1_LED_REG_A_EVENT_ON,
  154. VEND1_LED_REG_A_EVENT_OFF,
  155. };
  156. struct as21xxx_led_pattern_info {
  157. unsigned int pattern;
  158. u16 val;
  159. };
  160. struct as21xxx_priv {
  161. bool parity_status;
  162. /* Protect concurrent IPC access */
  163. struct mutex ipc_lock;
  164. };
  165. static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = {
  166. {
  167. .pattern = BIT(TRIGGER_NETDEV_LINK_10),
  168. .val = VEND1_LED_REG_A_EVENT_ON_10
  169. },
  170. {
  171. .pattern = BIT(TRIGGER_NETDEV_LINK_100),
  172. .val = VEND1_LED_REG_A_EVENT_ON_100
  173. },
  174. {
  175. .pattern = BIT(TRIGGER_NETDEV_LINK_1000),
  176. .val = VEND1_LED_REG_A_EVENT_ON_1000
  177. },
  178. {
  179. .pattern = BIT(TRIGGER_NETDEV_LINK_2500),
  180. .val = VEND1_LED_REG_A_EVENT_ON_2500
  181. },
  182. {
  183. .pattern = BIT(TRIGGER_NETDEV_LINK_5000),
  184. .val = VEND1_LED_REG_A_EVENT_ON_5000
  185. },
  186. {
  187. .pattern = BIT(TRIGGER_NETDEV_LINK_10000),
  188. .val = VEND1_LED_REG_A_EVENT_ON_10000
  189. },
  190. {
  191. .pattern = BIT(TRIGGER_NETDEV_LINK),
  192. .val = VEND1_LED_REG_A_EVENT_ON_LINK
  193. },
  194. {
  195. .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
  196. BIT(TRIGGER_NETDEV_LINK_100) |
  197. BIT(TRIGGER_NETDEV_LINK_1000),
  198. .val = VEND1_LED_REG_A_EVENT_ON_FE_GE
  199. },
  200. {
  201. .pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
  202. BIT(TRIGGER_NETDEV_LINK_5000) |
  203. BIT(TRIGGER_NETDEV_LINK_10000),
  204. .val = VEND1_LED_REG_A_EVENT_ON_NG
  205. },
  206. {
  207. .pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
  208. .val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX
  209. },
  210. {
  211. .pattern = BIT(TRIGGER_NETDEV_TX),
  212. .val = VEND1_LED_REG_A_EVENT_BLINK_TX
  213. },
  214. {
  215. .pattern = BIT(TRIGGER_NETDEV_RX),
  216. .val = VEND1_LED_REG_A_EVENT_BLINK_RX
  217. },
  218. {
  219. .pattern = BIT(TRIGGER_NETDEV_TX) |
  220. BIT(TRIGGER_NETDEV_RX),
  221. .val = VEND1_LED_REG_A_EVENT_BLINK_ACT
  222. },
  223. {
  224. .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
  225. BIT(TRIGGER_NETDEV_LINK_100) |
  226. BIT(TRIGGER_NETDEV_LINK_1000) |
  227. BIT(TRIGGER_NETDEV_LINK_2500) |
  228. BIT(TRIGGER_NETDEV_LINK_5000) |
  229. BIT(TRIGGER_NETDEV_LINK_10000),
  230. .val = VEND1_LED_REG_A_EVENT_ON_LINK
  231. },
  232. {
  233. .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
  234. BIT(TRIGGER_NETDEV_LINK_100) |
  235. BIT(TRIGGER_NETDEV_LINK_1000) |
  236. BIT(TRIGGER_NETDEV_LINK_2500) |
  237. BIT(TRIGGER_NETDEV_LINK_5000) |
  238. BIT(TRIGGER_NETDEV_LINK_10000) |
  239. BIT(TRIGGER_NETDEV_TX) |
  240. BIT(TRIGGER_NETDEV_RX),
  241. .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT
  242. },
  243. {
  244. .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
  245. BIT(TRIGGER_NETDEV_LINK_100) |
  246. BIT(TRIGGER_NETDEV_LINK_1000) |
  247. BIT(TRIGGER_NETDEV_LINK_2500) |
  248. BIT(TRIGGER_NETDEV_LINK_5000) |
  249. BIT(TRIGGER_NETDEV_LINK_10000) |
  250. BIT(TRIGGER_NETDEV_RX),
  251. .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX
  252. },
  253. {
  254. .pattern = BIT(TRIGGER_NETDEV_LINK_10) |
  255. BIT(TRIGGER_NETDEV_LINK_100) |
  256. BIT(TRIGGER_NETDEV_LINK_1000) |
  257. BIT(TRIGGER_NETDEV_TX) |
  258. BIT(TRIGGER_NETDEV_RX),
  259. .val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT
  260. },
  261. {
  262. .pattern = BIT(TRIGGER_NETDEV_LINK_2500) |
  263. BIT(TRIGGER_NETDEV_LINK_5000) |
  264. BIT(TRIGGER_NETDEV_LINK_10000) |
  265. BIT(TRIGGER_NETDEV_TX) |
  266. BIT(TRIGGER_NETDEV_RX),
  267. .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT
  268. }
  269. };
  270. static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data,
  271. size_t size)
  272. {
  273. int i, ret;
  274. u16 val;
  275. ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
  276. VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD);
  277. if (ret)
  278. return ret;
  279. ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR,
  280. AEON_BOOT_ADDR);
  281. if (ret)
  282. return ret;
  283. ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1,
  284. VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD,
  285. 0x3ffc, 0xc000);
  286. if (ret)
  287. return ret;
  288. val = phy_read_mmd(phydev, MDIO_MMD_VEND1,
  289. VEND1_GLB_REG_MDIO_INDIRECT_STATUS);
  290. if (val > 1) {
  291. phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val);
  292. return -EINVAL;
  293. }
  294. /* Firmware is always aligned to u16 */
  295. for (i = 0; i < size; i += 2) {
  296. val = data[i + 1] << 8 | data[i];
  297. ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
  298. VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val);
  299. if (ret)
  300. return ret;
  301. }
  302. ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
  303. VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR,
  304. lower_16_bits(AEON_CPU_BOOT_ADDR));
  305. if (ret)
  306. return ret;
  307. ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
  308. VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR,
  309. upper_16_bits(AEON_CPU_BOOT_ADDR));
  310. if (ret)
  311. return ret;
  312. return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL,
  313. VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START);
  314. }
  315. static int aeon_firmware_load(struct phy_device *phydev)
  316. {
  317. struct device *dev = &phydev->mdio.dev;
  318. const struct firmware *fw;
  319. const char *fw_name;
  320. int ret;
  321. ret = of_property_read_string(dev->of_node, "firmware-name",
  322. &fw_name);
  323. if (ret)
  324. return ret;
  325. ret = request_firmware(&fw, fw_name, dev);
  326. if (ret) {
  327. phydev_err(phydev, "failed to find FW file %s (%d)\n",
  328. fw_name, ret);
  329. return ret;
  330. }
  331. ret = aeon_firmware_boot(phydev, fw->data, fw->size);
  332. release_firmware(fw);
  333. return ret;
  334. }
  335. static bool aeon_ipc_ready(u16 val, bool parity_status)
  336. {
  337. u16 status;
  338. if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status)
  339. return false;
  340. status = val & AEON_IPC_STS_STATUS;
  341. return status != AEON_IPC_STS_STATUS_RCVD &&
  342. status != AEON_IPC_STS_STATUS_PROCESS &&
  343. status != AEON_IPC_STS_STATUS_BUSY;
  344. }
  345. static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status)
  346. {
  347. u16 val;
  348. /* Exit condition logic:
  349. * - Wait for parity bit equal
  350. * - Wait for status success, error OR ready
  351. */
  352. return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val,
  353. aeon_ipc_ready(val, parity_status),
  354. AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false);
  355. }
  356. static int aeon_ipc_send_cmd(struct phy_device *phydev,
  357. struct as21xxx_priv *priv,
  358. u16 cmd, u16 *ret_sts)
  359. {
  360. bool curr_parity;
  361. int ret;
  362. /* The IPC sync by using a single parity bit.
  363. * Each CMD have alternately this bit set or clear
  364. * to understand correct flow and packet order.
  365. */
  366. curr_parity = priv->parity_status;
  367. if (priv->parity_status)
  368. cmd |= AEON_IPC_CMD_PARITY;
  369. /* Always update parity for next packet */
  370. priv->parity_status = !priv->parity_status;
  371. ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd);
  372. if (ret)
  373. return ret;
  374. /* Wait for packet to be processed */
  375. usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000);
  376. /* With no ret_sts, ignore waiting for packet completion
  377. * (ipc parity bit sync)
  378. */
  379. if (!ret_sts)
  380. return 0;
  381. ret = aeon_ipc_wait_cmd(phydev, curr_parity);
  382. if (ret)
  383. return ret;
  384. ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS);
  385. if (ret < 0)
  386. return ret;
  387. *ret_sts = ret;
  388. if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS)
  389. return -EINVAL;
  390. return 0;
  391. }
  392. /* If data is NULL, return 0 or negative error.
  393. * If data not NULL, return number of Bytes received from IPC or
  394. * a negative error.
  395. */
  396. static int aeon_ipc_send_msg(struct phy_device *phydev,
  397. u16 opcode, u16 *data, unsigned int data_len,
  398. u16 *ret_data)
  399. {
  400. struct as21xxx_priv *priv = phydev->priv;
  401. unsigned int ret_size;
  402. u16 cmd, ret_sts;
  403. int ret;
  404. int i;
  405. /* IPC have a max of 8 register to transfer data,
  406. * make sure we never exceed this.
  407. */
  408. if (data_len > AEON_IPC_DATA_MAX)
  409. return -EINVAL;
  410. for (i = 0; i < data_len / sizeof(u16); i++)
  411. phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i),
  412. data[i]);
  413. cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) |
  414. FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode);
  415. mutex_lock(&priv->ipc_lock);
  416. ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts);
  417. if (ret) {
  418. phydev_err(phydev, "failed to send ipc msg for %x: %d\n",
  419. opcode, ret);
  420. goto out;
  421. }
  422. if (!data)
  423. goto out;
  424. if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) {
  425. ret = -EINVAL;
  426. goto out;
  427. }
  428. /* Prevent IPC from stack smashing the kernel.
  429. * We can't trust IPC to return a good value and we always
  430. * preallocate space for 16 Bytes.
  431. */
  432. ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts);
  433. if (ret_size > AEON_IPC_DATA_MAX) {
  434. ret = -EINVAL;
  435. goto out;
  436. }
  437. /* Read data from IPC data register for ret_size value from IPC */
  438. for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) {
  439. ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i));
  440. if (ret < 0)
  441. goto out;
  442. ret_data[i] = ret;
  443. }
  444. ret = ret_size;
  445. out:
  446. mutex_unlock(&priv->ipc_lock);
  447. return ret;
  448. }
  449. static int aeon_ipc_noop(struct phy_device *phydev,
  450. struct as21xxx_priv *priv, u16 *ret_sts)
  451. {
  452. u16 cmd;
  453. cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) |
  454. FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP);
  455. return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts);
  456. }
  457. /* Logic to sync parity bit with IPC.
  458. * We send 2 NOP cmd with same partity and we wait for IPC
  459. * to handle the packet only for the second one. This way
  460. * we make sure we are sync for every next cmd.
  461. */
  462. static int aeon_ipc_sync_parity(struct phy_device *phydev,
  463. struct as21xxx_priv *priv)
  464. {
  465. u16 ret_sts;
  466. int ret;
  467. mutex_lock(&priv->ipc_lock);
  468. /* Send NOP with no parity */
  469. aeon_ipc_noop(phydev, priv, NULL);
  470. /* Reset packet parity */
  471. priv->parity_status = false;
  472. /* Send second NOP with no parity */
  473. ret = aeon_ipc_noop(phydev, priv, &ret_sts);
  474. mutex_unlock(&priv->ipc_lock);
  475. /* We expect to return -EINVAL */
  476. if (ret != -EINVAL)
  477. return ret;
  478. if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) {
  479. phydev_err(phydev, "Invalid IPC status on sync parity: %x\n",
  480. ret_sts);
  481. return -EINVAL;
  482. }
  483. return 0;
  484. }
  485. static int aeon_ipc_get_fw_version(struct phy_device *phydev)
  486. {
  487. u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1];
  488. char fw_version[AEON_IPC_DATA_MAX + 1];
  489. int ret;
  490. data[0] = IPC_INFO_VERSION;
  491. ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data,
  492. sizeof(data), ret_data);
  493. if (ret < 0)
  494. return ret;
  495. /* Make sure FW version is NULL terminated */
  496. memcpy(fw_version, ret_data, ret);
  497. fw_version[ret] = '\0';
  498. phydev_info(phydev, "Firmware Version: %s\n", fw_version);
  499. return 0;
  500. }
  501. static int aeon_dpc_ra_enable(struct phy_device *phydev)
  502. {
  503. u16 data[2];
  504. data[0] = IPC_CFG_PARAM_DIRECT;
  505. data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA;
  506. return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data,
  507. sizeof(data), NULL);
  508. }
  509. static int as21xxx_probe(struct phy_device *phydev)
  510. {
  511. struct as21xxx_priv *priv;
  512. int ret;
  513. priv = devm_kzalloc(&phydev->mdio.dev,
  514. sizeof(*priv), GFP_KERNEL);
  515. if (!priv)
  516. return -ENOMEM;
  517. phydev->priv = priv;
  518. ret = devm_mutex_init(&phydev->mdio.dev,
  519. &priv->ipc_lock);
  520. if (ret)
  521. return ret;
  522. ret = aeon_ipc_sync_parity(phydev, priv);
  523. if (ret)
  524. return ret;
  525. ret = aeon_ipc_get_fw_version(phydev);
  526. if (ret)
  527. return ret;
  528. /* Enable PTP clk if not already Enabled */
  529. ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK,
  530. VEND1_PTP_CLK_EN);
  531. if (ret)
  532. return ret;
  533. return aeon_dpc_ra_enable(phydev);
  534. }
  535. static int as21xxx_read_link(struct phy_device *phydev, int *bmcr)
  536. {
  537. int status;
  538. /* Normal C22 BMCR report inconsistent data, use
  539. * the mapped C22 in C45 to have more consistent link info.
  540. */
  541. *bmcr = phy_read_mmd(phydev, MDIO_MMD_AN,
  542. AS21XXX_MDIO_AN_C22 + MII_BMCR);
  543. if (*bmcr < 0)
  544. return *bmcr;
  545. /* Autoneg is being started, therefore disregard current
  546. * link status and report link as down.
  547. */
  548. if (*bmcr & BMCR_ANRESTART) {
  549. phydev->link = 0;
  550. return 0;
  551. }
  552. status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
  553. if (status < 0)
  554. return status;
  555. phydev->link = !!(status & MDIO_STAT1_LSTATUS);
  556. return 0;
  557. }
  558. static int as21xxx_read_c22_lpa(struct phy_device *phydev)
  559. {
  560. int lpagb;
  561. /* MII_STAT1000 are only filled in the mapped C22
  562. * in C45, use that to fill lpagb values and check.
  563. */
  564. lpagb = phy_read_mmd(phydev, MDIO_MMD_AN,
  565. AS21XXX_MDIO_AN_C22 + MII_STAT1000);
  566. if (lpagb < 0)
  567. return lpagb;
  568. if (lpagb & LPA_1000MSFAIL) {
  569. int adv = phy_read_mmd(phydev, MDIO_MMD_AN,
  570. AS21XXX_MDIO_AN_C22 + MII_CTRL1000);
  571. if (adv < 0)
  572. return adv;
  573. if (adv & CTL1000_ENABLE_MASTER)
  574. phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
  575. else
  576. phydev_err(phydev, "Master/Slave resolution failed\n");
  577. return -ENOLINK;
  578. }
  579. mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
  580. lpagb);
  581. return 0;
  582. }
  583. static int as21xxx_read_status(struct phy_device *phydev)
  584. {
  585. int bmcr, old_link = phydev->link;
  586. int ret;
  587. ret = as21xxx_read_link(phydev, &bmcr);
  588. if (ret)
  589. return ret;
  590. /* why bother the PHY if nothing can have changed */
  591. if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
  592. return 0;
  593. phydev->speed = SPEED_UNKNOWN;
  594. phydev->duplex = DUPLEX_UNKNOWN;
  595. phydev->pause = 0;
  596. phydev->asym_pause = 0;
  597. if (phydev->autoneg == AUTONEG_ENABLE) {
  598. ret = genphy_c45_read_lpa(phydev);
  599. if (ret)
  600. return ret;
  601. ret = as21xxx_read_c22_lpa(phydev);
  602. if (ret)
  603. return ret;
  604. phy_resolve_aneg_linkmode(phydev);
  605. } else {
  606. int speed;
  607. linkmode_zero(phydev->lp_advertising);
  608. speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
  609. VEND1_SPEED_STATUS);
  610. if (speed < 0)
  611. return speed;
  612. switch (speed & VEND1_SPEED_STATUS) {
  613. case VEND1_SPEED_10000:
  614. phydev->speed = SPEED_10000;
  615. phydev->duplex = DUPLEX_FULL;
  616. break;
  617. case VEND1_SPEED_5000:
  618. phydev->speed = SPEED_5000;
  619. phydev->duplex = DUPLEX_FULL;
  620. break;
  621. case VEND1_SPEED_2500:
  622. phydev->speed = SPEED_2500;
  623. phydev->duplex = DUPLEX_FULL;
  624. break;
  625. case VEND1_SPEED_1000:
  626. phydev->speed = SPEED_1000;
  627. if (bmcr & BMCR_FULLDPLX)
  628. phydev->duplex = DUPLEX_FULL;
  629. else
  630. phydev->duplex = DUPLEX_HALF;
  631. break;
  632. case VEND1_SPEED_100:
  633. phydev->speed = SPEED_100;
  634. phydev->duplex = DUPLEX_FULL;
  635. break;
  636. case VEND1_SPEED_10:
  637. phydev->speed = SPEED_10;
  638. phydev->duplex = DUPLEX_FULL;
  639. break;
  640. default:
  641. return -EINVAL;
  642. }
  643. }
  644. return 0;
  645. }
  646. static int as21xxx_led_brightness_set(struct phy_device *phydev,
  647. u8 index, enum led_brightness value)
  648. {
  649. u16 val = VEND1_LED_REG_A_EVENT_OFF;
  650. if (index > AEON_MAX_LEDS)
  651. return -EINVAL;
  652. if (value)
  653. val = VEND1_LED_REG_A_EVENT_ON;
  654. return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
  655. VEND1_LED_REG(index),
  656. VEND1_LED_REG_A_EVENT,
  657. FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
  658. }
  659. static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index,
  660. unsigned long rules)
  661. {
  662. int i;
  663. if (index > AEON_MAX_LEDS)
  664. return -EINVAL;
  665. for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
  666. if (rules == as21xxx_led_supported_pattern[i].pattern)
  667. return 0;
  668. return -EOPNOTSUPP;
  669. }
  670. static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index,
  671. unsigned long *rules)
  672. {
  673. int i, val;
  674. if (index > AEON_MAX_LEDS)
  675. return -EINVAL;
  676. val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index));
  677. if (val < 0)
  678. return val;
  679. val = FIELD_GET(VEND1_LED_REG_A_EVENT, val);
  680. for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
  681. if (val == as21xxx_led_supported_pattern[i].val) {
  682. *rules = as21xxx_led_supported_pattern[i].pattern;
  683. return 0;
  684. }
  685. /* Should be impossible */
  686. return -EINVAL;
  687. }
  688. static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index,
  689. unsigned long rules)
  690. {
  691. u16 val = 0;
  692. int i;
  693. if (index > AEON_MAX_LEDS)
  694. return -EINVAL;
  695. for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++)
  696. if (rules == as21xxx_led_supported_pattern[i].pattern) {
  697. val = as21xxx_led_supported_pattern[i].val;
  698. break;
  699. }
  700. return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
  701. VEND1_LED_REG(index),
  702. VEND1_LED_REG_A_EVENT,
  703. FIELD_PREP(VEND1_LED_REG_A_EVENT, val));
  704. }
  705. static int as21xxx_led_polarity_set(struct phy_device *phydev, int index,
  706. unsigned long modes)
  707. {
  708. bool led_active_low = false;
  709. u16 mask, val = 0;
  710. u32 mode;
  711. if (index > AEON_MAX_LEDS)
  712. return -EINVAL;
  713. for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
  714. switch (mode) {
  715. case PHY_LED_ACTIVE_LOW:
  716. led_active_low = true;
  717. break;
  718. case PHY_LED_ACTIVE_HIGH: /* default mode */
  719. led_active_low = false;
  720. break;
  721. default:
  722. return -EINVAL;
  723. }
  724. }
  725. mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
  726. if (led_active_low)
  727. val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index);
  728. return phy_modify_mmd(phydev, MDIO_MMD_VEND1,
  729. VEND1_GLB_REG_CPU_CTRL,
  730. mask, val);
  731. }
  732. static int as21xxx_match_phy_device(struct phy_device *phydev,
  733. const struct phy_driver *phydrv)
  734. {
  735. struct as21xxx_priv *priv;
  736. u16 ret_sts;
  737. u32 phy_id;
  738. int ret;
  739. /* Skip PHY that are not AS21xxx */
  740. if (!phy_id_compare_vendor(phydev->c45_ids.device_ids[MDIO_MMD_PCS],
  741. PHY_VENDOR_AEONSEMI))
  742. return genphy_match_phy_device(phydev, phydrv);
  743. /* Read PHY ID to handle firmware loaded or HW reset */
  744. ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1);
  745. if (ret < 0)
  746. return ret;
  747. phy_id = ret << 16;
  748. ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2);
  749. if (ret < 0)
  750. return ret;
  751. phy_id |= ret;
  752. /* With PHY ID not the generic AS21xxx one assume
  753. * the firmware just loaded
  754. */
  755. if (phy_id != PHY_ID_AS21XXX)
  756. return phy_id == phydrv->phy_id;
  757. /* Allocate temp priv and load the firmware */
  758. priv = kzalloc_obj(*priv);
  759. if (!priv)
  760. return -ENOMEM;
  761. mutex_init(&priv->ipc_lock);
  762. ret = aeon_firmware_load(phydev);
  763. if (ret)
  764. goto out;
  765. /* Sync parity... */
  766. ret = aeon_ipc_sync_parity(phydev, priv);
  767. if (ret)
  768. goto out;
  769. /* ...and send a third NOOP cmd to wait for firmware finish loading */
  770. ret = aeon_ipc_noop(phydev, priv, &ret_sts);
  771. if (ret)
  772. goto out;
  773. out:
  774. mutex_destroy(&priv->ipc_lock);
  775. kfree(priv);
  776. /* Return can either be 0 or a negative error code.
  777. * Returning 0 here means THIS is NOT a suitable PHY.
  778. *
  779. * For the specific case of the generic Aeonsemi PHY ID that
  780. * needs the firmware the be loaded first to have a correct PHY ID,
  781. * this is OK as a matching PHY ID will be found right after.
  782. * This relies on the driver probe order where the first PHY driver
  783. * probed is the generic one.
  784. */
  785. return ret;
  786. }
  787. static struct phy_driver as21xxx_drivers[] = {
  788. {
  789. /* PHY expose in C45 as 0x7500 0x9410
  790. * before firmware is loaded.
  791. * This driver entry must be attempted first to load
  792. * the firmware and thus update the ID registers.
  793. */
  794. PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX),
  795. .name = "Aeonsemi AS21xxx",
  796. .match_phy_device = as21xxx_match_phy_device,
  797. },
  798. {
  799. PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1),
  800. .name = "Aeonsemi AS21011JB1",
  801. .probe = as21xxx_probe,
  802. .match_phy_device = as21xxx_match_phy_device,
  803. .read_status = as21xxx_read_status,
  804. .led_brightness_set = as21xxx_led_brightness_set,
  805. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  806. .led_hw_control_set = as21xxx_led_hw_control_set,
  807. .led_hw_control_get = as21xxx_led_hw_control_get,
  808. .led_polarity_set = as21xxx_led_polarity_set,
  809. },
  810. {
  811. PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
  812. .name = "Aeonsemi AS21011PB1",
  813. .probe = as21xxx_probe,
  814. .match_phy_device = as21xxx_match_phy_device,
  815. .read_status = as21xxx_read_status,
  816. .led_brightness_set = as21xxx_led_brightness_set,
  817. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  818. .led_hw_control_set = as21xxx_led_hw_control_set,
  819. .led_hw_control_get = as21xxx_led_hw_control_get,
  820. .led_polarity_set = as21xxx_led_polarity_set,
  821. },
  822. {
  823. PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
  824. .name = "Aeonsemi AS21010PB1",
  825. .probe = as21xxx_probe,
  826. .match_phy_device = as21xxx_match_phy_device,
  827. .read_status = as21xxx_read_status,
  828. .led_brightness_set = as21xxx_led_brightness_set,
  829. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  830. .led_hw_control_set = as21xxx_led_hw_control_set,
  831. .led_hw_control_get = as21xxx_led_hw_control_get,
  832. .led_polarity_set = as21xxx_led_polarity_set,
  833. },
  834. {
  835. PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
  836. .name = "Aeonsemi AS21010JB1",
  837. .probe = as21xxx_probe,
  838. .match_phy_device = as21xxx_match_phy_device,
  839. .read_status = as21xxx_read_status,
  840. .led_brightness_set = as21xxx_led_brightness_set,
  841. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  842. .led_hw_control_set = as21xxx_led_hw_control_set,
  843. .led_hw_control_get = as21xxx_led_hw_control_get,
  844. .led_polarity_set = as21xxx_led_polarity_set,
  845. },
  846. {
  847. PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
  848. .name = "Aeonsemi AS21210PB1",
  849. .probe = as21xxx_probe,
  850. .match_phy_device = as21xxx_match_phy_device,
  851. .read_status = as21xxx_read_status,
  852. .led_brightness_set = as21xxx_led_brightness_set,
  853. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  854. .led_hw_control_set = as21xxx_led_hw_control_set,
  855. .led_hw_control_get = as21xxx_led_hw_control_get,
  856. .led_polarity_set = as21xxx_led_polarity_set,
  857. },
  858. {
  859. PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
  860. .name = "Aeonsemi AS21510JB1",
  861. .probe = as21xxx_probe,
  862. .match_phy_device = as21xxx_match_phy_device,
  863. .read_status = as21xxx_read_status,
  864. .led_brightness_set = as21xxx_led_brightness_set,
  865. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  866. .led_hw_control_set = as21xxx_led_hw_control_set,
  867. .led_hw_control_get = as21xxx_led_hw_control_get,
  868. .led_polarity_set = as21xxx_led_polarity_set,
  869. },
  870. {
  871. PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
  872. .name = "Aeonsemi AS21510PB1",
  873. .probe = as21xxx_probe,
  874. .match_phy_device = as21xxx_match_phy_device,
  875. .read_status = as21xxx_read_status,
  876. .led_brightness_set = as21xxx_led_brightness_set,
  877. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  878. .led_hw_control_set = as21xxx_led_hw_control_set,
  879. .led_hw_control_get = as21xxx_led_hw_control_get,
  880. .led_polarity_set = as21xxx_led_polarity_set,
  881. },
  882. {
  883. PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
  884. .name = "Aeonsemi AS21511JB1",
  885. .probe = as21xxx_probe,
  886. .match_phy_device = as21xxx_match_phy_device,
  887. .read_status = as21xxx_read_status,
  888. .led_brightness_set = as21xxx_led_brightness_set,
  889. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  890. .led_hw_control_set = as21xxx_led_hw_control_set,
  891. .led_hw_control_get = as21xxx_led_hw_control_get,
  892. .led_polarity_set = as21xxx_led_polarity_set,
  893. },
  894. {
  895. PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
  896. .name = "Aeonsemi AS21210JB1",
  897. .probe = as21xxx_probe,
  898. .match_phy_device = as21xxx_match_phy_device,
  899. .read_status = as21xxx_read_status,
  900. .led_brightness_set = as21xxx_led_brightness_set,
  901. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  902. .led_hw_control_set = as21xxx_led_hw_control_set,
  903. .led_hw_control_get = as21xxx_led_hw_control_get,
  904. .led_polarity_set = as21xxx_led_polarity_set,
  905. },
  906. {
  907. PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
  908. .name = "Aeonsemi AS21511PB1",
  909. .probe = as21xxx_probe,
  910. .match_phy_device = as21xxx_match_phy_device,
  911. .read_status = as21xxx_read_status,
  912. .led_brightness_set = as21xxx_led_brightness_set,
  913. .led_hw_is_supported = as21xxx_led_hw_is_supported,
  914. .led_hw_control_set = as21xxx_led_hw_control_set,
  915. .led_hw_control_get = as21xxx_led_hw_control_get,
  916. .led_polarity_set = as21xxx_led_polarity_set,
  917. },
  918. };
  919. module_phy_driver(as21xxx_drivers);
  920. static struct mdio_device_id __maybe_unused as21xxx_tbl[] = {
  921. { PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) },
  922. { }
  923. };
  924. MODULE_DEVICE_TABLE(mdio, as21xxx_tbl);
  925. MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver");
  926. MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
  927. MODULE_LICENSE("GPL");