@@ -31,6 +31,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
31
31
#define PHY_MC_KSZ8081_OMSO_RMII_OVERRIDE_MASK BIT(1)
32
32
#define PHY_MC_KSZ8081_OMSO_MII_OVERRIDE_MASK BIT(0)
33
33
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
+
34
38
#define PHY_MC_KSZ8081_CTRL2_REG 0x1F
35
39
#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7)
36
40
@@ -57,6 +61,9 @@ struct mc_ksz8081_data {
57
61
const struct device * dev ;
58
62
struct phy_link_state state ;
59
63
phy_callback_t cb ;
64
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
65
+ struct gpio_callback gpio_callback ;
66
+ #endif
60
67
void * cb_data ;
61
68
struct k_mutex mutex ;
62
69
struct k_work_delayable phy_monitor_work ;
@@ -93,6 +100,72 @@ static int phy_mc_ksz8081_write(const struct device *dev,
93
100
return 0 ;
94
101
}
95
102
103
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
104
+ static int phy_mc_ksz8081_clear_interrupt (struct mc_ksz8081_data * data )
105
+ {
106
+ const struct device * dev = data -> dev ;
107
+ const struct mc_ksz8081_config * config = dev -> config ;
108
+ uint32_t ics ;
109
+ int ret ;
110
+
111
+ /* Lock mutex */
112
+ ret = k_mutex_lock (& data -> mutex , K_FOREVER );
113
+ if (ret < 0 ) {
114
+ LOG_ERR ("PHY mutex lock error" );
115
+ return ret ;
116
+ }
117
+
118
+ /* Read/clear PHY interrupt status register */
119
+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
120
+ if (ret < 0 ) {
121
+ LOG_ERR ("Error reading phy (%d) interrupt status register" , config -> addr );
122
+ }
123
+
124
+ /* Unlock mutex */
125
+ k_mutex_unlock (& data -> mutex );
126
+ return ret ;
127
+ }
128
+
129
+ static int phy_mc_ksz8081_config_interrupt (const struct device * dev )
130
+ {
131
+ struct mc_ksz8081_data * data = dev -> data ;
132
+ uint32_t ics ;
133
+ int ret ;
134
+
135
+ /* Read Interrupt Control/Status register to write back */
136
+ ret = phy_mc_ksz8081_read (dev , PHY_MC_KSZ8081_ICS_REG , & ics );
137
+ if (ret < 0 ) {
138
+ return ret ;
139
+ }
140
+ ics |= PHY_MC_KSZ8081_ICS_LINK_UP_IE_MASK | PHY_MC_KSZ8081_ICS_LINK_DOWN_IE_MASK ;
141
+
142
+ /* Write settings to Interrupt Control/Status register */
143
+ ret = phy_mc_ksz8081_write (dev , PHY_MC_KSZ8081_ICS_REG , ics );
144
+ if (ret < 0 ) {
145
+ return ret ;
146
+ }
147
+
148
+ /* Clear interrupt */
149
+ ret = phy_mc_ksz8081_clear_interrupt (data );
150
+ if (ret < 0 ) {
151
+ return ret ;
152
+ }
153
+
154
+ return ret ;
155
+ }
156
+
157
+ static void phy_mc_ksz8081_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
158
+ gpio_port_pins_t pins )
159
+ {
160
+ struct mc_ksz8081_data * data = CONTAINER_OF (cb , struct mc_ksz8081_data , gpio_callback );
161
+ int ret = k_work_reschedule (& data -> phy_monitor_work , K_NO_WAIT );
162
+
163
+ if (ret < 0 ) {
164
+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
165
+ }
166
+ }
167
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
168
+
96
169
static int phy_mc_ksz8081_autonegotiate (const struct device * dev )
97
170
{
98
171
const struct mc_ksz8081_config * config = dev -> config ;
@@ -119,7 +192,6 @@ static int phy_mc_ksz8081_autonegotiate(const struct device *dev)
119
192
return ret ;
120
193
}
121
194
122
- /* TODO change this to GPIO interrupt driven */
123
195
do {
124
196
if (timeout -- == 0 ) {
125
197
LOG_DBG ("PHY (%d) autonegotiation timed out" , config -> addr );
@@ -356,7 +428,13 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, enum phy_link_speed
356
428
}
357
429
358
430
/* We are going to reconfigure the phy, don't need to monitor until done */
431
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
432
+ if (!config -> interrupt_gpio .port ) {
433
+ k_work_cancel_delayable (& data -> phy_monitor_work );
434
+ }
435
+ #else
359
436
k_work_cancel_delayable (& data -> phy_monitor_work );
437
+ #endif
360
438
361
439
/* DT configurations */
362
440
ret = phy_mc_ksz8081_static_cfg (dev );
@@ -399,6 +477,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, enum phy_link_speed
399
477
/* Unlock mutex */
400
478
k_mutex_unlock (& data -> mutex );
401
479
480
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
481
+ if (config -> interrupt_gpio .port ) {
482
+ return ret ;
483
+ }
484
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
485
+
402
486
/* Start monitoring */
403
487
k_work_reschedule (& data -> phy_monitor_work ,
404
488
K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -427,9 +511,21 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
427
511
struct mc_ksz8081_data * data =
428
512
CONTAINER_OF (dwork , struct mc_ksz8081_data , phy_monitor_work );
429
513
const struct device * dev = data -> dev ;
514
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
515
+ const struct mc_ksz8081_config * config = dev -> config ;
516
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
430
517
struct phy_link_state state = {};
431
518
int rc ;
432
519
520
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
521
+ if (config -> interrupt_gpio .port ) {
522
+ rc = phy_mc_ksz8081_clear_interrupt (data );
523
+ if (rc < 0 ) {
524
+ return ;
525
+ }
526
+ }
527
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
528
+
433
529
rc = phy_mc_ksz8081_get_link (dev , & state );
434
530
435
531
if (rc == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
@@ -439,7 +535,12 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
439
535
}
440
536
}
441
537
442
- /* TODO change this to GPIO interrupt driven */
538
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
539
+ if (config -> interrupt_gpio .port ) {
540
+ return ;
541
+ }
542
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
543
+
443
544
k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
444
545
}
445
546
@@ -490,6 +591,38 @@ static int phy_mc_ksz8081_init(const struct device *dev)
490
591
k_work_init_delayable (& data -> phy_monitor_work ,
491
592
phy_mc_ksz8081_monitor_work_handler );
492
593
594
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
595
+ if (!config -> interrupt_gpio .port ) {
596
+ goto done ;
597
+ }
598
+
599
+ /* Configure interrupt pin */
600
+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
601
+ if (ret < 0 ) {
602
+ goto done ;
603
+ }
604
+
605
+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
606
+ BIT (config -> interrupt_gpio .pin ));
607
+
608
+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
609
+ if (ret < 0 ) {
610
+ goto done ;
611
+ }
612
+
613
+ ret = phy_mc_ksz8081_config_interrupt (dev );
614
+ if (ret < 0 ) {
615
+ goto done ;
616
+ }
617
+
618
+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio , GPIO_INT_EDGE_TO_ACTIVE );
619
+ done :
620
+ if (ret < 0 ) {
621
+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
622
+ return ret ;
623
+ }
624
+ #endif
625
+
493
626
/* Advertise default speeds */
494
627
phy_mc_ksz8081_cfg_link (dev , config -> default_speeds , 0 );
495
628
0 commit comments