@@ -21,11 +21,17 @@ LOG_MODULE_REGISTER(phy_mchp_ksz9131, CONFIG_PHY_LOG_LEVEL);
2121struct mchp_ksz9131_config {
2222 uint8_t phy_addr ;
2323 const struct device * const mdio ;
24+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
25+ const struct gpio_dt_spec interrupt_gpio ;
26+ #endif
2427};
2528
2629struct mchp_ksz9131_data {
2730 const struct device * dev ;
2831 phy_callback_t cb ;
32+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
33+ struct gpio_callback gpio_callback ;
34+ #endif
2935 void * cb_data ;
3036 struct k_work_delayable monitor_work ;
3137 struct phy_link_state state ;
@@ -127,6 +133,64 @@ static int phy_check_ksz9131_id(const struct device *dev)
127133 return ret ;
128134}
129135
136+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
137+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
138+ {
139+ const struct device * dev = data -> dev ;
140+ const struct mchp_ksz9131_config * cfg = dev -> config ;
141+ uint16_t reg_val ;
142+ int ret ;
143+
144+ k_sem_take (& data -> sem , K_FOREVER );
145+
146+ /* Read/clear PHY interrupt status register */
147+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
148+ if (ret < 0 ) {
149+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
150+ }
151+
152+ k_sem_give (& data -> sem );
153+
154+ return ret ;
155+ }
156+
157+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
158+ {
159+ struct mchp_ksz9131_data * data = dev -> data ;
160+ uint16_t reg_val ;
161+ int ret ;
162+
163+ /* Read Interrupt Control/Status register to write back */
164+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
165+ if (ret < 0 ) {
166+ return ret ;
167+ }
168+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
169+
170+ /* Write settings to Interrupt Control/Status register */
171+ ret = ksz9131_write (dev , 27 , reg_val );
172+ if (ret < 0 ) {
173+ return ret ;
174+ }
175+
176+ /* Clear interrupt */
177+ ret = phy_mchp_ksz9131_clear_interrupt (data );
178+
179+ return ret ;
180+ }
181+
182+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
183+ gpio_port_pins_t pins )
184+ {
185+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
186+ int ret = k_work_reschedule (& data -> 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+
130194static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
131195{
132196 const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -186,6 +250,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
186250
187251static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
188252{
253+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
254+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
255+ #endif
189256 struct mchp_ksz9131_data * const data = dev -> data ;
190257 uint16_t anar ;
191258 uint16_t c1kt ;
@@ -194,7 +261,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
194261 k_sem_take (& data -> sem , K_FOREVER );
195262
196263 /* 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
197269 k_work_cancel_delayable (& data -> monitor_work );
270+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
198271
199272 ret = ksz9131_read (dev , MII_ANAR , & anar );
200273 if (ret < 0 ) {
@@ -256,6 +329,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
256329done :
257330 k_sem_give (& data -> sem );
258331
332+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
333+ if (cfg -> interrupt_gpio .port ) {
334+ return ret ;
335+ }
336+ #endif
337+
259338 /* Start monitoring */
260339 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
261340
@@ -356,9 +435,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
356435 struct mchp_ksz9131_data * const data =
357436 CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
358437 const struct device * dev = data -> dev ;
438+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
439+ const struct mchp_ksz9131_config * cfg = dev -> config ;
440+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
359441 struct phy_link_state state = {};
360442 int ret ;
361443
444+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
445+ if (cfg -> interrupt_gpio .port ) {
446+ ret = phy_mchp_ksz9131_clear_interrupt (data );
447+ if (ret < 0 ) {
448+ return ;
449+ }
450+ }
451+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
452+
362453 ret = phy_mchp_ksz9131_get_link (dev , & state );
363454 if (ret == 0 && (state .speed != data -> state .speed || state .is_up != data -> state .is_up )) {
364455 memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -367,6 +458,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
367458 }
368459 }
369460
461+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
462+ if (cfg -> interrupt_gpio .port ) {
463+ return ;
464+ }
465+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
466+
370467 /* Submit delayed work */
371468 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
372469}
@@ -396,7 +493,37 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
396493
397494 k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
398495
496+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
497+ if (!cfg -> interrupt_gpio .port ) {
498+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
499+ goto done ;
500+ }
501+
502+ /* Configure interrupt pin */
503+ ret = gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT );
504+ if (ret < 0 ) {
505+ goto done ;
506+ }
507+
508+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
509+ BIT (cfg -> interrupt_gpio .pin ));
510+
511+ ret = gpio_add_callback_dt (& cfg -> interrupt_gpio , & data -> gpio_callback );
512+ if (ret < 0 ) {
513+ goto done ;
514+ }
515+
516+ ret = phy_mchp_ksz9131_config_interrupt (dev );
517+ if (ret < 0 ) {
518+ goto done ;
519+ }
520+
521+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio ,
522+ GPIO_INT_EDGE_TO_ACTIVE );
523+ done :
524+ #else
399525 phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
526+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
400527
401528 if (ret < 0 ) {
402529 LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -413,10 +540,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
413540 .write = phy_mchp_ksz9131_write ,
414541};
415542
543+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
544+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
545+ #else
546+ #define INTERRUPT_GPIO (n )
547+ #endif /* interrupt gpio */
548+
416549#define MICROCHIP_KSZ9131_INIT (n ) \
417550 static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
418551 .phy_addr = DT_INST_REG_ADDR(n), \
419552 .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
553+ INTERRUPT_GPIO(n) \
420554 }; \
421555 \
422556 static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments