@@ -28,11 +28,17 @@ LOG_MODULE_REGISTER(phy_mchp_ksz9131, CONFIG_PHY_LOG_LEVEL);
2828struct mchp_ksz9131_config {
2929 uint8_t phy_addr ;
3030 const struct device * const mdio ;
31+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
32+ const struct gpio_dt_spec interrupt_gpio ;
33+ #endif
3134};
3235
3336struct mchp_ksz9131_data {
3437 const struct device * dev ;
3538 phy_callback_t cb ;
39+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
40+ struct gpio_callback gpio_callback ;
41+ #endif
3642 void * cb_data ;
3743 struct k_work_delayable monitor_work ;
3844 struct phy_link_state state ;
@@ -128,6 +134,67 @@ static int phy_check_ksz9131_id(const struct device *dev)
128134 return ret ;
129135}
130136
137+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
138+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
139+ {
140+ const struct device * dev = data -> dev ;
141+ const struct mchp_ksz9131_config * cfg = dev -> config ;
142+ uint16_t reg_val ;
143+ int ret ;
144+
145+ k_sem_take (& data -> sem , K_FOREVER );
146+
147+ /* Read/clear PHY interrupt status register */
148+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
149+ if (ret < 0 ) {
150+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
151+ }
152+
153+ k_sem_give (& data -> sem );
154+
155+ return ret ;
156+ }
157+
158+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
159+ {
160+ struct mchp_ksz9131_data * data = dev -> data ;
161+ uint16_t reg_val ;
162+ int ret ;
163+
164+ /* Read Interrupt Control/Status register to write back */
165+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
166+ if (ret < 0 ) {
167+ return ret ;
168+ }
169+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
170+
171+ /* Write settings to Interrupt Control/Status register */
172+ ret = ksz9131_write (dev , 27 , reg_val );
173+ if (ret < 0 ) {
174+ return ret ;
175+ }
176+
177+ /* Clear interrupt */
178+ ret = phy_mchp_ksz9131_clear_interrupt (data );
179+ if (ret < 0 ) {
180+ return ret ;
181+ }
182+
183+ return ret ;
184+ }
185+
186+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
187+ gpio_port_pins_t pins )
188+ {
189+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
190+ int ret = k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
191+
192+ if (ret < 0 ) {
193+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
194+ }
195+ }
196+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
197+
131198static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
132199{
133200 const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -183,6 +250,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
183250
184251static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
185252{
253+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
254+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
255+ #endif
186256 struct mchp_ksz9131_data * const data = dev -> data ;
187257 uint16_t anar ;
188258 uint16_t c1kt ;
@@ -191,7 +261,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
191261 k_sem_take (& data -> sem , K_FOREVER );
192262
193263 /* We are going to reconfigure the phy, don't need to monitor until done */
264+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
265+ if (!cfg -> interrupt_gpio .port ) {
266+ k_work_cancel_delayable (& data -> monitor_work );
267+ }
268+ #else
194269 k_work_cancel_delayable (& data -> monitor_work );
270+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
195271
196272 do {
197273 BREAK_IF_ERR (ret , ksz9131_read (dev , MII_ANAR , & anar ));
@@ -243,6 +319,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
243319
244320 k_sem_give (& data -> sem );
245321
322+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
323+ if (cfg -> interrupt_gpio .port ) {
324+ return ret ;
325+ }
326+ #endif
327+
246328 /* Start monitoring */
247329 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
248330
@@ -331,9 +413,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
331413 struct mchp_ksz9131_data * const data =
332414 CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
333415 const struct device * dev = data -> dev ;
416+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
417+ const struct mchp_ksz9131_config * cfg = dev -> config ;
418+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
334419 struct phy_link_state state = {};
335420 int ret ;
336421
422+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
423+ if (cfg -> interrupt_gpio .port ) {
424+ ret = phy_mchp_ksz9131_clear_interrupt (data );
425+ if (ret < 0 ) {
426+ return ;
427+ }
428+ }
429+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
430+
337431 ret = phy_mchp_ksz9131_get_link (dev , & state );
338432 if (ret == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
339433 memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -342,6 +436,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
342436 }
343437 }
344438
439+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
440+ if (cfg -> interrupt_gpio .port ) {
441+ return ;
442+ }
443+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
444+
345445 /* Submit delayed work */
346446 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
347447}
@@ -371,7 +471,30 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
371471
372472 k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
373473
474+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
475+ do {
476+ if (!cfg -> interrupt_gpio .port ) {
477+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
478+ break ;
479+ }
480+
481+ /* Configure interrupt pin */
482+ BREAK_IF_ERR (ret , gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT ));
483+
484+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
485+ BIT (cfg -> interrupt_gpio .pin ));
486+
487+ BREAK_IF_ERR (ret , gpio_add_callback_dt (& cfg -> interrupt_gpio ,
488+ & data -> gpio_callback ));
489+
490+ BREAK_IF_ERR (ret , phy_mchp_ksz9131_config_interrupt (dev ));
491+
492+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio ,
493+ GPIO_INT_EDGE_TO_ACTIVE );
494+ } while (0 );
495+ #else
374496 phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
497+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
375498
376499 if (ret < 0 ) {
377500 LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -388,10 +511,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
388511 .write = phy_mchp_ksz9131_write ,
389512};
390513
514+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
515+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
516+ #else
517+ #define INTERRUPT_GPIO (n )
518+ #endif /* interrupt gpio */
519+
391520#define MICROCHIP_KSZ9131_INIT (n ) \
392521 static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
393522 .phy_addr = DT_INST_REG_ADDR(n), \
394523 .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
524+ INTERRUPT_GPIO(n) \
395525 }; \
396526 \
397527 static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments