@@ -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 ;
@@ -125,6 +131,64 @@ static int phy_check_ksz9131_id(const struct device *dev)
125131 return ret ;
126132}
127133
134+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
135+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
136+ {
137+ const struct device * dev = data -> dev ;
138+ const struct mchp_ksz9131_config * cfg = dev -> config ;
139+ uint16_t reg_val ;
140+ int ret ;
141+
142+ k_sem_take (& data -> sem , K_FOREVER );
143+
144+ /* Read/clear PHY interrupt status register */
145+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
146+ if (ret < 0 ) {
147+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
148+ }
149+
150+ k_sem_give (& data -> sem );
151+
152+ return ret ;
153+ }
154+
155+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
156+ {
157+ struct mchp_ksz9131_data * data = dev -> data ;
158+ uint16_t reg_val ;
159+ int ret ;
160+
161+ /* Read Interrupt Control/Status register to write back */
162+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
163+ if (ret < 0 ) {
164+ return ret ;
165+ }
166+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
167+
168+ /* Write settings to Interrupt Control/Status register */
169+ ret = ksz9131_write (dev , 27 , reg_val );
170+ if (ret < 0 ) {
171+ return ret ;
172+ }
173+
174+ /* Clear interrupt */
175+ ret = phy_mchp_ksz9131_clear_interrupt (data );
176+
177+ return ret ;
178+ }
179+
180+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
181+ gpio_port_pins_t pins )
182+ {
183+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
184+ int ret = k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
185+
186+ if (ret < 0 ) {
187+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
188+ }
189+ }
190+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
191+
128192static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
129193{
130194 const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -184,6 +248,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
184248
185249static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
186250{
251+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
252+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
253+ #endif
187254 struct mchp_ksz9131_data * const data = dev -> data ;
188255 uint16_t anar ;
189256 uint16_t c1kt ;
@@ -192,7 +259,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
192259 k_sem_take (& data -> sem , K_FOREVER );
193260
194261 /* We are going to reconfigure the phy, don't need to monitor until done */
262+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
263+ if (!cfg -> interrupt_gpio .port ) {
264+ k_work_cancel_delayable (& data -> monitor_work );
265+ }
266+ #else
195267 k_work_cancel_delayable (& data -> monitor_work );
268+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
196269
197270 ret = ksz9131_read (dev , MII_ANAR , & anar );
198271 if (ret < 0 ) {
@@ -254,6 +327,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
254327done :
255328 k_sem_give (& data -> sem );
256329
330+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
331+ if (cfg -> interrupt_gpio .port ) {
332+ return ret ;
333+ }
334+ #endif
335+
257336 /* Start monitoring */
258337 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
259338
@@ -352,9 +431,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
352431 struct mchp_ksz9131_data * const data =
353432 CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
354433 const struct device * dev = data -> dev ;
434+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
435+ const struct mchp_ksz9131_config * cfg = dev -> config ;
436+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
355437 struct phy_link_state state = {};
356438 int ret ;
357439
440+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
441+ if (cfg -> interrupt_gpio .port ) {
442+ ret = phy_mchp_ksz9131_clear_interrupt (data );
443+ if (ret < 0 ) {
444+ return ;
445+ }
446+ }
447+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
448+
358449 ret = phy_mchp_ksz9131_get_link (dev , & state );
359450 if (ret == 0 && (state .speed != data -> state .speed || state .is_up != data -> state .is_up )) {
360451 memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -363,6 +454,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
363454 }
364455 }
365456
457+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
458+ if (cfg -> interrupt_gpio .port ) {
459+ return ;
460+ }
461+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
462+
366463 /* Submit delayed work */
367464 k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
368465}
@@ -392,7 +489,37 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
392489
393490 k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
394491
492+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
493+ if (!cfg -> interrupt_gpio .port ) {
494+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
495+ goto done ;
496+ }
497+
498+ /* Configure interrupt pin */
499+ ret = gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT );
500+ if (ret < 0 ) {
501+ goto done ;
502+ }
503+
504+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
505+ BIT (cfg -> interrupt_gpio .pin ));
506+
507+ ret = gpio_add_callback_dt (& cfg -> interrupt_gpio , & data -> gpio_callback );
508+ if (ret < 0 ) {
509+ goto done ;
510+ }
511+
512+ ret = phy_mchp_ksz9131_config_interrupt (dev );
513+ if (ret < 0 ) {
514+ goto done ;
515+ }
516+
517+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio ,
518+ GPIO_INT_EDGE_TO_ACTIVE );
519+ done :
520+ #else
395521 phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
522+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
396523
397524 if (ret < 0 ) {
398525 LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -409,10 +536,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
409536 .write = phy_mchp_ksz9131_write ,
410537};
411538
539+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
540+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
541+ #else
542+ #define INTERRUPT_GPIO (n )
543+ #endif /* interrupt gpio */
544+
412545#define MICROCHIP_KSZ9131_INIT (n ) \
413546 static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
414547 .phy_addr = DT_INST_REG_ADDR(n), \
415548 .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
549+ INTERRUPT_GPIO(n) \
416550 }; \
417551 \
418552 static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments