@@ -31,6 +31,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
3131#define PHY_MC_KSZ8081_OMSO_RMII_OVERRIDE_MASK BIT(1)
3232#define PHY_MC_KSZ8081_OMSO_MII_OVERRIDE_MASK BIT(0)
3333
34+ #define PHY_MC_KSZ8081_ICS_REG 0x1B
35+ #define PHY_MC_KSZ8081_ICS_LINK_DOWN_IE_MASK BIT(10)
36+ #define PHY_MC_KSZ8081_ICS_LINK_UP_IE_MASK BIT(8)
37+
3438#define PHY_MC_KSZ8081_CTRL2_REG 0x1F
3539#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7)
3640
@@ -58,10 +62,18 @@ struct mc_ksz8081_config {
5862#define KSZ8081_SILENCE_DEBUG_LOGS BIT(1)
5963#define KSZ8081_LINK_STATE_VALID BIT(2)
6064
65+ #define USING_INTERRUPT_GPIO \
66+ UTIL_OR(DT_ALL_INST_HAS_PROP_STATUS_OKAY(int_gpios), \
67+ UTIL_AND(DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios), \
68+ (config->interrupt_gpio.port != NULL)))
69+
6170struct mc_ksz8081_data {
6271 const struct device * dev ;
6372 struct phy_link_state state ;
6473 phy_callback_t cb ;
74+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
75+ struct gpio_callback gpio_callback ;
76+ #endif
6577 void * cb_data ;
6678 struct k_mutex mutex ;
6779 struct k_work_delayable phy_monitor_work ;
@@ -111,6 +123,74 @@ static int phy_mc_ksz8081_write(const struct device *dev,
111123 return 0 ;
112124}
113125
126+ #if !DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
127+ #define phy_mc_ksz8081_clear_interrupt (data ) 0
128+ #else
129+ static int phy_mc_ksz8081_clear_interrupt (struct mc_ksz8081_data * data )
130+ {
131+ const struct device * dev = data -> dev ;
132+ const struct mc_ksz8081_config * config = dev -> config ;
133+ uint32_t ics ;
134+ int ret ;
135+
136+ /* Lock mutex */
137+ ret = k_mutex_lock (& data -> mutex , K_FOREVER );
138+ if (ret < 0 ) {
139+ LOG_ERR ("PHY mutex lock error" );
140+ return ret ;
141+ }
142+
143+ /* Read/clear PHY interrupt status register */
144+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
145+ if (ret < 0 ) {
146+ LOG_ERR ("Error reading phy (%d) interrupt status register" , config -> addr );
147+ }
148+
149+ /* Unlock mutex */
150+ k_mutex_unlock (& data -> mutex );
151+ return ret ;
152+ }
153+
154+ static int phy_mc_ksz8081_config_interrupt (const struct device * dev )
155+ {
156+ struct mc_ksz8081_data * data = dev -> data ;
157+ uint32_t ics ;
158+ int ret ;
159+
160+ /* Read Interrupt Control/Status register to write back */
161+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
162+ if (ret < 0 ) {
163+ return ret ;
164+ }
165+ ics |= PHY_MC_KSZ8081_ICS_LINK_UP_IE_MASK | PHY_MC_KSZ8081_ICS_LINK_DOWN_IE_MASK ;
166+
167+ /* Write settings to Interrupt Control/Status register */
168+ ret = phy_mc_ksz8081_write (dev , PHY_MC_KSZ8081_ICS_REG , ics );
169+ if (ret < 0 ) {
170+ return ret ;
171+ }
172+
173+ /* Clear interrupt */
174+ ret = phy_mc_ksz8081_clear_interrupt (data );
175+ if (ret < 0 ) {
176+ return ret ;
177+ }
178+
179+ return ret ;
180+ }
181+
182+ static void phy_mc_ksz8081_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
183+ gpio_port_pins_t pins )
184+ {
185+ struct mc_ksz8081_data * data = CONTAINER_OF (cb , struct mc_ksz8081_data , gpio_callback );
186+ int ret = k_work_reschedule (& data -> phy_monitor_work , K_NO_WAIT );
187+
188+ if (ret < 0 ) {
189+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
190+ }
191+ }
192+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
193+
114194static int phy_mc_ksz8081_autonegotiate (const struct device * dev )
115195{
116196 const struct mc_ksz8081_config * config = dev -> config ;
@@ -142,7 +222,6 @@ static int phy_mc_ksz8081_autonegotiate(const struct device *dev)
142222 goto done ;
143223 }
144224
145- /* TODO change this to GPIO interrupt driven */
146225 data -> flags |= KSZ8081_SILENCE_DEBUG_LOGS ;
147226 do {
148227 if (timeout -- == 0 ) {
@@ -432,6 +511,10 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, enum phy_link_speed
432511 /* Unlock mutex */
433512 k_mutex_unlock (& data -> mutex );
434513
514+ if (USING_INTERRUPT_GPIO ) {
515+ return ret ;
516+ }
517+
435518 /* Start monitoring */
436519 k_work_reschedule (& data -> phy_monitor_work ,
437520 K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -465,6 +548,13 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
465548 bool turn_on_logs = false;
466549 int rc = 0 ;
467550
551+ if (USING_INTERRUPT_GPIO ) {
552+ rc = phy_mc_ksz8081_clear_interrupt (data );
553+ if (rc < 0 ) {
554+ return ;
555+ }
556+ }
557+
468558 if (!data -> state .is_up ) {
469559 /* some overrides might need set on cold reset way late for some reason */
470560 phy_mc_ksz8081_static_cfg (dev );
@@ -508,21 +598,50 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
508598 data -> flags |= KSZ8081_SILENCE_DEBUG_LOGS ;
509599 }
510600
511- /* TODO change this to GPIO interrupt driven */
601+ if (USING_INTERRUPT_GPIO ) {
602+ return ;
603+ }
604+
512605 k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
513606}
514607
515608#if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
516609static int ksz8081_init_int_gpios (const struct device * dev )
517610{
518611 const struct mc_ksz8081_config * config = dev -> config ;
612+ struct mc_ksz8081_data * data = dev -> data ;
613+ int ret ;
519614
520615 if (config -> interrupt_gpio .port == NULL ) {
521616 return 0 ;
522617 }
523618
524- /* Prevent NAND TREE mode */
525- return gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_OUTPUT_ACTIVE );
619+ /* Configure interrupt pin */
620+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
621+ if (ret < 0 ) {
622+ goto done ;
623+ }
624+
625+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
626+ BIT (config -> interrupt_gpio .pin ));
627+
628+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
629+ if (ret < 0 ) {
630+ goto done ;
631+ }
632+
633+ ret = phy_mc_ksz8081_config_interrupt (dev );
634+ if (ret < 0 ) {
635+ goto done ;
636+ }
637+
638+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio , GPIO_INT_EDGE_TO_ACTIVE );
639+ done :
640+ if (ret < 0 ) {
641+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
642+ }
643+
644+ return ret ;
526645}
527646#else
528647#define ksz8081_init_int_gpios (dev ) 0
@@ -574,7 +693,7 @@ static int phy_mc_ksz8081_init(const struct device *dev)
574693 }
575694
576695 ret = ksz8081_init_int_gpios (dev );
577- if (ret ) {
696+ if (ret < 0 ) {
578697 return ret ;
579698 }
580699
0 commit comments