@@ -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 < 0 ) {
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 < 0 ) {
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 < 0 ) {
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 < 0 ) {
142+ return ret ;
143+ }
144+
145+ /* Clear interrupt */
146+ ret = phy_mc_ksz8081_clear_interrupt (data );
147+ if (ret < 0 ) {
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 ;
@@ -116,7 +189,6 @@ static int phy_mc_ksz8081_autonegotiate(const struct device *dev)
116189 return ret ;
117190 }
118191
119- /* TODO change this to GPIO interrupt driven */
120192 do {
121193 if (timeout -- == 0 ) {
122194 LOG_DBG ("PHY (%d) autonegotiation timed out" , config -> addr );
@@ -349,7 +421,13 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
349421 }
350422
351423 /* We are going to reconfigure the phy, don't need to monitor until done */
424+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
425+ if (!config -> interrupt_gpio .port ) {
426+ k_work_cancel_delayable (& data -> phy_monitor_work );
427+ }
428+ #else
352429 k_work_cancel_delayable (& data -> phy_monitor_work );
430+ #endif
353431
354432 /* DT configurations */
355433 ret = phy_mc_ksz8081_static_cfg (dev );
@@ -422,6 +500,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
422500 /* Unlock mutex */
423501 k_mutex_unlock (& data -> mutex );
424502
503+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
504+ if (config -> interrupt_gpio .port ) {
505+ return ret ;
506+ }
507+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
508+
425509 /* Start monitoring */
426510 k_work_reschedule (& data -> phy_monitor_work ,
427511 K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -450,9 +534,21 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
450534 struct mc_ksz8081_data * data =
451535 CONTAINER_OF (dwork , struct mc_ksz8081_data , phy_monitor_work );
452536 const struct device * dev = data -> dev ;
537+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
538+ const struct mc_ksz8081_config * config = dev -> config ;
539+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
453540 struct phy_link_state state = {};
454541 int rc ;
455542
543+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
544+ if (config -> interrupt_gpio .port ) {
545+ rc = phy_mc_ksz8081_clear_interrupt (data );
546+ if (rc < 0 ) {
547+ return ;
548+ }
549+ }
550+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
551+
456552 rc = phy_mc_ksz8081_get_link (dev , & state );
457553
458554 if (rc == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
@@ -462,7 +558,12 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
462558 }
463559 }
464560
465- /* TODO change this to GPIO interrupt driven */
561+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
562+ if (config -> interrupt_gpio .port ) {
563+ return ;
564+ }
565+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
566+
466567 k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
467568}
468569
@@ -513,6 +614,41 @@ static int phy_mc_ksz8081_init(const struct device *dev)
513614 k_work_init_delayable (& data -> phy_monitor_work ,
514615 phy_mc_ksz8081_monitor_work_handler );
515616
617+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
618+ if (!config -> interrupt_gpio .port ) {
619+ phy_mc_ksz8081_monitor_work_handler (& data -> phy_monitor_work .work );
620+ goto done ;
621+ }
622+
623+ /* Configure interrupt pin */
624+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
625+ if (ret < 0 ) {
626+ goto done ;
627+ }
628+
629+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
630+ BIT (config -> interrupt_gpio .pin ));
631+ if (ret < 0 ) {
632+ goto done ;
633+ }
634+
635+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
636+ if (ret < 0 ) {
637+ goto done ;
638+ }
639+
640+ ret = phy_mc_ksz8081_config_interrupt (dev );
641+ if (ret < 0 ) {
642+ goto done ;
643+ }
644+
645+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio ,
646+ GPIO_INT_EDGE_TO_ACTIVE );
647+ done :
648+ if (ret < 0 ) {
649+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
650+ }
651+ #endif
516652 return 0 ;
517653}
518654
0 commit comments