intel-xway.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
  4. * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de>
  5. */
  6. #include <linux/mdio.h>
  7. #include <linux/module.h>
  8. #include <linux/phy.h>
  9. #include <linux/of.h>
  10. #include <linux/bitfield.h>
  11. #define XWAY_MDIO_MIICTRL 0x17 /* mii control */
  12. #define XWAY_MDIO_IMASK 0x19 /* interrupt mask */
  13. #define XWAY_MDIO_ISTAT 0x1A /* interrupt status */
  14. #define XWAY_MDIO_LED 0x1B /* led control */
  15. #define XWAY_MDIO_MIICTRL_RXSKEW_MASK GENMASK(14, 12)
  16. #define XWAY_MDIO_MIICTRL_TXSKEW_MASK GENMASK(10, 8)
  17. /* bit 15:12 are reserved */
  18. #define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */
  19. #define XWAY_MDIO_LED_LED2_EN BIT(10) /* Enable the integrated function of LED2 */
  20. #define XWAY_MDIO_LED_LED1_EN BIT(9) /* Enable the integrated function of LED1 */
  21. #define XWAY_MDIO_LED_LED0_EN BIT(8) /* Enable the integrated function of LED0 */
  22. /* bit 7:4 are reserved */
  23. #define XWAY_MDIO_LED_LED3_DA BIT(3) /* Direct Access to LED3 */
  24. #define XWAY_MDIO_LED_LED2_DA BIT(2) /* Direct Access to LED2 */
  25. #define XWAY_MDIO_LED_LED1_DA BIT(1) /* Direct Access to LED1 */
  26. #define XWAY_MDIO_LED_LED0_DA BIT(0) /* Direct Access to LED0 */
  27. #define XWAY_MDIO_INIT_WOL BIT(15) /* Wake-On-LAN */
  28. #define XWAY_MDIO_INIT_MSRE BIT(14)
  29. #define XWAY_MDIO_INIT_NPRX BIT(13)
  30. #define XWAY_MDIO_INIT_NPTX BIT(12)
  31. #define XWAY_MDIO_INIT_ANE BIT(11) /* Auto-Neg error */
  32. #define XWAY_MDIO_INIT_ANC BIT(10) /* Auto-Neg complete */
  33. #define XWAY_MDIO_INIT_ADSC BIT(5) /* Link auto-downspeed detect */
  34. #define XWAY_MDIO_INIT_MPIPC BIT(4)
  35. #define XWAY_MDIO_INIT_MDIXC BIT(3)
  36. #define XWAY_MDIO_INIT_DXMC BIT(2) /* Duplex mode change */
  37. #define XWAY_MDIO_INIT_LSPC BIT(1) /* Link speed change */
  38. #define XWAY_MDIO_INIT_LSTC BIT(0) /* Link state change */
  39. #define XWAY_MDIO_INIT_MASK (XWAY_MDIO_INIT_LSTC | \
  40. XWAY_MDIO_INIT_ADSC)
  41. #define ADVERTISED_MPD BIT(10) /* Multi-port device */
  42. /* LED Configuration */
  43. #define XWAY_MMD_LEDCH 0x01E0
  44. /* Inverse of SCAN Function */
  45. #define XWAY_MMD_LEDCH_NACS_NONE 0x0000
  46. #define XWAY_MMD_LEDCH_NACS_LINK 0x0001
  47. #define XWAY_MMD_LEDCH_NACS_PDOWN 0x0002
  48. #define XWAY_MMD_LEDCH_NACS_EEE 0x0003
  49. #define XWAY_MMD_LEDCH_NACS_ANEG 0x0004
  50. #define XWAY_MMD_LEDCH_NACS_ABIST 0x0005
  51. #define XWAY_MMD_LEDCH_NACS_CDIAG 0x0006
  52. #define XWAY_MMD_LEDCH_NACS_TEST 0x0007
  53. /* Slow Blink Frequency */
  54. #define XWAY_MMD_LEDCH_SBF_F02HZ 0x0000
  55. #define XWAY_MMD_LEDCH_SBF_F04HZ 0x0010
  56. #define XWAY_MMD_LEDCH_SBF_F08HZ 0x0020
  57. #define XWAY_MMD_LEDCH_SBF_F16HZ 0x0030
  58. /* Fast Blink Frequency */
  59. #define XWAY_MMD_LEDCH_FBF_F02HZ 0x0000
  60. #define XWAY_MMD_LEDCH_FBF_F04HZ 0x0040
  61. #define XWAY_MMD_LEDCH_FBF_F08HZ 0x0080
  62. #define XWAY_MMD_LEDCH_FBF_F16HZ 0x00C0
  63. /* LED Configuration */
  64. #define XWAY_MMD_LEDCL 0x01E1
  65. /* Complex Blinking Configuration */
  66. #define XWAY_MMD_LEDCH_CBLINK_NONE 0x0000
  67. #define XWAY_MMD_LEDCH_CBLINK_LINK 0x0001
  68. #define XWAY_MMD_LEDCH_CBLINK_PDOWN 0x0002
  69. #define XWAY_MMD_LEDCH_CBLINK_EEE 0x0003
  70. #define XWAY_MMD_LEDCH_CBLINK_ANEG 0x0004
  71. #define XWAY_MMD_LEDCH_CBLINK_ABIST 0x0005
  72. #define XWAY_MMD_LEDCH_CBLINK_CDIAG 0x0006
  73. #define XWAY_MMD_LEDCH_CBLINK_TEST 0x0007
  74. /* Complex SCAN Configuration */
  75. #define XWAY_MMD_LEDCH_SCAN_NONE 0x0000
  76. #define XWAY_MMD_LEDCH_SCAN_LINK 0x0010
  77. #define XWAY_MMD_LEDCH_SCAN_PDOWN 0x0020
  78. #define XWAY_MMD_LEDCH_SCAN_EEE 0x0030
  79. #define XWAY_MMD_LEDCH_SCAN_ANEG 0x0040
  80. #define XWAY_MMD_LEDCH_SCAN_ABIST 0x0050
  81. #define XWAY_MMD_LEDCH_SCAN_CDIAG 0x0060
  82. #define XWAY_MMD_LEDCH_SCAN_TEST 0x0070
  83. /* Configuration for LED Pin x */
  84. #define XWAY_MMD_LED0H 0x01E2
  85. /* Fast Blinking Configuration */
  86. #define XWAY_MMD_LEDxH_BLINKF_MASK 0x000F
  87. #define XWAY_MMD_LEDxH_BLINKF_NONE 0x0000
  88. #define XWAY_MMD_LEDxH_BLINKF_LINK10 0x0001
  89. #define XWAY_MMD_LEDxH_BLINKF_LINK100 0x0002
  90. #define XWAY_MMD_LEDxH_BLINKF_LINK10X 0x0003
  91. #define XWAY_MMD_LEDxH_BLINKF_LINK1000 0x0004
  92. #define XWAY_MMD_LEDxH_BLINKF_LINK10_0 0x0005
  93. #define XWAY_MMD_LEDxH_BLINKF_LINK100X 0x0006
  94. #define XWAY_MMD_LEDxH_BLINKF_LINK10XX 0x0007
  95. #define XWAY_MMD_LEDxH_BLINKF_PDOWN 0x0008
  96. #define XWAY_MMD_LEDxH_BLINKF_EEE 0x0009
  97. #define XWAY_MMD_LEDxH_BLINKF_ANEG 0x000A
  98. #define XWAY_MMD_LEDxH_BLINKF_ABIST 0x000B
  99. #define XWAY_MMD_LEDxH_BLINKF_CDIAG 0x000C
  100. /* Constant On Configuration */
  101. #define XWAY_MMD_LEDxH_CON_MASK 0x00F0
  102. #define XWAY_MMD_LEDxH_CON_NONE 0x0000
  103. #define XWAY_MMD_LEDxH_CON_LINK10 0x0010
  104. #define XWAY_MMD_LEDxH_CON_LINK100 0x0020
  105. #define XWAY_MMD_LEDxH_CON_LINK10X 0x0030
  106. #define XWAY_MMD_LEDxH_CON_LINK1000 0x0040
  107. #define XWAY_MMD_LEDxH_CON_LINK10_0 0x0050
  108. #define XWAY_MMD_LEDxH_CON_LINK100X 0x0060
  109. #define XWAY_MMD_LEDxH_CON_LINK10XX 0x0070
  110. #define XWAY_MMD_LEDxH_CON_PDOWN 0x0080
  111. #define XWAY_MMD_LEDxH_CON_EEE 0x0090
  112. #define XWAY_MMD_LEDxH_CON_ANEG 0x00A0
  113. #define XWAY_MMD_LEDxH_CON_ABIST 0x00B0
  114. #define XWAY_MMD_LEDxH_CON_CDIAG 0x00C0
  115. #define XWAY_MMD_LEDxH_CON_COPPER 0x00D0
  116. #define XWAY_MMD_LEDxH_CON_FIBER 0x00E0
  117. /* Configuration for LED Pin x */
  118. #define XWAY_MMD_LED0L 0x01E3
  119. /* Pulsing Configuration */
  120. #define XWAY_MMD_LEDxL_PULSE_MASK 0x000F
  121. #define XWAY_MMD_LEDxL_PULSE_NONE 0x0000
  122. #define XWAY_MMD_LEDxL_PULSE_TXACT 0x0001
  123. #define XWAY_MMD_LEDxL_PULSE_RXACT 0x0002
  124. #define XWAY_MMD_LEDxL_PULSE_COL 0x0004
  125. /* Slow Blinking Configuration */
  126. #define XWAY_MMD_LEDxL_BLINKS_MASK 0x00F0
  127. #define XWAY_MMD_LEDxL_BLINKS_NONE 0x0000
  128. #define XWAY_MMD_LEDxL_BLINKS_LINK10 0x0010
  129. #define XWAY_MMD_LEDxL_BLINKS_LINK100 0x0020
  130. #define XWAY_MMD_LEDxL_BLINKS_LINK10X 0x0030
  131. #define XWAY_MMD_LEDxL_BLINKS_LINK1000 0x0040
  132. #define XWAY_MMD_LEDxL_BLINKS_LINK10_0 0x0050
  133. #define XWAY_MMD_LEDxL_BLINKS_LINK100X 0x0060
  134. #define XWAY_MMD_LEDxL_BLINKS_LINK10XX 0x0070
  135. #define XWAY_MMD_LEDxL_BLINKS_PDOWN 0x0080
  136. #define XWAY_MMD_LEDxL_BLINKS_EEE 0x0090
  137. #define XWAY_MMD_LEDxL_BLINKS_ANEG 0x00A0
  138. #define XWAY_MMD_LEDxL_BLINKS_ABIST 0x00B0
  139. #define XWAY_MMD_LEDxL_BLINKS_CDIAG 0x00C0
  140. #define XWAY_MMD_LED1H 0x01E4
  141. #define XWAY_MMD_LED1L 0x01E5
  142. #define XWAY_MMD_LED2H 0x01E6
  143. #define XWAY_MMD_LED2L 0x01E7
  144. #define XWAY_MMD_LED3H 0x01E8
  145. #define XWAY_MMD_LED3L 0x01E9
  146. #define XWAY_GPHY_MAX_LEDS 3
  147. #define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx))
  148. #define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx))
  149. #define XWAY_GPHY_LED_DA(idx) BIT(idx)
  150. #define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx))
  151. #define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx))
  152. #define PHY_ID_PHY11G_1_3 0x030260D1
  153. #define PHY_ID_PHY22F_1_3 0x030260E1
  154. #define PHY_ID_PHY11G_1_4 0xD565A400
  155. #define PHY_ID_PHY22F_1_4 0xD565A410
  156. #define PHY_ID_PHY11G_1_5 0xD565A401
  157. #define PHY_ID_PHY22F_1_5 0xD565A411
  158. #define PHY_ID_PHY11G_VR9_1_1 0xD565A408
  159. #define PHY_ID_PHY22F_VR9_1_1 0xD565A418
  160. #define PHY_ID_PHY11G_VR9_1_2 0xD565A409
  161. #define PHY_ID_PHY22F_VR9_1_2 0xD565A419
  162. static const int xway_internal_delay[] = {0, 500, 1000, 1500, 2000, 2500,
  163. 3000, 3500};
  164. static int xway_gphy_rgmii_init(struct phy_device *phydev)
  165. {
  166. unsigned int delay_size = ARRAY_SIZE(xway_internal_delay);
  167. s32 int_delay;
  168. int val = 0;
  169. if (!phy_interface_is_rgmii(phydev))
  170. return 0;
  171. /* Existing behavior was to use default pin strapping delay in rgmii
  172. * mode, but rgmii should have meant no delay. Warn existing users,
  173. * but do not change anything at the moment.
  174. */
  175. if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
  176. u16 txskew, rxskew;
  177. val = phy_read(phydev, XWAY_MDIO_MIICTRL);
  178. if (val < 0)
  179. return val;
  180. txskew = FIELD_GET(XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
  181. rxskew = FIELD_GET(XWAY_MDIO_MIICTRL_RXSKEW_MASK, val);
  182. if (txskew > 0 || rxskew > 0)
  183. phydev_warn(phydev,
  184. "PHY has delays (e.g. via pin strapping), but phy-mode = 'rgmii'\n"
  185. "Should be 'rgmii-id' to use internal delays txskew:%d ps rxskew:%d ps\n",
  186. xway_internal_delay[txskew],
  187. xway_internal_delay[rxskew]);
  188. return 0;
  189. }
  190. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  191. phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  192. int_delay = phy_get_internal_delay(phydev, xway_internal_delay,
  193. delay_size, true);
  194. /* if rx-internal-delay-ps is missing, use default of 2.0 ns */
  195. if (int_delay < 0)
  196. int_delay = 4; /* 2000 ps */
  197. val |= FIELD_PREP(XWAY_MDIO_MIICTRL_RXSKEW_MASK, int_delay);
  198. }
  199. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  200. phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
  201. int_delay = phy_get_internal_delay(phydev, xway_internal_delay,
  202. delay_size, false);
  203. /* if tx-internal-delay-ps is missing, use default of 2.0 ns */
  204. if (int_delay < 0)
  205. int_delay = 4; /* 2000 ps */
  206. val |= FIELD_PREP(XWAY_MDIO_MIICTRL_TXSKEW_MASK, int_delay);
  207. }
  208. return phy_modify(phydev, XWAY_MDIO_MIICTRL,
  209. XWAY_MDIO_MIICTRL_RXSKEW_MASK |
  210. XWAY_MDIO_MIICTRL_TXSKEW_MASK, val);
  211. }
  212. static int xway_gphy_init_leds(struct phy_device *phydev)
  213. {
  214. int err;
  215. u32 ledxh;
  216. u32 ledxl;
  217. /* Ensure that integrated led function is enabled for all leds */
  218. err = phy_write(phydev, XWAY_MDIO_LED,
  219. XWAY_MDIO_LED_LED0_EN |
  220. XWAY_MDIO_LED_LED1_EN |
  221. XWAY_MDIO_LED_LED2_EN |
  222. XWAY_MDIO_LED_LED3_EN);
  223. if (err)
  224. return err;
  225. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
  226. XWAY_MMD_LEDCH_NACS_NONE |
  227. XWAY_MMD_LEDCH_SBF_F02HZ |
  228. XWAY_MMD_LEDCH_FBF_F16HZ);
  229. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCL,
  230. XWAY_MMD_LEDCH_CBLINK_NONE |
  231. XWAY_MMD_LEDCH_SCAN_NONE);
  232. /**
  233. * In most cases only one LED is connected to this phy, so
  234. * configure them all to constant on and pulse mode. LED3 is
  235. * only available in some packages, leave it in its reset
  236. * configuration.
  237. */
  238. ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX;
  239. ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT |
  240. XWAY_MMD_LEDxL_BLINKS_NONE;
  241. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh);
  242. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl);
  243. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh);
  244. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl);
  245. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
  246. phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
  247. return 0;
  248. }
  249. static int xway_gphy_config_init(struct phy_device *phydev)
  250. {
  251. struct device_node *np;
  252. int err;
  253. /* Mask all interrupts */
  254. err = phy_write(phydev, XWAY_MDIO_IMASK, 0);
  255. if (err)
  256. return err;
  257. /* Use default LED configuration if 'leds' node isn't defined */
  258. np = of_get_child_by_name(phydev->mdio.dev.of_node, "leds");
  259. if (np)
  260. of_node_put(np);
  261. else
  262. xway_gphy_init_leds(phydev);
  263. /* Clear all pending interrupts */
  264. phy_read(phydev, XWAY_MDIO_ISTAT);
  265. err = xway_gphy_rgmii_init(phydev);
  266. if (err)
  267. return err;
  268. return 0;
  269. }
  270. static int xway_gphy14_config_aneg(struct phy_device *phydev)
  271. {
  272. int reg, err;
  273. /* Advertise as multi-port device, see IEEE802.3-2002 40.5.1.1 */
  274. /* This is a workaround for an errata in rev < 1.5 devices */
  275. reg = phy_read(phydev, MII_CTRL1000);
  276. reg |= ADVERTISED_MPD;
  277. err = phy_write(phydev, MII_CTRL1000, reg);
  278. if (err)
  279. return err;
  280. return genphy_config_aneg(phydev);
  281. }
  282. static int xway_gphy_ack_interrupt(struct phy_device *phydev)
  283. {
  284. int reg;
  285. reg = phy_read(phydev, XWAY_MDIO_ISTAT);
  286. return (reg < 0) ? reg : 0;
  287. }
  288. static int xway_gphy_config_intr(struct phy_device *phydev)
  289. {
  290. u16 mask = 0;
  291. int err;
  292. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  293. err = xway_gphy_ack_interrupt(phydev);
  294. if (err)
  295. return err;
  296. mask = XWAY_MDIO_INIT_MASK;
  297. err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
  298. } else {
  299. err = phy_write(phydev, XWAY_MDIO_IMASK, mask);
  300. if (err)
  301. return err;
  302. err = xway_gphy_ack_interrupt(phydev);
  303. }
  304. return err;
  305. }
  306. static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev)
  307. {
  308. int irq_status;
  309. irq_status = phy_read(phydev, XWAY_MDIO_ISTAT);
  310. if (irq_status < 0) {
  311. phy_error(phydev);
  312. return IRQ_NONE;
  313. }
  314. if (!(irq_status & XWAY_MDIO_INIT_MASK))
  315. return IRQ_NONE;
  316. phy_trigger_machine(phydev);
  317. return IRQ_HANDLED;
  318. }
  319. static int xway_gphy_led_brightness_set(struct phy_device *phydev,
  320. u8 index, enum led_brightness value)
  321. {
  322. int ret;
  323. if (index >= XWAY_GPHY_MAX_LEDS)
  324. return -EINVAL;
  325. /* clear EN and set manual LED state */
  326. ret = phy_modify(phydev, XWAY_MDIO_LED,
  327. ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) |
  328. XWAY_GPHY_LED_DA(index),
  329. (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index));
  330. if (ret)
  331. return ret;
  332. /* clear HW LED setup */
  333. if (value == LED_OFF) {
  334. ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0);
  335. if (ret)
  336. return ret;
  337. return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0);
  338. } else {
  339. return 0;
  340. }
  341. }
  342. static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
  343. BIT(TRIGGER_NETDEV_LINK_10) |
  344. BIT(TRIGGER_NETDEV_LINK_100) |
  345. BIT(TRIGGER_NETDEV_LINK_1000) |
  346. BIT(TRIGGER_NETDEV_RX) |
  347. BIT(TRIGGER_NETDEV_TX));
  348. static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index,
  349. unsigned long rules)
  350. {
  351. if (index >= XWAY_GPHY_MAX_LEDS)
  352. return -EINVAL;
  353. /* activity triggers are not possible without combination with a link
  354. * trigger.
  355. */
  356. if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) &&
  357. !(rules & (BIT(TRIGGER_NETDEV_LINK) |
  358. BIT(TRIGGER_NETDEV_LINK_10) |
  359. BIT(TRIGGER_NETDEV_LINK_100) |
  360. BIT(TRIGGER_NETDEV_LINK_1000))))
  361. return -EOPNOTSUPP;
  362. /* All other combinations of the supported triggers are allowed */
  363. if (rules & ~supported_triggers)
  364. return -EOPNOTSUPP;
  365. return 0;
  366. }
  367. static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index,
  368. unsigned long *rules)
  369. {
  370. int lval, hval;
  371. if (index >= XWAY_GPHY_MAX_LEDS)
  372. return -EINVAL;
  373. hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index));
  374. if (hval < 0)
  375. return hval;
  376. lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index));
  377. if (lval < 0)
  378. return lval;
  379. if (hval & XWAY_MMD_LEDxH_CON_LINK10)
  380. *rules |= BIT(TRIGGER_NETDEV_LINK_10);
  381. if (hval & XWAY_MMD_LEDxH_CON_LINK100)
  382. *rules |= BIT(TRIGGER_NETDEV_LINK_100);
  383. if (hval & XWAY_MMD_LEDxH_CON_LINK1000)
  384. *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
  385. if ((hval & XWAY_MMD_LEDxH_CON_LINK10) &&
  386. (hval & XWAY_MMD_LEDxH_CON_LINK100) &&
  387. (hval & XWAY_MMD_LEDxH_CON_LINK1000))
  388. *rules |= BIT(TRIGGER_NETDEV_LINK);
  389. if (lval & XWAY_MMD_LEDxL_PULSE_TXACT)
  390. *rules |= BIT(TRIGGER_NETDEV_TX);
  391. if (lval & XWAY_MMD_LEDxL_PULSE_RXACT)
  392. *rules |= BIT(TRIGGER_NETDEV_RX);
  393. return 0;
  394. }
  395. static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index,
  396. unsigned long rules)
  397. {
  398. u16 hval = 0, lval = 0;
  399. int ret;
  400. if (index >= XWAY_GPHY_MAX_LEDS)
  401. return -EINVAL;
  402. if (rules & BIT(TRIGGER_NETDEV_LINK) ||
  403. rules & BIT(TRIGGER_NETDEV_LINK_10))
  404. hval |= XWAY_MMD_LEDxH_CON_LINK10;
  405. if (rules & BIT(TRIGGER_NETDEV_LINK) ||
  406. rules & BIT(TRIGGER_NETDEV_LINK_100))
  407. hval |= XWAY_MMD_LEDxH_CON_LINK100;
  408. if (rules & BIT(TRIGGER_NETDEV_LINK) ||
  409. rules & BIT(TRIGGER_NETDEV_LINK_1000))
  410. hval |= XWAY_MMD_LEDxH_CON_LINK1000;
  411. if (rules & BIT(TRIGGER_NETDEV_TX))
  412. lval |= XWAY_MMD_LEDxL_PULSE_TXACT;
  413. if (rules & BIT(TRIGGER_NETDEV_RX))
  414. lval |= XWAY_MMD_LEDxL_PULSE_RXACT;
  415. ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval);
  416. if (ret)
  417. return ret;
  418. ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval);
  419. if (ret)
  420. return ret;
  421. return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index));
  422. }
  423. static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index,
  424. unsigned long modes)
  425. {
  426. bool force_active_low = false, force_active_high = false;
  427. u32 mode;
  428. if (index >= XWAY_GPHY_MAX_LEDS)
  429. return -EINVAL;
  430. for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
  431. switch (mode) {
  432. case PHY_LED_ACTIVE_LOW:
  433. force_active_low = true;
  434. break;
  435. case PHY_LED_ACTIVE_HIGH:
  436. force_active_high = true;
  437. break;
  438. default:
  439. return -EINVAL;
  440. }
  441. }
  442. if (force_active_low)
  443. return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
  444. if (force_active_high)
  445. return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index));
  446. return -EINVAL;
  447. }
  448. static struct phy_driver xway_gphy[] = {
  449. {
  450. .phy_id = PHY_ID_PHY11G_1_3,
  451. .phy_id_mask = 0xffffffff,
  452. .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.3",
  453. /* PHY_GBIT_FEATURES */
  454. .config_init = xway_gphy_config_init,
  455. .config_aneg = xway_gphy14_config_aneg,
  456. .handle_interrupt = xway_gphy_handle_interrupt,
  457. .config_intr = xway_gphy_config_intr,
  458. .suspend = genphy_suspend,
  459. .resume = genphy_resume,
  460. .led_brightness_set = xway_gphy_led_brightness_set,
  461. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  462. .led_hw_control_get = xway_gphy_led_hw_control_get,
  463. .led_hw_control_set = xway_gphy_led_hw_control_set,
  464. .led_polarity_set = xway_gphy_led_polarity_set,
  465. }, {
  466. .phy_id = PHY_ID_PHY22F_1_3,
  467. .phy_id_mask = 0xffffffff,
  468. .name = "Intel XWAY PHY22F (PEF 7061) v1.3",
  469. /* PHY_BASIC_FEATURES */
  470. .config_init = xway_gphy_config_init,
  471. .config_aneg = xway_gphy14_config_aneg,
  472. .handle_interrupt = xway_gphy_handle_interrupt,
  473. .config_intr = xway_gphy_config_intr,
  474. .suspend = genphy_suspend,
  475. .resume = genphy_resume,
  476. .led_brightness_set = xway_gphy_led_brightness_set,
  477. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  478. .led_hw_control_get = xway_gphy_led_hw_control_get,
  479. .led_hw_control_set = xway_gphy_led_hw_control_set,
  480. .led_polarity_set = xway_gphy_led_polarity_set,
  481. }, {
  482. .phy_id = PHY_ID_PHY11G_1_4,
  483. .phy_id_mask = 0xffffffff,
  484. .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.4",
  485. /* PHY_GBIT_FEATURES */
  486. .config_init = xway_gphy_config_init,
  487. .config_aneg = xway_gphy14_config_aneg,
  488. .handle_interrupt = xway_gphy_handle_interrupt,
  489. .config_intr = xway_gphy_config_intr,
  490. .suspend = genphy_suspend,
  491. .resume = genphy_resume,
  492. .led_brightness_set = xway_gphy_led_brightness_set,
  493. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  494. .led_hw_control_get = xway_gphy_led_hw_control_get,
  495. .led_hw_control_set = xway_gphy_led_hw_control_set,
  496. .led_polarity_set = xway_gphy_led_polarity_set,
  497. }, {
  498. .phy_id = PHY_ID_PHY22F_1_4,
  499. .phy_id_mask = 0xffffffff,
  500. .name = "Intel XWAY PHY22F (PEF 7061) v1.4",
  501. /* PHY_BASIC_FEATURES */
  502. .config_init = xway_gphy_config_init,
  503. .config_aneg = xway_gphy14_config_aneg,
  504. .handle_interrupt = xway_gphy_handle_interrupt,
  505. .config_intr = xway_gphy_config_intr,
  506. .suspend = genphy_suspend,
  507. .resume = genphy_resume,
  508. .led_brightness_set = xway_gphy_led_brightness_set,
  509. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  510. .led_hw_control_get = xway_gphy_led_hw_control_get,
  511. .led_hw_control_set = xway_gphy_led_hw_control_set,
  512. .led_polarity_set = xway_gphy_led_polarity_set,
  513. }, {
  514. .phy_id = PHY_ID_PHY11G_1_5,
  515. .phy_id_mask = 0xffffffff,
  516. .name = "Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6",
  517. /* PHY_GBIT_FEATURES */
  518. .config_init = xway_gphy_config_init,
  519. .handle_interrupt = xway_gphy_handle_interrupt,
  520. .config_intr = xway_gphy_config_intr,
  521. .suspend = genphy_suspend,
  522. .resume = genphy_resume,
  523. .led_brightness_set = xway_gphy_led_brightness_set,
  524. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  525. .led_hw_control_get = xway_gphy_led_hw_control_get,
  526. .led_hw_control_set = xway_gphy_led_hw_control_set,
  527. .led_polarity_set = xway_gphy_led_polarity_set,
  528. }, {
  529. .phy_id = PHY_ID_PHY22F_1_5,
  530. .phy_id_mask = 0xffffffff,
  531. .name = "Intel XWAY PHY22F (PEF 7061) v1.5 / v1.6",
  532. /* PHY_BASIC_FEATURES */
  533. .config_init = xway_gphy_config_init,
  534. .handle_interrupt = xway_gphy_handle_interrupt,
  535. .config_intr = xway_gphy_config_intr,
  536. .suspend = genphy_suspend,
  537. .resume = genphy_resume,
  538. .led_brightness_set = xway_gphy_led_brightness_set,
  539. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  540. .led_hw_control_get = xway_gphy_led_hw_control_get,
  541. .led_hw_control_set = xway_gphy_led_hw_control_set,
  542. .led_polarity_set = xway_gphy_led_polarity_set,
  543. }, {
  544. .phy_id = PHY_ID_PHY11G_VR9_1_1,
  545. .phy_id_mask = 0xffffffff,
  546. .name = "Intel XWAY PHY11G (xRX v1.1 integrated)",
  547. /* PHY_GBIT_FEATURES */
  548. .config_init = xway_gphy_config_init,
  549. .handle_interrupt = xway_gphy_handle_interrupt,
  550. .config_intr = xway_gphy_config_intr,
  551. .suspend = genphy_suspend,
  552. .resume = genphy_resume,
  553. .led_brightness_set = xway_gphy_led_brightness_set,
  554. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  555. .led_hw_control_get = xway_gphy_led_hw_control_get,
  556. .led_hw_control_set = xway_gphy_led_hw_control_set,
  557. .led_polarity_set = xway_gphy_led_polarity_set,
  558. }, {
  559. .phy_id = PHY_ID_PHY22F_VR9_1_1,
  560. .phy_id_mask = 0xffffffff,
  561. .name = "Intel XWAY PHY22F (xRX v1.1 integrated)",
  562. /* PHY_BASIC_FEATURES */
  563. .config_init = xway_gphy_config_init,
  564. .handle_interrupt = xway_gphy_handle_interrupt,
  565. .config_intr = xway_gphy_config_intr,
  566. .suspend = genphy_suspend,
  567. .resume = genphy_resume,
  568. .led_brightness_set = xway_gphy_led_brightness_set,
  569. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  570. .led_hw_control_get = xway_gphy_led_hw_control_get,
  571. .led_hw_control_set = xway_gphy_led_hw_control_set,
  572. .led_polarity_set = xway_gphy_led_polarity_set,
  573. }, {
  574. .phy_id = PHY_ID_PHY11G_VR9_1_2,
  575. .phy_id_mask = 0xffffffff,
  576. .name = "Intel XWAY PHY11G (xRX v1.2 integrated)",
  577. /* PHY_GBIT_FEATURES */
  578. .config_init = xway_gphy_config_init,
  579. .handle_interrupt = xway_gphy_handle_interrupt,
  580. .config_intr = xway_gphy_config_intr,
  581. .suspend = genphy_suspend,
  582. .resume = genphy_resume,
  583. .led_brightness_set = xway_gphy_led_brightness_set,
  584. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  585. .led_hw_control_get = xway_gphy_led_hw_control_get,
  586. .led_hw_control_set = xway_gphy_led_hw_control_set,
  587. .led_polarity_set = xway_gphy_led_polarity_set,
  588. }, {
  589. .phy_id = PHY_ID_PHY22F_VR9_1_2,
  590. .phy_id_mask = 0xffffffff,
  591. .name = "Intel XWAY PHY22F (xRX v1.2 integrated)",
  592. /* PHY_BASIC_FEATURES */
  593. .config_init = xway_gphy_config_init,
  594. .handle_interrupt = xway_gphy_handle_interrupt,
  595. .config_intr = xway_gphy_config_intr,
  596. .suspend = genphy_suspend,
  597. .resume = genphy_resume,
  598. .led_brightness_set = xway_gphy_led_brightness_set,
  599. .led_hw_is_supported = xway_gphy_led_hw_is_supported,
  600. .led_hw_control_get = xway_gphy_led_hw_control_get,
  601. .led_hw_control_set = xway_gphy_led_hw_control_set,
  602. .led_polarity_set = xway_gphy_led_polarity_set,
  603. },
  604. };
  605. module_phy_driver(xway_gphy);
  606. static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = {
  607. { PHY_ID_PHY11G_1_3, 0xffffffff },
  608. { PHY_ID_PHY22F_1_3, 0xffffffff },
  609. { PHY_ID_PHY11G_1_4, 0xffffffff },
  610. { PHY_ID_PHY22F_1_4, 0xffffffff },
  611. { PHY_ID_PHY11G_1_5, 0xffffffff },
  612. { PHY_ID_PHY22F_1_5, 0xffffffff },
  613. { PHY_ID_PHY11G_VR9_1_1, 0xffffffff },
  614. { PHY_ID_PHY22F_VR9_1_1, 0xffffffff },
  615. { PHY_ID_PHY11G_VR9_1_2, 0xffffffff },
  616. { PHY_ID_PHY22F_VR9_1_2, 0xffffffff },
  617. { }
  618. };
  619. MODULE_DEVICE_TABLE(mdio, xway_gphy_tbl);
  620. MODULE_DESCRIPTION("Intel XWAY PHY driver");
  621. MODULE_LICENSE("GPL");