@@ -29,6 +29,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
29
29
#define PHY_MC_KSZ8081_OMSO_RMII_OVERRIDE_MASK BIT(1)
30
30
#define PHY_MC_KSZ8081_OMSO_MII_OVERRIDE_MASK BIT(0)
31
31
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
+
32
36
#define PHY_MC_KSZ8081_CTRL2_REG 0x1F
33
37
#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7)
34
38
@@ -54,6 +58,9 @@ struct mc_ksz8081_data {
54
58
const struct device * dev ;
55
59
struct phy_link_state state ;
56
60
phy_callback_t cb ;
61
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
62
+ struct gpio_callback gpio_callback ;
63
+ #endif
57
64
void * cb_data ;
58
65
struct k_mutex mutex ;
59
66
struct k_work_delayable phy_monitor_work ;
@@ -90,6 +97,72 @@ static int phy_mc_ksz8081_write(const struct device *dev,
90
97
return 0 ;
91
98
}
92
99
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 ) {
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 ) {
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 ) {
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 ) {
142
+ return ret ;
143
+ }
144
+
145
+ /* Clear interrupt */
146
+ ret = phy_mc_ksz8081_clear_interrupt (data );
147
+ if (ret ) {
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
+
93
166
static int phy_mc_ksz8081_autonegotiate (const struct device * dev )
94
167
{
95
168
const struct mc_ksz8081_config * config = dev -> config ;
@@ -349,7 +422,13 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
349
422
}
350
423
351
424
/* We are going to reconfigure the phy, don't need to monitor until done */
425
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
426
+ if (!config -> interrupt_gpio .port ) {
427
+ k_work_cancel_delayable (& data -> phy_monitor_work );
428
+ }
429
+ #else
352
430
k_work_cancel_delayable (& data -> phy_monitor_work );
431
+ #endif
353
432
354
433
/* DT configurations */
355
434
ret = phy_mc_ksz8081_static_cfg (dev );
@@ -422,6 +501,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
422
501
/* Unlock mutex */
423
502
k_mutex_unlock (& data -> mutex );
424
503
504
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
505
+ if (config -> interrupt_gpio .port ) {
506
+ return ret ;
507
+ }
508
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
509
+
425
510
/* Start monitoring */
426
511
k_work_reschedule (& data -> phy_monitor_work ,
427
512
K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -450,9 +535,21 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
450
535
struct mc_ksz8081_data * data =
451
536
CONTAINER_OF (dwork , struct mc_ksz8081_data , phy_monitor_work );
452
537
const struct device * dev = data -> dev ;
538
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
539
+ const struct mc_ksz8081_config * config = dev -> config ;
540
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
453
541
struct phy_link_state state = {};
454
542
int rc ;
455
543
544
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
545
+ if (config -> interrupt_gpio .port ) {
546
+ rc = phy_mc_ksz8081_clear_interrupt (data );
547
+ if (rc ) {
548
+ return ;
549
+ }
550
+ }
551
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
552
+
456
553
rc = phy_mc_ksz8081_get_link (dev , & state );
457
554
458
555
if (rc == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
@@ -462,6 +559,12 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
462
559
}
463
560
}
464
561
562
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
563
+ if (config -> interrupt_gpio .port ) {
564
+ return ;
565
+ }
566
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
567
+
465
568
/* TODO change this to GPIO interrupt driven */
466
569
k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
467
570
}
@@ -513,6 +616,42 @@ static int phy_mc_ksz8081_init(const struct device *dev)
513
616
k_work_init_delayable (& data -> phy_monitor_work ,
514
617
phy_mc_ksz8081_monitor_work_handler );
515
618
619
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
620
+ do {
621
+ if (!config -> interrupt_gpio .port ) {
622
+ phy_mc_ksz8081_monitor_work_handler (& data -> phy_monitor_work .work );
623
+ break ;
624
+ }
625
+
626
+ /* Configure interrupt pin */
627
+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
628
+ if (ret ) {
629
+ break ;
630
+ }
631
+
632
+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
633
+ BIT (config -> interrupt_gpio .pin ));
634
+ if (ret ) {
635
+ break ;
636
+ }
637
+
638
+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
639
+ if (ret ) {
640
+ break ;
641
+ }
642
+
643
+ ret = phy_mc_ksz8081_config_interrupt (dev );
644
+ if (ret ) {
645
+ break ;
646
+ }
647
+
648
+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio ,
649
+ GPIO_INT_EDGE_TO_ACTIVE );
650
+ } while (0 );
651
+ if (ret ) {
652
+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
653
+ }
654
+ #endif
516
655
return 0 ;
517
656
}
518
657
0 commit comments