@@ -21,11 +21,17 @@ LOG_MODULE_REGISTER(phy_mchp_ksz9131, CONFIG_PHY_LOG_LEVEL);
21
21
struct mchp_ksz9131_config {
22
22
uint8_t phy_addr ;
23
23
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
24
27
};
25
28
26
29
struct mchp_ksz9131_data {
27
30
const struct device * dev ;
28
31
phy_callback_t cb ;
32
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
33
+ struct gpio_callback gpio_callback ;
34
+ #endif
29
35
void * cb_data ;
30
36
struct k_work_delayable monitor_work ;
31
37
struct phy_link_state state ;
@@ -125,6 +131,64 @@ static int phy_check_ksz9131_id(const struct device *dev)
125
131
return ret ;
126
132
}
127
133
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
+
128
192
static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
129
193
{
130
194
const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -184,6 +248,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
184
248
185
249
static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
186
250
{
251
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
252
+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
253
+ #endif
187
254
struct mchp_ksz9131_data * const data = dev -> data ;
188
255
uint16_t anar ;
189
256
uint16_t c1kt ;
@@ -192,7 +259,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
192
259
k_sem_take (& data -> sem , K_FOREVER );
193
260
194
261
/* 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
195
267
k_work_cancel_delayable (& data -> monitor_work );
268
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
196
269
197
270
ret = ksz9131_read (dev , MII_ANAR , & anar );
198
271
if (ret < 0 ) {
@@ -254,6 +327,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
254
327
done :
255
328
k_sem_give (& data -> sem );
256
329
330
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
331
+ if (cfg -> interrupt_gpio .port ) {
332
+ return ret ;
333
+ }
334
+ #endif
335
+
257
336
/* Start monitoring */
258
337
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
259
338
@@ -352,9 +431,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
352
431
struct mchp_ksz9131_data * const data =
353
432
CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
354
433
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) */
355
437
struct phy_link_state state = {};
356
438
int ret ;
357
439
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
+
358
449
ret = phy_mchp_ksz9131_get_link (dev , & state );
359
450
if (ret == 0 && (state .speed != data -> state .speed || state .is_up != data -> state .is_up )) {
360
451
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)
363
454
}
364
455
}
365
456
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
+
366
463
/* Submit delayed work */
367
464
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
368
465
}
@@ -392,7 +489,37 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
392
489
393
490
k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
394
491
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
395
521
phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
522
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
396
523
397
524
if (ret < 0 ) {
398
525
LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -409,10 +536,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
409
536
.write = phy_mchp_ksz9131_write ,
410
537
};
411
538
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
+
412
545
#define MICROCHIP_KSZ9131_INIT (n ) \
413
546
static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
414
547
.phy_addr = DT_INST_REG_ADDR(n), \
415
548
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
549
+ INTERRUPT_GPIO(n) \
416
550
}; \
417
551
\
418
552
static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments