@@ -29,6 +29,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
2929#define PHY_MC_KSZ8081_OMSO_RMII_OVERRIDE_MASK BIT(1)
3030#define PHY_MC_KSZ8081_OMSO_MII_OVERRIDE_MASK BIT(0)
3131
32+ #define PHY_MC_KSZ8081_ICS_REG 0x1B
33+ #define PHY_MC_KSZ8081_ICS_LINK_DOWN_IE_MASK BIT(10)
34+ #define PHY_MC_KSZ8081_ICS_LINK_UP_IE_MASK BIT(8)
35+
3236#define PHY_MC_KSZ8081_CTRL2_REG 0x1F
3337#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7)
3438
@@ -54,6 +58,9 @@ struct mc_ksz8081_data {
5458 const struct device * dev ;
5559 struct phy_link_state state ;
5660 phy_callback_t cb ;
61+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
62+ struct gpio_callback gpio_callback ;
63+ #endif
5764 void * cb_data ;
5865 struct k_mutex mutex ;
5966 struct k_work_delayable phy_monitor_work ;
@@ -90,6 +97,72 @@ static int phy_mc_ksz8081_write(const struct device *dev,
9097 return 0 ;
9198}
9299
100+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
101+ static int phy_mc_ksz8081_clear_interrupt (struct mc_ksz8081_data * data )
102+ {
103+ const struct device * dev = data -> dev ;
104+ const struct mc_ksz8081_config * config = dev -> config ;
105+ uint32_t ics ;
106+ int ret ;
107+
108+ /* Lock mutex */
109+ ret = k_mutex_lock (& data -> mutex , K_FOREVER );
110+ if (ret ) {
111+ LOG_ERR ("PHY mutex lock error" );
112+ return ret ;
113+ }
114+
115+ /* Read/clear PHY interrupt status register */
116+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
117+ if (ret ) {
118+ LOG_ERR ("Error reading phy (%d) interrupt status register" , config -> addr );
119+ }
120+
121+ /* Unlock mutex */
122+ k_mutex_unlock (& data -> mutex );
123+ return ret ;
124+ }
125+
126+ static int phy_mc_ksz8081_config_interrupt (const struct device * dev )
127+ {
128+ struct mc_ksz8081_data * data = dev -> data ;
129+ uint32_t ics ;
130+ int ret ;
131+
132+ /* Read Interrupt Control/Status register to write back */
133+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
134+ if (ret ) {
135+ return ret ;
136+ }
137+ ics |= PHY_MC_KSZ8081_ICS_LINK_UP_IE_MASK | PHY_MC_KSZ8081_ICS_LINK_DOWN_IE_MASK ;
138+
139+ /* Write settings to Interrupt Control/Status register */
140+ ret = phy_mc_ksz8081_write (dev , PHY_MC_KSZ8081_ICS_REG , ics );
141+ if (ret ) {
142+ return ret ;
143+ }
144+
145+ /* Clear interrupt */
146+ ret = phy_mc_ksz8081_clear_interrupt (data );
147+ if (ret ) {
148+ return ret ;
149+ }
150+
151+ return ret ;
152+ }
153+
154+ static void phy_mc_ksz8081_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
155+ gpio_port_pins_t pins )
156+ {
157+ struct mc_ksz8081_data * data = CONTAINER_OF (cb , struct mc_ksz8081_data , gpio_callback );
158+ int ret = k_work_reschedule (& data -> phy_monitor_work , K_NO_WAIT );
159+
160+ if (ret < 0 ) {
161+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
162+ }
163+ }
164+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
165+
93166static int phy_mc_ksz8081_autonegotiate (const struct device * dev )
94167{
95168 const struct mc_ksz8081_config * config = dev -> config ;
@@ -349,7 +422,13 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
349422 }
350423
351424 /* We are going to reconfigure the phy, don't need to monitor until done */
425+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
426+ if (!config -> interrupt_gpio .port ) {
427+ k_work_cancel_delayable (& data -> phy_monitor_work );
428+ }
429+ #else
352430 k_work_cancel_delayable (& data -> phy_monitor_work );
431+ #endif
353432
354433 /* DT configurations */
355434 ret = phy_mc_ksz8081_static_cfg (dev );
@@ -422,6 +501,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
422501 /* Unlock mutex */
423502 k_mutex_unlock (& data -> mutex );
424503
504+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
505+ if (config -> interrupt_gpio .port ) {
506+ return ret ;
507+ }
508+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
509+
425510 /* Start monitoring */
426511 k_work_reschedule (& data -> phy_monitor_work ,
427512 K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -450,9 +535,21 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
450535 struct mc_ksz8081_data * data =
451536 CONTAINER_OF (dwork , struct mc_ksz8081_data , phy_monitor_work );
452537 const struct device * dev = data -> dev ;
538+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
539+ const struct mc_ksz8081_config * config = dev -> config ;
540+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
453541 struct phy_link_state state = {};
454542 int rc ;
455543
544+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
545+ if (config -> interrupt_gpio .port ) {
546+ rc = phy_mc_ksz8081_clear_interrupt (data );
547+ if (rc ) {
548+ return ;
549+ }
550+ }
551+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
552+
456553 rc = phy_mc_ksz8081_get_link (dev , & state );
457554
458555 if (rc == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
@@ -462,6 +559,12 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
462559 }
463560 }
464561
562+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
563+ if (config -> interrupt_gpio .port ) {
564+ return ;
565+ }
566+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
567+
465568 /* TODO change this to GPIO interrupt driven */
466569 k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
467570}
@@ -513,6 +616,42 @@ static int phy_mc_ksz8081_init(const struct device *dev)
513616 k_work_init_delayable (& data -> phy_monitor_work ,
514617 phy_mc_ksz8081_monitor_work_handler );
515618
619+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
620+ do {
621+ if (!config -> interrupt_gpio .port ) {
622+ phy_mc_ksz8081_monitor_work_handler (& data -> phy_monitor_work .work );
623+ break ;
624+ }
625+
626+ /* Configure interrupt pin */
627+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
628+ if (ret ) {
629+ break ;
630+ }
631+
632+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
633+ BIT (config -> interrupt_gpio .pin ));
634+ if (ret ) {
635+ break ;
636+ }
637+
638+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
639+ if (ret ) {
640+ break ;
641+ }
642+
643+ ret = phy_mc_ksz8081_config_interrupt (dev );
644+ if (ret ) {
645+ break ;
646+ }
647+
648+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio ,
649+ GPIO_INT_EDGE_TO_ACTIVE );
650+ } while (0 );
651+ if (ret ) {
652+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
653+ }
654+ #endif
516655 return 0 ;
517656}
518657
0 commit comments