@@ -24,11 +24,17 @@ struct mchp_ksz9131_config {
24
24
uint8_t phy_addr ;
25
25
const struct device * const mdio ;
26
26
enum phy_link_speed default_speeds ;
27
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
28
+ const struct gpio_dt_spec interrupt_gpio ;
29
+ #endif
27
30
};
28
31
29
32
struct mchp_ksz9131_data {
30
33
const struct device * dev ;
31
34
phy_callback_t cb ;
35
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
36
+ struct gpio_callback gpio_callback ;
37
+ #endif
32
38
void * cb_data ;
33
39
struct k_work_delayable monitor_work ;
34
40
struct phy_link_state state ;
@@ -189,6 +195,64 @@ static int phy_mchp_ksz9131_link_status(const struct device *dev, bool *link_up)
189
195
return ret ;
190
196
}
191
197
198
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
199
+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
200
+ {
201
+ const struct device * dev = data -> dev ;
202
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
203
+ uint16_t reg_val ;
204
+ int ret ;
205
+
206
+ k_sem_take (& data -> sem , K_FOREVER );
207
+
208
+ /* Read/clear PHY interrupt status register */
209
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
210
+ if (ret < 0 ) {
211
+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
212
+ }
213
+
214
+ k_sem_give (& data -> sem );
215
+
216
+ return ret ;
217
+ }
218
+
219
+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
220
+ {
221
+ struct mchp_ksz9131_data * data = dev -> data ;
222
+ uint16_t reg_val ;
223
+ int ret ;
224
+
225
+ /* Read Interrupt Control/Status register to write back */
226
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
227
+ if (ret < 0 ) {
228
+ return ret ;
229
+ }
230
+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
231
+
232
+ /* Write settings to Interrupt Control/Status register */
233
+ ret = ksz9131_write (dev , PHY_KSZ9131_ICS_REG , reg_val );
234
+ if (ret < 0 ) {
235
+ return ret ;
236
+ }
237
+
238
+ /* Clear interrupt */
239
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
240
+
241
+ return ret ;
242
+ }
243
+
244
+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
245
+ gpio_port_pins_t pins )
246
+ {
247
+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
248
+ int ret = k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
249
+
250
+ if (ret < 0 ) {
251
+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
252
+ }
253
+ }
254
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
255
+
192
256
static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
193
257
{
194
258
const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -247,6 +311,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
247
311
static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds ,
248
312
enum phy_cfg_link_flag flags )
249
313
{
314
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
315
+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
316
+ #endif
250
317
struct mchp_ksz9131_data * const data = dev -> data ;
251
318
uint16_t c1kt ;
252
319
int ret ;
@@ -259,7 +326,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
259
326
k_sem_take (& data -> sem , K_FOREVER );
260
327
261
328
/* We are going to reconfigure the phy, don't need to monitor until done */
329
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
330
+ if (!cfg -> interrupt_gpio .port ) {
331
+ k_work_cancel_delayable (& data -> monitor_work );
332
+ }
333
+ #else
262
334
k_work_cancel_delayable (& data -> monitor_work );
335
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
263
336
264
337
ret = phy_mchp_ksz9131_update_anar (dev , adv_speeds );
265
338
if (ret < 0 ) {
@@ -270,6 +343,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
270
343
done :
271
344
k_sem_give (& data -> sem );
272
345
346
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
347
+ if (cfg -> interrupt_gpio .port ) {
348
+ return ret ;
349
+ }
350
+ #endif
351
+
273
352
/* Start monitoring */
274
353
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
275
354
@@ -359,9 +438,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
359
438
struct mchp_ksz9131_data * const data =
360
439
CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
361
440
const struct device * dev = data -> dev ;
441
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
442
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
443
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
362
444
struct phy_link_state state = {};
363
445
int ret ;
364
446
447
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
448
+ if (cfg -> interrupt_gpio .port ) {
449
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
450
+ if (ret < 0 ) {
451
+ return ;
452
+ }
453
+ }
454
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
455
+
365
456
ret = phy_mchp_ksz9131_get_link (dev , & state );
366
457
if (ret == 0 && (state .speed != data -> state .speed || state .is_up != data -> state .is_up )) {
367
458
memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -370,6 +461,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
370
461
}
371
462
}
372
463
464
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
465
+ if (cfg -> interrupt_gpio .port ) {
466
+ return ;
467
+ }
468
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
469
+
373
470
/* Submit delayed work */
374
471
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
375
472
}
@@ -399,7 +496,36 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
399
496
400
497
k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
401
498
499
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
500
+ if (!cfg -> interrupt_gpio .port ) {
501
+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
502
+ goto done ;
503
+ }
504
+
505
+ /* Configure interrupt pin */
506
+ ret = gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT );
507
+ if (ret < 0 ) {
508
+ goto done ;
509
+ }
510
+
511
+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
512
+ BIT (cfg -> interrupt_gpio .pin ));
513
+
514
+ ret = gpio_add_callback_dt (& cfg -> interrupt_gpio , & data -> gpio_callback );
515
+ if (ret < 0 ) {
516
+ goto done ;
517
+ }
518
+
519
+ ret = phy_mchp_ksz9131_config_interrupt (dev );
520
+ if (ret < 0 ) {
521
+ goto done ;
522
+ }
523
+
524
+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio , GPIO_INT_EDGE_TO_ACTIVE );
525
+ done :
526
+ #else
402
527
phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
528
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
403
529
404
530
if (ret < 0 ) {
405
531
LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -418,11 +544,18 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
418
544
.write = phy_mchp_ksz9131_write ,
419
545
};
420
546
547
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
548
+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
549
+ #else
550
+ #define INTERRUPT_GPIO (n )
551
+ #endif /* interrupt gpio */
552
+
421
553
#define MICROCHIP_KSZ9131_INIT (n ) \
422
554
static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
423
555
.phy_addr = DT_INST_REG_ADDR(n), \
424
556
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
425
557
.default_speeds = PHY_INST_GENERATE_DEFAULT_SPEEDS(n), \
558
+ INTERRUPT_GPIO(n) \
426
559
}; \
427
560
\
428
561
static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments