@@ -28,11 +28,17 @@ LOG_MODULE_REGISTER(phy_mchp_ksz9131, CONFIG_PHY_LOG_LEVEL);
28
28
struct mchp_ksz9131_config {
29
29
uint8_t phy_addr ;
30
30
const struct device * const mdio ;
31
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
32
+ const struct gpio_dt_spec interrupt_gpio ;
33
+ #endif
31
34
};
32
35
33
36
struct mchp_ksz9131_data {
34
37
const struct device * dev ;
35
38
phy_callback_t cb ;
39
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
40
+ struct gpio_callback gpio_callback ;
41
+ #endif
36
42
void * cb_data ;
37
43
struct k_work_delayable monitor_work ;
38
44
struct phy_link_state state ;
@@ -128,6 +134,67 @@ static int phy_check_ksz9131_id(const struct device *dev)
128
134
return ret ;
129
135
}
130
136
137
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
138
+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
139
+ {
140
+ const struct device * dev = data -> dev ;
141
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
142
+ uint16_t reg_val ;
143
+ int ret ;
144
+
145
+ k_sem_take (& data -> sem , K_FOREVER );
146
+
147
+ /* Read/clear PHY interrupt status register */
148
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
149
+ if (ret ) {
150
+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
151
+ }
152
+
153
+ k_sem_give (& data -> sem );
154
+
155
+ return ret ;
156
+ }
157
+
158
+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
159
+ {
160
+ struct mchp_ksz9131_data * data = dev -> data ;
161
+ uint16_t reg_val ;
162
+ int ret ;
163
+
164
+ /* Read Interrupt Control/Status register to write back */
165
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
166
+ if (ret ) {
167
+ return ret ;
168
+ }
169
+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
170
+
171
+ /* Write settings to Interrupt Control/Status register */
172
+ ret = ksz9131_write (dev , 27 , reg_val );
173
+ if (ret ) {
174
+ return ret ;
175
+ }
176
+
177
+ /* Clear interrupt */
178
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
179
+ if (ret ) {
180
+ return ret ;
181
+ }
182
+
183
+ return ret ;
184
+ }
185
+
186
+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
187
+ gpio_port_pins_t pins )
188
+ {
189
+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
190
+ int ret = k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
191
+
192
+ if (ret < 0 ) {
193
+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
194
+ }
195
+ }
196
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
197
+
131
198
static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
132
199
{
133
200
const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -183,6 +250,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
183
250
184
251
static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
185
252
{
253
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
254
+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
255
+ #endif
186
256
struct mchp_ksz9131_data * const data = dev -> data ;
187
257
uint16_t anar ;
188
258
uint16_t c1kt ;
@@ -191,7 +261,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
191
261
k_sem_take (& data -> sem , K_FOREVER );
192
262
193
263
/* We are going to reconfigure the phy, don't need to monitor until done */
264
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
265
+ if (!cfg -> interrupt_gpio .port ) {
266
+ k_work_cancel_delayable (& data -> monitor_work );
267
+ }
268
+ #else
194
269
k_work_cancel_delayable (& data -> monitor_work );
270
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
195
271
196
272
do {
197
273
BREAK_IF_ERR (ret , ksz9131_read (dev , MII_ANAR , & anar ));
@@ -243,6 +319,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
243
319
244
320
k_sem_give (& data -> sem );
245
321
322
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
323
+ if (cfg -> interrupt_gpio .port ) {
324
+ return ret ;
325
+ }
326
+ #endif
327
+
246
328
/* Start monitoring */
247
329
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
248
330
@@ -331,9 +413,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
331
413
struct mchp_ksz9131_data * const data =
332
414
CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
333
415
const struct device * dev = data -> dev ;
416
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
417
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
418
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
334
419
struct phy_link_state state = {};
335
420
int ret ;
336
421
422
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
423
+ if (cfg -> interrupt_gpio .port ) {
424
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
425
+ if (ret ) {
426
+ return ;
427
+ }
428
+ }
429
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
430
+
337
431
ret = phy_mchp_ksz9131_get_link (dev , & state );
338
432
if (ret == 0 && memcmp (& state , & data -> state , sizeof (struct phy_link_state )) != 0 ) {
339
433
memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -342,6 +436,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
342
436
}
343
437
}
344
438
439
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
440
+ if (cfg -> interrupt_gpio .port ) {
441
+ return ;
442
+ }
443
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
444
+
345
445
/* Submit delayed work */
346
446
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
347
447
}
@@ -371,7 +471,30 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
371
471
372
472
k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
373
473
474
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
475
+ do {
476
+ if (!cfg -> interrupt_gpio .port ) {
477
+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
478
+ break ;
479
+ }
480
+
481
+ /* Configure interrupt pin */
482
+ BREAK_IF_ERR (ret , gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT ));
483
+
484
+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
485
+ BIT (cfg -> interrupt_gpio .pin ));
486
+
487
+ BREAK_IF_ERR (ret , gpio_add_callback_dt (& cfg -> interrupt_gpio ,
488
+ & data -> gpio_callback ));
489
+
490
+ BREAK_IF_ERR (ret , phy_mchp_ksz9131_config_interrupt (dev ));
491
+
492
+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio ,
493
+ GPIO_INT_EDGE_TO_ACTIVE );
494
+ } while (0 );
495
+ #else
374
496
phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
497
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
375
498
376
499
if (ret ) {
377
500
LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -388,10 +511,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
388
511
.write = phy_mchp_ksz9131_write ,
389
512
};
390
513
514
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
515
+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
516
+ #else
517
+ #define INTERRUPT_GPIO (n )
518
+ #endif /* interrupt gpio */
519
+
391
520
#define MICROCHIP_KSZ9131_INIT (n ) \
392
521
static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
393
522
.phy_addr = DT_INST_REG_ADDR(n), \
394
523
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
524
+ INTERRUPT_GPIO(n) \
395
525
}; \
396
526
\
397
527
static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments