icplus.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Driver for ICPlus PHYs
  4. *
  5. * Copyright (c) 2007 Freescale Semiconductor, Inc.
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/string.h>
  9. #include <linux/errno.h>
  10. #include <linux/unistd.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/init.h>
  13. #include <linux/delay.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/etherdevice.h>
  16. #include <linux/skbuff.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/mm.h>
  19. #include <linux/module.h>
  20. #include <linux/mii.h>
  21. #include <linux/ethtool.h>
  22. #include <linux/phy.h>
  23. #include <linux/property.h>
  24. #include <asm/io.h>
  25. #include <asm/irq.h>
  26. #include <linux/uaccess.h>
  27. MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers");
  28. MODULE_AUTHOR("Michael Barkowski");
  29. MODULE_LICENSE("GPL");
  30. /* IP101A/G - IP1001 */
  31. #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */
  32. #define IP1001_RXPHASE_SEL BIT(0) /* Add delay on RX_CLK */
  33. #define IP1001_TXPHASE_SEL BIT(1) /* Add delay on TX_CLK */
  34. #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */
  35. #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */
  36. #define IP101A_G_APS_ON BIT(1) /* IP101A/G APS Mode bit */
  37. #define IP101A_G_AUTO_MDIX_DIS BIT(11)
  38. #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */
  39. #define IP101A_G_IRQ_PIN_USED BIT(15) /* INTR pin used */
  40. #define IP101A_G_IRQ_ALL_MASK BIT(11) /* IRQ's inactive */
  41. #define IP101A_G_IRQ_SPEED_CHANGE BIT(2)
  42. #define IP101A_G_IRQ_DUPLEX_CHANGE BIT(1)
  43. #define IP101A_G_IRQ_LINK_CHANGE BIT(0)
  44. #define IP101A_G_PHY_STATUS 18
  45. #define IP101A_G_MDIX BIT(9)
  46. #define IP101A_G_PHY_SPEC_CTRL 30
  47. #define IP101A_G_FORCE_MDIX BIT(3)
  48. #define IP101G_PAGE_CONTROL 0x14
  49. #define IP101G_PAGE_CONTROL_MASK GENMASK(4, 0)
  50. #define IP101G_DIGITAL_IO_SPEC_CTRL 0x1d
  51. #define IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32 BIT(2)
  52. #define IP101G_DEFAULT_PAGE 16
  53. #define IP101G_P1_CNT_CTRL 17
  54. #define CNT_CTRL_RX_EN BIT(13)
  55. #define IP101G_P8_CNT_CTRL 17
  56. #define CNT_CTRL_RDCLR_EN BIT(15)
  57. #define IP101G_CNT_REG 18
  58. #define IP175C_PHY_ID 0x02430d80
  59. #define IP1001_PHY_ID 0x02430d90
  60. #define IP101A_PHY_ID 0x02430c54
  61. /* The 32-pin IP101GR package can re-configure the mode of the RXER/INTR_32 pin
  62. * (pin number 21). The hardware default is RXER (receive error) mode. But it
  63. * can be configured to interrupt mode manually.
  64. */
  65. enum ip101gr_sel_intr32 {
  66. IP101GR_SEL_INTR32_KEEP,
  67. IP101GR_SEL_INTR32_INTR,
  68. IP101GR_SEL_INTR32_RXER,
  69. };
  70. struct ip101g_hw_stat {
  71. const char *name;
  72. int page;
  73. };
  74. static struct ip101g_hw_stat ip101g_hw_stats[] = {
  75. { "phy_crc_errors", 1 },
  76. { "phy_symbol_errors", 11, },
  77. };
  78. struct ip101a_g_phy_priv {
  79. enum ip101gr_sel_intr32 sel_intr32;
  80. u64 stats[ARRAY_SIZE(ip101g_hw_stats)];
  81. };
  82. static int ip175c_config_init(struct phy_device *phydev)
  83. {
  84. int err, i;
  85. static int full_reset_performed;
  86. if (full_reset_performed == 0) {
  87. /* master reset */
  88. err = mdiobus_write(phydev->mdio.bus, 30, 0, 0x175c);
  89. if (err < 0)
  90. return err;
  91. /* ensure no bus delays overlap reset period */
  92. err = mdiobus_read(phydev->mdio.bus, 30, 0);
  93. /* data sheet specifies reset period is 2 msec */
  94. mdelay(2);
  95. /* enable IP175C mode */
  96. err = mdiobus_write(phydev->mdio.bus, 29, 31, 0x175c);
  97. if (err < 0)
  98. return err;
  99. /* Set MII0 speed and duplex (in PHY mode) */
  100. err = mdiobus_write(phydev->mdio.bus, 29, 22, 0x420);
  101. if (err < 0)
  102. return err;
  103. /* reset switch ports */
  104. for (i = 0; i < 5; i++) {
  105. err = mdiobus_write(phydev->mdio.bus, i,
  106. MII_BMCR, BMCR_RESET);
  107. if (err < 0)
  108. return err;
  109. }
  110. for (i = 0; i < 5; i++)
  111. err = mdiobus_read(phydev->mdio.bus, i, MII_BMCR);
  112. mdelay(2);
  113. full_reset_performed = 1;
  114. }
  115. if (phydev->mdio.addr != 4) {
  116. phydev->state = PHY_RUNNING;
  117. phydev->speed = SPEED_100;
  118. phydev->duplex = DUPLEX_FULL;
  119. phydev->link = 1;
  120. netif_carrier_on(phydev->attached_dev);
  121. }
  122. return 0;
  123. }
  124. static int ip1001_config_init(struct phy_device *phydev)
  125. {
  126. int c;
  127. /* Enable Auto Power Saving mode */
  128. c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2);
  129. if (c < 0)
  130. return c;
  131. c |= IP1001_APS_ON;
  132. c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c);
  133. if (c < 0)
  134. return c;
  135. if (phy_interface_is_rgmii(phydev)) {
  136. c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
  137. if (c < 0)
  138. return c;
  139. c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
  140. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
  141. c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
  142. else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
  143. c |= IP1001_RXPHASE_SEL;
  144. else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
  145. c |= IP1001_TXPHASE_SEL;
  146. c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
  147. if (c < 0)
  148. return c;
  149. }
  150. return 0;
  151. }
  152. static int ip175c_read_status(struct phy_device *phydev)
  153. {
  154. if (phydev->mdio.addr == 4) /* WAN port */
  155. genphy_read_status(phydev);
  156. else
  157. /* Don't need to read status for switch ports */
  158. phydev->irq = PHY_MAC_INTERRUPT;
  159. return 0;
  160. }
  161. static int ip175c_config_aneg(struct phy_device *phydev)
  162. {
  163. if (phydev->mdio.addr == 4) /* WAN port */
  164. genphy_config_aneg(phydev);
  165. return 0;
  166. }
  167. static int ip101a_g_probe(struct phy_device *phydev)
  168. {
  169. struct device *dev = &phydev->mdio.dev;
  170. struct ip101a_g_phy_priv *priv;
  171. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  172. if (!priv)
  173. return -ENOMEM;
  174. /* Both functions (RX error and interrupt status) are sharing the same
  175. * pin on the 32-pin IP101GR, so this is an exclusive choice.
  176. */
  177. if (device_property_read_bool(dev, "icplus,select-rx-error") &&
  178. device_property_read_bool(dev, "icplus,select-interrupt")) {
  179. dev_err(dev,
  180. "RXER and INTR mode cannot be selected together\n");
  181. return -EINVAL;
  182. }
  183. if (device_property_read_bool(dev, "icplus,select-rx-error"))
  184. priv->sel_intr32 = IP101GR_SEL_INTR32_RXER;
  185. else if (device_property_read_bool(dev, "icplus,select-interrupt"))
  186. priv->sel_intr32 = IP101GR_SEL_INTR32_INTR;
  187. else
  188. priv->sel_intr32 = IP101GR_SEL_INTR32_KEEP;
  189. phydev->priv = priv;
  190. return 0;
  191. }
  192. static int ip101a_g_config_intr_pin(struct phy_device *phydev)
  193. {
  194. struct ip101a_g_phy_priv *priv = phydev->priv;
  195. int oldpage, err = 0;
  196. oldpage = phy_select_page(phydev, IP101G_DEFAULT_PAGE);
  197. if (oldpage < 0)
  198. goto out;
  199. /* configure the RXER/INTR_32 pin of the 32-pin IP101GR if needed: */
  200. switch (priv->sel_intr32) {
  201. case IP101GR_SEL_INTR32_RXER:
  202. err = __phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
  203. IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32, 0);
  204. if (err < 0)
  205. goto out;
  206. break;
  207. case IP101GR_SEL_INTR32_INTR:
  208. err = __phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL,
  209. IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32,
  210. IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32);
  211. if (err < 0)
  212. goto out;
  213. break;
  214. default:
  215. /* Don't touch IP101G_DIGITAL_IO_SPEC_CTRL because it's not
  216. * documented on IP101A and it's not clear whether this would
  217. * cause problems.
  218. * For the 32-pin IP101GR we simply keep the SEL_INTR32
  219. * configuration as set by the bootloader when not configured
  220. * to one of the special functions.
  221. */
  222. break;
  223. }
  224. out:
  225. return phy_restore_page(phydev, oldpage, err);
  226. }
  227. static int ip101a_config_init(struct phy_device *phydev)
  228. {
  229. int ret;
  230. /* Enable Auto Power Saving mode */
  231. ret = phy_set_bits(phydev, IP10XX_SPEC_CTRL_STATUS, IP101A_G_APS_ON);
  232. if (ret)
  233. return ret;
  234. return ip101a_g_config_intr_pin(phydev);
  235. }
  236. static int ip101g_config_init(struct phy_device *phydev)
  237. {
  238. int ret;
  239. /* Enable the PHY counters */
  240. ret = phy_modify_paged(phydev, 1, IP101G_P1_CNT_CTRL,
  241. CNT_CTRL_RX_EN, CNT_CTRL_RX_EN);
  242. if (ret)
  243. return ret;
  244. /* Clear error counters on read */
  245. ret = phy_modify_paged(phydev, 8, IP101G_P8_CNT_CTRL,
  246. CNT_CTRL_RDCLR_EN, CNT_CTRL_RDCLR_EN);
  247. if (ret)
  248. return ret;
  249. return ip101a_g_config_intr_pin(phydev);
  250. }
  251. static int ip101a_g_read_status(struct phy_device *phydev)
  252. {
  253. int oldpage, ret, stat1, stat2;
  254. ret = genphy_read_status(phydev);
  255. if (ret)
  256. return ret;
  257. oldpage = phy_select_page(phydev, IP101G_DEFAULT_PAGE);
  258. if (oldpage < 0)
  259. goto out;
  260. ret = __phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
  261. if (ret < 0)
  262. goto out;
  263. stat1 = ret;
  264. ret = __phy_read(phydev, IP101A_G_PHY_SPEC_CTRL);
  265. if (ret < 0)
  266. goto out;
  267. stat2 = ret;
  268. if (stat1 & IP101A_G_AUTO_MDIX_DIS) {
  269. if (stat2 & IP101A_G_FORCE_MDIX)
  270. phydev->mdix_ctrl = ETH_TP_MDI_X;
  271. else
  272. phydev->mdix_ctrl = ETH_TP_MDI;
  273. } else {
  274. phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
  275. }
  276. if (stat2 & IP101A_G_MDIX)
  277. phydev->mdix = ETH_TP_MDI_X;
  278. else
  279. phydev->mdix = ETH_TP_MDI;
  280. ret = 0;
  281. out:
  282. return phy_restore_page(phydev, oldpage, ret);
  283. }
  284. static int ip101a_g_config_mdix(struct phy_device *phydev)
  285. {
  286. u16 ctrl = 0, ctrl2 = 0;
  287. int oldpage;
  288. int ret = 0;
  289. switch (phydev->mdix_ctrl) {
  290. case ETH_TP_MDI:
  291. ctrl = IP101A_G_AUTO_MDIX_DIS;
  292. break;
  293. case ETH_TP_MDI_X:
  294. ctrl = IP101A_G_AUTO_MDIX_DIS;
  295. ctrl2 = IP101A_G_FORCE_MDIX;
  296. break;
  297. case ETH_TP_MDI_AUTO:
  298. break;
  299. default:
  300. return 0;
  301. }
  302. oldpage = phy_select_page(phydev, IP101G_DEFAULT_PAGE);
  303. if (oldpage < 0)
  304. goto out;
  305. ret = __phy_modify(phydev, IP10XX_SPEC_CTRL_STATUS,
  306. IP101A_G_AUTO_MDIX_DIS, ctrl);
  307. if (ret)
  308. goto out;
  309. ret = __phy_modify(phydev, IP101A_G_PHY_SPEC_CTRL,
  310. IP101A_G_FORCE_MDIX, ctrl2);
  311. out:
  312. return phy_restore_page(phydev, oldpage, ret);
  313. }
  314. static int ip101a_g_config_aneg(struct phy_device *phydev)
  315. {
  316. int ret;
  317. ret = ip101a_g_config_mdix(phydev);
  318. if (ret)
  319. return ret;
  320. return genphy_config_aneg(phydev);
  321. }
  322. static int ip101a_g_ack_interrupt(struct phy_device *phydev)
  323. {
  324. int err;
  325. err = phy_read_paged(phydev, IP101G_DEFAULT_PAGE,
  326. IP101A_G_IRQ_CONF_STATUS);
  327. if (err < 0)
  328. return err;
  329. return 0;
  330. }
  331. static int ip101a_g_config_intr(struct phy_device *phydev)
  332. {
  333. u16 val;
  334. int err;
  335. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  336. err = ip101a_g_ack_interrupt(phydev);
  337. if (err)
  338. return err;
  339. /* INTR pin used: Speed/link/duplex will cause an interrupt */
  340. val = IP101A_G_IRQ_PIN_USED;
  341. err = phy_write_paged(phydev, IP101G_DEFAULT_PAGE,
  342. IP101A_G_IRQ_CONF_STATUS, val);
  343. } else {
  344. val = IP101A_G_IRQ_ALL_MASK;
  345. err = phy_write_paged(phydev, IP101G_DEFAULT_PAGE,
  346. IP101A_G_IRQ_CONF_STATUS, val);
  347. if (err)
  348. return err;
  349. err = ip101a_g_ack_interrupt(phydev);
  350. }
  351. return err;
  352. }
  353. static irqreturn_t ip101a_g_handle_interrupt(struct phy_device *phydev)
  354. {
  355. int irq_status;
  356. irq_status = phy_read_paged(phydev, IP101G_DEFAULT_PAGE,
  357. IP101A_G_IRQ_CONF_STATUS);
  358. if (irq_status < 0) {
  359. phy_error(phydev);
  360. return IRQ_NONE;
  361. }
  362. if (!(irq_status & (IP101A_G_IRQ_SPEED_CHANGE |
  363. IP101A_G_IRQ_DUPLEX_CHANGE |
  364. IP101A_G_IRQ_LINK_CHANGE)))
  365. return IRQ_NONE;
  366. phy_trigger_machine(phydev);
  367. return IRQ_HANDLED;
  368. }
  369. /* The IP101A doesn't really have a page register. We just pretend to have one
  370. * so we can use the paged versions of the callbacks of the IP101G.
  371. */
  372. static int ip101a_read_page(struct phy_device *phydev)
  373. {
  374. return IP101G_DEFAULT_PAGE;
  375. }
  376. static int ip101a_write_page(struct phy_device *phydev, int page)
  377. {
  378. WARN_ONCE(page != IP101G_DEFAULT_PAGE, "wrong page selected\n");
  379. return 0;
  380. }
  381. static int ip101g_read_page(struct phy_device *phydev)
  382. {
  383. return __phy_read(phydev, IP101G_PAGE_CONTROL);
  384. }
  385. static int ip101g_write_page(struct phy_device *phydev, int page)
  386. {
  387. return __phy_write(phydev, IP101G_PAGE_CONTROL, page);
  388. }
  389. static int ip101a_g_has_page_register(struct phy_device *phydev)
  390. {
  391. int oldval, val, ret;
  392. oldval = phy_read(phydev, IP101G_PAGE_CONTROL);
  393. if (oldval < 0)
  394. return oldval;
  395. ret = phy_write(phydev, IP101G_PAGE_CONTROL, 0xffff);
  396. if (ret)
  397. return ret;
  398. val = phy_read(phydev, IP101G_PAGE_CONTROL);
  399. if (val < 0)
  400. return val;
  401. ret = phy_write(phydev, IP101G_PAGE_CONTROL, oldval);
  402. if (ret)
  403. return ret;
  404. return val == IP101G_PAGE_CONTROL_MASK;
  405. }
  406. static int ip101a_g_match_phy_device(struct phy_device *phydev, bool ip101a)
  407. {
  408. int ret;
  409. if (phydev->phy_id != IP101A_PHY_ID)
  410. return 0;
  411. /* The IP101A and the IP101G share the same PHY identifier.The IP101G
  412. * seems to be a successor of the IP101A and implements more functions.
  413. * Amongst other things there is a page select register, which is not
  414. * available on the IP101A. Use this to distinguish these two.
  415. */
  416. ret = ip101a_g_has_page_register(phydev);
  417. if (ret < 0)
  418. return ret;
  419. return ip101a == !ret;
  420. }
  421. static int ip101a_match_phy_device(struct phy_device *phydev)
  422. {
  423. return ip101a_g_match_phy_device(phydev, true);
  424. }
  425. static int ip101g_match_phy_device(struct phy_device *phydev)
  426. {
  427. return ip101a_g_match_phy_device(phydev, false);
  428. }
  429. static int ip101g_get_sset_count(struct phy_device *phydev)
  430. {
  431. return ARRAY_SIZE(ip101g_hw_stats);
  432. }
  433. static void ip101g_get_strings(struct phy_device *phydev, u8 *data)
  434. {
  435. int i;
  436. for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++)
  437. strscpy(data + i * ETH_GSTRING_LEN,
  438. ip101g_hw_stats[i].name, ETH_GSTRING_LEN);
  439. }
  440. static u64 ip101g_get_stat(struct phy_device *phydev, int i)
  441. {
  442. struct ip101g_hw_stat stat = ip101g_hw_stats[i];
  443. struct ip101a_g_phy_priv *priv = phydev->priv;
  444. int val;
  445. u64 ret;
  446. val = phy_read_paged(phydev, stat.page, IP101G_CNT_REG);
  447. if (val < 0) {
  448. ret = U64_MAX;
  449. } else {
  450. priv->stats[i] += val;
  451. ret = priv->stats[i];
  452. }
  453. return ret;
  454. }
  455. static void ip101g_get_stats(struct phy_device *phydev,
  456. struct ethtool_stats *stats, u64 *data)
  457. {
  458. int i;
  459. for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++)
  460. data[i] = ip101g_get_stat(phydev, i);
  461. }
  462. static struct phy_driver icplus_driver[] = {
  463. {
  464. PHY_ID_MATCH_MODEL(IP175C_PHY_ID),
  465. .name = "ICPlus IP175C",
  466. /* PHY_BASIC_FEATURES */
  467. .config_init = ip175c_config_init,
  468. .config_aneg = ip175c_config_aneg,
  469. .read_status = ip175c_read_status,
  470. .suspend = genphy_suspend,
  471. .resume = genphy_resume,
  472. }, {
  473. PHY_ID_MATCH_MODEL(IP1001_PHY_ID),
  474. .name = "ICPlus IP1001",
  475. /* PHY_GBIT_FEATURES */
  476. .config_init = ip1001_config_init,
  477. .soft_reset = genphy_soft_reset,
  478. .suspend = genphy_suspend,
  479. .resume = genphy_resume,
  480. }, {
  481. .name = "ICPlus IP101A",
  482. .match_phy_device = ip101a_match_phy_device,
  483. .probe = ip101a_g_probe,
  484. .read_page = ip101a_read_page,
  485. .write_page = ip101a_write_page,
  486. .config_intr = ip101a_g_config_intr,
  487. .handle_interrupt = ip101a_g_handle_interrupt,
  488. .config_init = ip101a_config_init,
  489. .config_aneg = ip101a_g_config_aneg,
  490. .read_status = ip101a_g_read_status,
  491. .soft_reset = genphy_soft_reset,
  492. .suspend = genphy_suspend,
  493. .resume = genphy_resume,
  494. }, {
  495. .name = "ICPlus IP101G",
  496. .match_phy_device = ip101g_match_phy_device,
  497. .probe = ip101a_g_probe,
  498. .read_page = ip101g_read_page,
  499. .write_page = ip101g_write_page,
  500. .config_intr = ip101a_g_config_intr,
  501. .handle_interrupt = ip101a_g_handle_interrupt,
  502. .config_init = ip101g_config_init,
  503. .config_aneg = ip101a_g_config_aneg,
  504. .read_status = ip101a_g_read_status,
  505. .soft_reset = genphy_soft_reset,
  506. .get_sset_count = ip101g_get_sset_count,
  507. .get_strings = ip101g_get_strings,
  508. .get_stats = ip101g_get_stats,
  509. .suspend = genphy_suspend,
  510. .resume = genphy_resume,
  511. } };
  512. module_phy_driver(icplus_driver);
  513. static struct mdio_device_id __maybe_unused icplus_tbl[] = {
  514. { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) },
  515. { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) },
  516. { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) },
  517. { }
  518. };
  519. MODULE_DEVICE_TABLE(mdio, icplus_tbl);