@@ -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 < 0 ) {
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 < 0 ) {
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 < 0 ) {
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 < 0 ) {
142
+ return ret ;
143
+ }
144
+
145
+ /* Clear interrupt */
146
+ ret = phy_mc_ksz8081_clear_interrupt (data );
147
+ if (ret < 0 ) {
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 ;
@@ -116,7 +189,6 @@ static int phy_mc_ksz8081_autonegotiate(const struct device *dev)
116
189
return ret ;
117
190
}
118
191
119
- /* TODO change this to GPIO interrupt driven */
120
192
do {
121
193
if (timeout -- == 0 ) {
122
194
LOG_DBG ("PHY (%d) autonegotiation timed out" , config -> addr );
@@ -349,7 +421,13 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
349
421
}
350
422
351
423
/* We are going to reconfigure the phy, don't need to monitor until done */
424
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
425
+ if (!config -> interrupt_gpio .port ) {
426
+ k_work_cancel_delayable (& data -> phy_monitor_work );
427
+ }
428
+ #else
352
429
k_work_cancel_delayable (& data -> phy_monitor_work );
430
+ #endif
353
431
354
432
/* DT configurations */
355
433
ret = phy_mc_ksz8081_static_cfg (dev );
@@ -422,6 +500,12 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev,
422
500
/* Unlock mutex */
423
501
k_mutex_unlock (& data -> mutex );
424
502
503
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
504
+ if (config -> interrupt_gpio .port ) {
505
+ return ret ;
506
+ }
507
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
508
+
425
509
/* Start monitoring */
426
510
k_work_reschedule (& data -> phy_monitor_work ,
427
511
K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
@@ -450,9 +534,21 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
450
534
struct mc_ksz8081_data * data =
451
535
CONTAINER_OF (dwork , struct mc_ksz8081_data , phy_monitor_work );
452
536
const struct device * dev = data -> dev ;
537
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
538
+ const struct mc_ksz8081_config * config = dev -> config ;
539
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
453
540
struct phy_link_state state = {};
454
541
int rc ;
455
542
543
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
544
+ if (config -> interrupt_gpio .port ) {
545
+ rc = phy_mc_ksz8081_clear_interrupt (data );
546
+ if (rc < 0 ) {
547
+ return ;
548
+ }
549
+ }
550
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
551
+
456
552
rc = phy_mc_ksz8081_get_link (dev , & state );
457
553
458
554
if (rc == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
@@ -462,7 +558,12 @@ static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work)
462
558
}
463
559
}
464
560
465
- /* TODO change this to GPIO interrupt driven */
561
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
562
+ if (config -> interrupt_gpio .port ) {
563
+ return ;
564
+ }
565
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
566
+
466
567
k_work_reschedule (& data -> phy_monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
467
568
}
468
569
@@ -513,6 +614,41 @@ static int phy_mc_ksz8081_init(const struct device *dev)
513
614
k_work_init_delayable (& data -> phy_monitor_work ,
514
615
phy_mc_ksz8081_monitor_work_handler );
515
616
617
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
618
+ if (!config -> interrupt_gpio .port ) {
619
+ phy_mc_ksz8081_monitor_work_handler (& data -> phy_monitor_work .work );
620
+ goto done ;
621
+ }
622
+
623
+ /* Configure interrupt pin */
624
+ ret = gpio_pin_configure_dt (& config -> interrupt_gpio , GPIO_INPUT );
625
+ if (ret < 0 ) {
626
+ goto done ;
627
+ }
628
+
629
+ gpio_init_callback (& data -> gpio_callback , phy_mc_ksz8081_interrupt_handler ,
630
+ BIT (config -> interrupt_gpio .pin ));
631
+ if (ret < 0 ) {
632
+ goto done ;
633
+ }
634
+
635
+ ret = gpio_add_callback_dt (& config -> interrupt_gpio , & data -> gpio_callback );
636
+ if (ret < 0 ) {
637
+ goto done ;
638
+ }
639
+
640
+ ret = phy_mc_ksz8081_config_interrupt (dev );
641
+ if (ret < 0 ) {
642
+ goto done ;
643
+ }
644
+
645
+ ret = gpio_pin_interrupt_configure_dt (& config -> interrupt_gpio ,
646
+ GPIO_INT_EDGE_TO_ACTIVE );
647
+ done :
648
+ if (ret < 0 ) {
649
+ LOG_ERR ("PHY (%d) config interrupt failed" , config -> addr );
650
+ }
651
+ #endif
516
652
return 0 ;
517
653
}
518
654
0 commit comments