dp83822.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Driver for the Texas Instruments DP83822 PHY
  3. *
  4. * Copyright (C) 2017 Texas Instruments Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/ethtool.h>
  16. #include <linux/etherdevice.h>
  17. #include <linux/kernel.h>
  18. #include <linux/mii.h>
  19. #include <linux/module.h>
  20. #include <linux/of.h>
  21. #include <linux/phy.h>
  22. #include <linux/netdevice.h>
  23. #define DP83822_PHY_ID 0x2000a240
  24. #define DP83822_DEVADDR 0x1f
  25. #define MII_DP83822_PHYSCR 0x11
  26. #define MII_DP83822_MISR1 0x12
  27. #define MII_DP83822_MISR2 0x13
  28. #define MII_DP83822_RESET_CTRL 0x1f
  29. #define DP83822_HW_RESET BIT(15)
  30. #define DP83822_SW_RESET BIT(14)
  31. /* PHYSCR Register Fields */
  32. #define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */
  33. #define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */
  34. /* MISR1 bits */
  35. #define DP83822_RX_ERR_HF_INT_EN BIT(0)
  36. #define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1)
  37. #define DP83822_ANEG_COMPLETE_INT_EN BIT(2)
  38. #define DP83822_DUP_MODE_CHANGE_INT_EN BIT(3)
  39. #define DP83822_SPEED_CHANGED_INT_EN BIT(4)
  40. #define DP83822_LINK_STAT_INT_EN BIT(5)
  41. #define DP83822_ENERGY_DET_INT_EN BIT(6)
  42. #define DP83822_LINK_QUAL_INT_EN BIT(7)
  43. /* MISR2 bits */
  44. #define DP83822_JABBER_DET_INT_EN BIT(0)
  45. #define DP83822_WOL_PKT_INT_EN BIT(1)
  46. #define DP83822_SLEEP_MODE_INT_EN BIT(2)
  47. #define DP83822_MDI_XOVER_INT_EN BIT(3)
  48. #define DP83822_LB_FIFO_INT_EN BIT(4)
  49. #define DP83822_PAGE_RX_INT_EN BIT(5)
  50. #define DP83822_ANEG_ERR_INT_EN BIT(6)
  51. #define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7)
  52. /* INT_STAT1 bits */
  53. #define DP83822_WOL_INT_EN BIT(4)
  54. #define DP83822_WOL_INT_STAT BIT(12)
  55. #define MII_DP83822_RXSOP1 0x04a5
  56. #define MII_DP83822_RXSOP2 0x04a6
  57. #define MII_DP83822_RXSOP3 0x04a7
  58. /* WoL Registers */
  59. #define MII_DP83822_WOL_CFG 0x04a0
  60. #define MII_DP83822_WOL_STAT 0x04a1
  61. #define MII_DP83822_WOL_DA1 0x04a2
  62. #define MII_DP83822_WOL_DA2 0x04a3
  63. #define MII_DP83822_WOL_DA3 0x04a4
  64. /* WoL bits */
  65. #define DP83822_WOL_MAGIC_EN BIT(0)
  66. #define DP83822_WOL_SECURE_ON BIT(5)
  67. #define DP83822_WOL_EN BIT(7)
  68. #define DP83822_WOL_INDICATION_SEL BIT(8)
  69. #define DP83822_WOL_CLR_INDICATION BIT(11)
  70. static int dp83822_ack_interrupt(struct phy_device *phydev)
  71. {
  72. int err;
  73. err = phy_read(phydev, MII_DP83822_MISR1);
  74. if (err < 0)
  75. return err;
  76. err = phy_read(phydev, MII_DP83822_MISR2);
  77. if (err < 0)
  78. return err;
  79. return 0;
  80. }
  81. static int dp83822_set_wol(struct phy_device *phydev,
  82. struct ethtool_wolinfo *wol)
  83. {
  84. struct net_device *ndev = phydev->attached_dev;
  85. u16 value;
  86. const u8 *mac;
  87. if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
  88. mac = (const u8 *)ndev->dev_addr;
  89. if (!is_valid_ether_addr(mac))
  90. return -EINVAL;
  91. /* MAC addresses start with byte 5, but stored in mac[0].
  92. * 822 PHYs store bytes 4|5, 2|3, 0|1
  93. */
  94. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1,
  95. (mac[1] << 8) | mac[0]);
  96. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2,
  97. (mac[3] << 8) | mac[2]);
  98. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3,
  99. (mac[5] << 8) | mac[4]);
  100. value = phy_read_mmd(phydev, DP83822_DEVADDR,
  101. MII_DP83822_WOL_CFG);
  102. if (wol->wolopts & WAKE_MAGIC)
  103. value |= DP83822_WOL_MAGIC_EN;
  104. else
  105. value &= ~DP83822_WOL_MAGIC_EN;
  106. if (wol->wolopts & WAKE_MAGICSECURE) {
  107. phy_write_mmd(phydev, DP83822_DEVADDR,
  108. MII_DP83822_RXSOP1,
  109. (wol->sopass[1] << 8) | wol->sopass[0]);
  110. phy_write_mmd(phydev, DP83822_DEVADDR,
  111. MII_DP83822_RXSOP2,
  112. (wol->sopass[3] << 8) | wol->sopass[2]);
  113. phy_write_mmd(phydev, DP83822_DEVADDR,
  114. MII_DP83822_RXSOP3,
  115. (wol->sopass[5] << 8) | wol->sopass[4]);
  116. value |= DP83822_WOL_SECURE_ON;
  117. } else {
  118. value &= ~DP83822_WOL_SECURE_ON;
  119. }
  120. value |= (DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL |
  121. DP83822_WOL_CLR_INDICATION);
  122. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
  123. value);
  124. } else {
  125. value = phy_read_mmd(phydev, DP83822_DEVADDR,
  126. MII_DP83822_WOL_CFG);
  127. value &= ~DP83822_WOL_EN;
  128. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
  129. value);
  130. }
  131. return 0;
  132. }
  133. static void dp83822_get_wol(struct phy_device *phydev,
  134. struct ethtool_wolinfo *wol)
  135. {
  136. int value;
  137. u16 sopass_val;
  138. wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE);
  139. wol->wolopts = 0;
  140. value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
  141. if (value & DP83822_WOL_MAGIC_EN)
  142. wol->wolopts |= WAKE_MAGIC;
  143. if (value & DP83822_WOL_SECURE_ON) {
  144. sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
  145. MII_DP83822_RXSOP1);
  146. wol->sopass[0] = (sopass_val & 0xff);
  147. wol->sopass[1] = (sopass_val >> 8);
  148. sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
  149. MII_DP83822_RXSOP2);
  150. wol->sopass[2] = (sopass_val & 0xff);
  151. wol->sopass[3] = (sopass_val >> 8);
  152. sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
  153. MII_DP83822_RXSOP3);
  154. wol->sopass[4] = (sopass_val & 0xff);
  155. wol->sopass[5] = (sopass_val >> 8);
  156. wol->wolopts |= WAKE_MAGICSECURE;
  157. }
  158. /* WoL is not enabled so set wolopts to 0 */
  159. if (!(value & DP83822_WOL_EN))
  160. wol->wolopts = 0;
  161. }
  162. static int dp83822_config_intr(struct phy_device *phydev)
  163. {
  164. int misr_status;
  165. int physcr_status;
  166. int err;
  167. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  168. misr_status = phy_read(phydev, MII_DP83822_MISR1);
  169. if (misr_status < 0)
  170. return misr_status;
  171. misr_status |= (DP83822_RX_ERR_HF_INT_EN |
  172. DP83822_FALSE_CARRIER_HF_INT_EN |
  173. DP83822_ANEG_COMPLETE_INT_EN |
  174. DP83822_DUP_MODE_CHANGE_INT_EN |
  175. DP83822_SPEED_CHANGED_INT_EN |
  176. DP83822_LINK_STAT_INT_EN |
  177. DP83822_ENERGY_DET_INT_EN |
  178. DP83822_LINK_QUAL_INT_EN);
  179. err = phy_write(phydev, MII_DP83822_MISR1, misr_status);
  180. if (err < 0)
  181. return err;
  182. misr_status = phy_read(phydev, MII_DP83822_MISR2);
  183. if (misr_status < 0)
  184. return misr_status;
  185. misr_status |= (DP83822_JABBER_DET_INT_EN |
  186. DP83822_WOL_PKT_INT_EN |
  187. DP83822_SLEEP_MODE_INT_EN |
  188. DP83822_MDI_XOVER_INT_EN |
  189. DP83822_LB_FIFO_INT_EN |
  190. DP83822_PAGE_RX_INT_EN |
  191. DP83822_ANEG_ERR_INT_EN |
  192. DP83822_EEE_ERROR_CHANGE_INT_EN);
  193. err = phy_write(phydev, MII_DP83822_MISR2, misr_status);
  194. if (err < 0)
  195. return err;
  196. physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
  197. if (physcr_status < 0)
  198. return physcr_status;
  199. physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN;
  200. } else {
  201. err = phy_write(phydev, MII_DP83822_MISR1, 0);
  202. if (err < 0)
  203. return err;
  204. err = phy_write(phydev, MII_DP83822_MISR1, 0);
  205. if (err < 0)
  206. return err;
  207. physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
  208. if (physcr_status < 0)
  209. return physcr_status;
  210. physcr_status &= ~DP83822_PHYSCR_INTEN;
  211. }
  212. return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status);
  213. }
  214. static int dp83822_config_init(struct phy_device *phydev)
  215. {
  216. int err;
  217. int value;
  218. err = genphy_config_init(phydev);
  219. if (err < 0)
  220. return err;
  221. value = DP83822_WOL_MAGIC_EN | DP83822_WOL_SECURE_ON | DP83822_WOL_EN;
  222. return phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
  223. value);
  224. }
  225. static int dp83822_phy_reset(struct phy_device *phydev)
  226. {
  227. int err;
  228. err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET);
  229. if (err < 0)
  230. return err;
  231. dp83822_config_init(phydev);
  232. return 0;
  233. }
  234. static int dp83822_suspend(struct phy_device *phydev)
  235. {
  236. int value;
  237. value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
  238. if (!(value & DP83822_WOL_EN))
  239. genphy_suspend(phydev);
  240. return 0;
  241. }
  242. static int dp83822_resume(struct phy_device *phydev)
  243. {
  244. int value;
  245. genphy_resume(phydev);
  246. value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
  247. phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value |
  248. DP83822_WOL_CLR_INDICATION);
  249. return 0;
  250. }
  251. static struct phy_driver dp83822_driver[] = {
  252. {
  253. .phy_id = DP83822_PHY_ID,
  254. .phy_id_mask = 0xfffffff0,
  255. .name = "TI DP83822",
  256. .features = PHY_BASIC_FEATURES,
  257. .flags = PHY_HAS_INTERRUPT,
  258. .config_init = dp83822_config_init,
  259. .soft_reset = dp83822_phy_reset,
  260. .get_wol = dp83822_get_wol,
  261. .set_wol = dp83822_set_wol,
  262. .ack_interrupt = dp83822_ack_interrupt,
  263. .config_intr = dp83822_config_intr,
  264. .suspend = dp83822_suspend,
  265. .resume = dp83822_resume,
  266. },
  267. };
  268. module_phy_driver(dp83822_driver);
  269. static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
  270. { DP83822_PHY_ID, 0xfffffff0 },
  271. { },
  272. };
  273. MODULE_DEVICE_TABLE(mdio, dp83822_tbl);
  274. MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver");
  275. MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
  276. MODULE_LICENSE("GPL");