66 */
77
88#include <zephyr/logging/log.h>
9- LOG_MODULE_REGISTER (phy_adin2111 , CONFIG_PHY_LOG_LEVEL );
109
10+ #if DT_NODE_HAS_STATUS (DT_INST (0 , adi_adin2111_phy ), okay )
1111#define DT_DRV_COMPAT adi_adin2111_phy
12+ #else
13+ #define DT_DRV_COMPAT adi_adin1100_phy
14+ #endif
15+
16+ LOG_MODULE_REGISTER (DT_DRV_COMPAT , CONFIG_PHY_LOG_LEVEL );
1217
1318#include <errno.h>
1419#include <stdint.h>
@@ -23,20 +28,28 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
2328
2429/* PHYs out of reset check retry delay */
2530#define ADIN2111_PHY_AWAIT_DELAY_POLL_US 15U
26- /* Number of retries for PHYs out of reset check */
27- #define ADIN2111_PHY_AWAIT_RETRY_COUNT 200U
31+ /*
32+ * Number of retries for PHYs out of reset check,
33+ * rmii variants as ADIN11XX need 70ms maximum after hw reset to be up,
34+ * so the increasing the count for that, as default 25ms (sw reset) + 45.
35+ */
36+ #define ADIN2111_PHY_AWAIT_RETRY_COUNT 3000U
2837
2938/* PHY's software powerdown check retry delay */
3039#define ADIN2111_PHY_SFT_PD_DELAY_POLL_US 15U
3140/* Number of retries for PHY's software powerdown check */
3241#define ADIN2111_PHY_SFT_PD_RETRY_COUNT 200U
3342
43+ /* Software reset, CLK_25 disabled time*/
44+ #define ADIN1100_PHY_SFT_RESET_MS 25U
45+
3446/* PHYs autonegotiation complete timeout */
3547#define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS 3000U
3648
3749/* ADIN2111 PHY identifier */
3850#define ADIN2111_PHY_ID 0x0283BCA1U
3951#define ADIN1110_PHY_ID 0x0283BC91U
52+ #define ADIN1100_PHY_ID 0x0283BC81U
4053
4154/* System Interrupt Mask Register */
4255#define ADIN2111_PHY_CRSM_IRQ_MASK 0x0020U
@@ -77,17 +90,26 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
7790/* LED 0 Enable */
7891#define ADIN2111_PHY_LED_CNTRL_LED0_EN BIT(7)
7992
93+ /* MMD bridge regs */
94+ #define ADIN1100_MMD_ACCESS_CNTRL 0x0DU
95+ #define ADIN1100_MMD_ACCESS 0x0EU
96+
8097struct phy_adin2111_config {
8198 const struct device * mdio ;
8299 uint8_t phy_addr ;
83100 bool led0_en ;
84101 bool led1_en ;
85102 bool tx_24v ;
103+ bool mii ;
86104};
87105
88106struct phy_adin2111_data {
107+ const struct device * dev ;
89108 struct phy_link_state state ;
90109 struct k_sem sem ;
110+ struct k_work_delayable monitor_work ;
111+ phy_callback_t cb ;
112+ void * cb_data ;
91113};
92114
93115static inline int phy_adin2111_c22_read (const struct device * dev , uint16_t reg ,
@@ -106,22 +128,62 @@ static inline int phy_adin2111_c22_write(const struct device *dev, uint16_t reg,
106128 return mdio_write (cfg -> mdio , cfg -> phy_addr , reg , val );
107129}
108130
109- static inline int phy_adin2111_c45_write (const struct device * dev , uint16_t devad ,
110- uint16_t reg , uint16_t val )
131+ static int phy_adin2111_c45_setup_dev_reg (const struct device * dev , uint16_t devad ,
132+ uint16_t reg )
111133{
112134 const struct phy_adin2111_config * cfg = dev -> config ;
135+ int rval ;
113136
114- return mdio_write_c45 (cfg -> mdio , cfg -> phy_addr , devad , reg , val );
137+ rval = mdio_write (cfg -> mdio , cfg -> phy_addr , ADIN1100_MMD_ACCESS_CNTRL , devad );
138+ if (rval < 0 ) {
139+ return rval ;
140+ }
141+ rval = mdio_write (cfg -> mdio , cfg -> phy_addr , ADIN1100_MMD_ACCESS , reg );
142+ if (rval < 0 ) {
143+ return rval ;
144+ }
145+
146+ return mdio_write (cfg -> mdio , cfg -> phy_addr , ADIN1100_MMD_ACCESS_CNTRL , devad | BIT (14 ));
115147}
116148
117- static inline int phy_adin2111_c45_read (const struct device * dev , uint16_t devad ,
118- uint16_t reg , uint16_t * val )
149+ static int phy_adin2111_c45_read (const struct device * dev , uint16_t devad ,
150+ uint16_t reg , uint16_t * val )
119151{
120152 const struct phy_adin2111_config * cfg = dev -> config ;
153+ int rval ;
154+
155+ if (cfg -> mii ) {
156+ /* Using C22 -> devad bridge */
157+ rval = phy_adin2111_c45_setup_dev_reg (dev , devad , reg );
158+ if (rval < 0 ) {
159+ return rval ;
160+ }
161+
162+ return mdio_read (cfg -> mdio , cfg -> phy_addr , ADIN1100_MMD_ACCESS , val );
163+ }
121164
122165 return mdio_read_c45 (cfg -> mdio , cfg -> phy_addr , devad , reg , val );
123166}
124167
168+ static int phy_adin2111_c45_write (const struct device * dev , uint16_t devad ,
169+ uint16_t reg , uint16_t val )
170+ {
171+ const struct phy_adin2111_config * cfg = dev -> config ;
172+ int rval ;
173+
174+ if (cfg -> mii ) {
175+ /* Using C22 -> devad bridge */
176+ rval = phy_adin2111_c45_setup_dev_reg (dev , devad , reg );
177+ if (rval < 0 ) {
178+ return rval ;
179+ }
180+
181+ return mdio_write (cfg -> mdio , cfg -> phy_addr , ADIN1100_MMD_ACCESS , val );
182+ }
183+
184+ return mdio_write_c45 (cfg -> mdio , cfg -> phy_addr , devad , reg , val );
185+ }
186+
125187static int phy_adin2111_reg_read (const struct device * dev , uint16_t reg_addr ,
126188 uint32_t * data )
127189{
@@ -304,6 +366,84 @@ static int phy_adin2111_cfg_link(const struct device *dev,
304366 return - ENOTSUP ;
305367}
306368
369+ static int phy_adin2111_reset (const struct device * dev )
370+ {
371+ int ret ;
372+
373+ ret = phy_adin2111_c22_write (dev , MII_BMCR , MII_BMCR_RESET );
374+ if (ret < 0 ) {
375+ return ret ;
376+ }
377+
378+ k_msleep (ADIN1100_PHY_SFT_RESET_MS );
379+
380+ return 0 ;
381+ }
382+
383+ static void invoke_link_cb (const struct device * dev )
384+ {
385+ struct phy_adin2111_data * const data = dev -> data ;
386+ struct phy_link_state state ;
387+
388+ if (data -> cb == NULL ) {
389+ return ;
390+ }
391+
392+ data -> cb (dev , & state , data -> cb_data );
393+ }
394+
395+ static int update_link_state (const struct device * dev )
396+ {
397+ struct phy_adin2111_data * const data = dev -> data ;
398+ const struct phy_adin2111_config * config = dev -> config ;
399+ struct phy_link_state old_state ;
400+ uint16_t bmsr ;
401+ int ret ;
402+
403+ ret = phy_adin2111_c22_read (dev , MII_BMSR , & bmsr );
404+ if (ret < 0 ) {
405+ return ret ;
406+ }
407+
408+ old_state = data -> state ;
409+ data -> state .is_up = !!(bmsr & MII_BMSR_LINK_STATUS );
410+
411+ if (old_state .speed != data -> state .speed || old_state .is_up != data -> state .is_up ) {
412+
413+ LOG_INF ("PHY (%d) Link is %s" , config -> phy_addr , data -> state .is_up ? "up" : "down" );
414+
415+ if (data -> state .is_up == false) {
416+ return 0 ;
417+ }
418+
419+ invoke_link_cb (dev );
420+
421+ LOG_INF ("PHY (%d) Link speed %s Mb, %s duplex\n" , config -> phy_addr ,
422+ (PHY_LINK_IS_SPEED_100M (data -> state .speed ) ? "100" : "10" ),
423+ PHY_LINK_IS_FULL_DUPLEX (data -> state .speed ) ? "full" : "half" );
424+ }
425+
426+ return 0 ;
427+ }
428+
429+ static void monitor_work_handler (struct k_work * work )
430+ {
431+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
432+ struct phy_adin2111_data * const data =
433+ CONTAINER_OF (dwork , struct phy_adin2111_data , monitor_work );
434+ const struct device * dev = data -> dev ;
435+ int rc ;
436+
437+ k_sem_take (& data -> sem , K_FOREVER );
438+
439+ rc = update_link_state (dev );
440+
441+ k_sem_give (& data -> sem );
442+
443+ /* Submit delayed work */
444+ k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
445+ }
446+
307447static int phy_adin2111_init (const struct device * dev )
308448{
309449 const struct phy_adin2111_config * const cfg = dev -> config ;
@@ -313,9 +453,21 @@ static int phy_adin2111_init(const struct device *dev)
313453 bool tx_24v_supported = false;
314454 int ret ;
315455
456+ data -> dev = dev ;
316457 data -> state .is_up = false;
317458 data -> state .speed = LINK_FULL_10BASE_T ;
318459
460+ /*
461+ * For adin1100 and further mii stuff,
462+ * reset may not be performed from the mac layer, doing a clean reset here.
463+ */
464+ if (cfg -> mii ) {
465+ ret = phy_adin2111_reset (dev );
466+ if (ret < 0 ) {
467+ return ret ;
468+ }
469+ }
470+
319471 ret = phy_adin2111_await_phy (dev );
320472 if (ret < 0 ) {
321473 LOG_ERR ("PHY %u didn't come out of reset, %d" ,
@@ -330,7 +482,7 @@ static int phy_adin2111_init(const struct device *dev)
330482 return - ENODEV ;
331483 }
332484
333- if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID ) {
485+ if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID && phy_id != ADIN1100_PHY_ID ) {
334486 LOG_ERR ("PHY %u unexpected PHY ID %X" , cfg -> phy_addr , phy_id );
335487 return - EINVAL ;
336488 }
@@ -447,6 +599,11 @@ static int phy_adin2111_init(const struct device *dev)
447599 return ret ;
448600 }
449601
602+ if (cfg -> mii ) {
603+ k_work_init_delayable (& data -> monitor_work , monitor_work_handler );
604+ monitor_work_handler (& data -> monitor_work .work );
605+ }
606+
450607 /**
451608 * done, PHY is in software powerdown (SFT PD)
452609 * exit software powerdown, PHY 1 has to exit before PHY 2
@@ -458,10 +615,17 @@ static int phy_adin2111_init(const struct device *dev)
458615static int phy_adin2111_link_cb_set (const struct device * dev , phy_callback_t cb ,
459616 void * user_data )
460617{
461- ARG_UNUSED (dev );
462- ARG_UNUSED (cb );
463- ARG_UNUSED (user_data );
464- return - ENOTSUP ;
618+ struct phy_adin2111_data * const data = dev -> data ;
619+
620+ data -> cb = cb ;
621+ data -> cb_data = user_data ;
622+
623+ /* Invoke the callback to notify the caller of the current
624+ * link status.
625+ */
626+ invoke_link_cb (dev );
627+
628+ return 0 ;
465629}
466630
467631static const struct ethphy_driver_api phy_adin2111_api = {
@@ -479,6 +643,8 @@ static const struct ethphy_driver_api phy_adin2111_api = {
479643 .led0_en = DT_INST_PROP(n, led0_en), \
480644 .led1_en = DT_INST_PROP(n, led1_en), \
481645 .tx_24v = !(DT_INST_PROP(n, disable_tx_mode_24v)), \
646+ IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(adi_adin1100_phy), \
647+ (.mii = 1)) \
482648 }; \
483649 static struct phy_adin2111_data phy_adin2111_data_##n = { \
484650 .sem = Z_SEM_INITIALIZER(phy_adin2111_data_##n.sem, 1, 1), \
0 commit comments