@@ -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 ;
@@ -127,6 +133,64 @@ static int phy_check_ksz9131_id(const struct device *dev)
127
133
return ret ;
128
134
}
129
135
136
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
137
+ static int phy_mchp_ksz9131_clear_interrupt (struct mchp_ksz9131_data * data )
138
+ {
139
+ const struct device * dev = data -> dev ;
140
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
141
+ uint16_t reg_val ;
142
+ int ret ;
143
+
144
+ k_sem_take (& data -> sem , K_FOREVER );
145
+
146
+ /* Read/clear PHY interrupt status register */
147
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
148
+ if (ret < 0 ) {
149
+ LOG_ERR ("Error reading phy (%d) interrupt status register" , cfg -> phy_addr );
150
+ }
151
+
152
+ k_sem_give (& data -> sem );
153
+
154
+ return ret ;
155
+ }
156
+
157
+ static int phy_mchp_ksz9131_config_interrupt (const struct device * dev )
158
+ {
159
+ struct mchp_ksz9131_data * data = dev -> data ;
160
+ uint16_t reg_val ;
161
+ int ret ;
162
+
163
+ /* Read Interrupt Control/Status register to write back */
164
+ ret = ksz9131_read (dev , PHY_KSZ9131_ICS_REG , & reg_val );
165
+ if (ret < 0 ) {
166
+ return ret ;
167
+ }
168
+ reg_val |= PHY_KSZ9131_ICS_LINK_UP_IE_MASK | PHY_KSZ9131_ICS_LINK_DOWN_IE_MASK ;
169
+
170
+ /* Write settings to Interrupt Control/Status register */
171
+ ret = ksz9131_write (dev , 27 , reg_val );
172
+ if (ret < 0 ) {
173
+ return ret ;
174
+ }
175
+
176
+ /* Clear interrupt */
177
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
178
+
179
+ return ret ;
180
+ }
181
+
182
+ static void phy_mchp_ksz9131_interrupt_handler (const struct device * port , struct gpio_callback * cb ,
183
+ gpio_port_pins_t pins )
184
+ {
185
+ struct mchp_ksz9131_data * data = CONTAINER_OF (cb , struct mchp_ksz9131_data , gpio_callback );
186
+ int ret = k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
187
+
188
+ if (ret < 0 ) {
189
+ LOG_ERR ("Failed to schedule monitor_work from ISR" );
190
+ }
191
+ }
192
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
193
+
130
194
static int phy_mchp_ksz9131_autonegotiate (const struct device * dev )
131
195
{
132
196
const struct mchp_ksz9131_config * const cfg = dev -> config ;
@@ -186,6 +250,9 @@ static int phy_mchp_ksz9131_autonegotiate(const struct device *dev)
186
250
187
251
static int phy_mchp_ksz9131_cfg_link (const struct device * dev , enum phy_link_speed adv_speeds )
188
252
{
253
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
254
+ const struct mchp_ksz9131_config * const cfg = dev -> config ;
255
+ #endif
189
256
struct mchp_ksz9131_data * const data = dev -> data ;
190
257
uint16_t anar ;
191
258
uint16_t c1kt ;
@@ -194,7 +261,13 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
194
261
k_sem_take (& data -> sem , K_FOREVER );
195
262
196
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
197
269
k_work_cancel_delayable (& data -> monitor_work );
270
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
198
271
199
272
ret = ksz9131_read (dev , MII_ANAR , & anar );
200
273
if (ret < 0 ) {
@@ -256,6 +329,12 @@ static int phy_mchp_ksz9131_cfg_link(const struct device *dev, enum phy_link_spe
256
329
done :
257
330
k_sem_give (& data -> sem );
258
331
332
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
333
+ if (cfg -> interrupt_gpio .port ) {
334
+ return ret ;
335
+ }
336
+ #endif
337
+
259
338
/* Start monitoring */
260
339
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
261
340
@@ -356,9 +435,21 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
356
435
struct mchp_ksz9131_data * const data =
357
436
CONTAINER_OF (dwork , struct mchp_ksz9131_data , monitor_work );
358
437
const struct device * dev = data -> dev ;
438
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
439
+ const struct mchp_ksz9131_config * cfg = dev -> config ;
440
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
359
441
struct phy_link_state state = {};
360
442
int ret ;
361
443
444
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
445
+ if (cfg -> interrupt_gpio .port ) {
446
+ ret = phy_mchp_ksz9131_clear_interrupt (data );
447
+ if (ret < 0 ) {
448
+ return ;
449
+ }
450
+ }
451
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
452
+
362
453
ret = phy_mchp_ksz9131_get_link (dev , & state );
363
454
if (ret == 0 && (state .speed != data -> state .speed || state .is_up != data -> state .is_up )) {
364
455
memcpy (& data -> state , & state , sizeof (struct phy_link_state ));
@@ -367,6 +458,12 @@ static void phy_mchp_ksz9131_monitor_work_handler(struct k_work *work)
367
458
}
368
459
}
369
460
461
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
462
+ if (cfg -> interrupt_gpio .port ) {
463
+ return ;
464
+ }
465
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
466
+
370
467
/* Submit delayed work */
371
468
k_work_reschedule (& data -> monitor_work , K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
372
469
}
@@ -396,7 +493,37 @@ static int phy_mchp_ksz9131_init(const struct device *dev)
396
493
397
494
k_work_init_delayable (& data -> monitor_work , phy_mchp_ksz9131_monitor_work_handler );
398
495
496
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
497
+ if (!cfg -> interrupt_gpio .port ) {
498
+ phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
499
+ goto done ;
500
+ }
501
+
502
+ /* Configure interrupt pin */
503
+ ret = gpio_pin_configure_dt (& cfg -> interrupt_gpio , GPIO_INPUT );
504
+ if (ret < 0 ) {
505
+ goto done ;
506
+ }
507
+
508
+ gpio_init_callback (& data -> gpio_callback , phy_mchp_ksz9131_interrupt_handler ,
509
+ BIT (cfg -> interrupt_gpio .pin ));
510
+
511
+ ret = gpio_add_callback_dt (& cfg -> interrupt_gpio , & data -> gpio_callback );
512
+ if (ret < 0 ) {
513
+ goto done ;
514
+ }
515
+
516
+ ret = phy_mchp_ksz9131_config_interrupt (dev );
517
+ if (ret < 0 ) {
518
+ goto done ;
519
+ }
520
+
521
+ ret = gpio_pin_interrupt_configure_dt (& cfg -> interrupt_gpio ,
522
+ GPIO_INT_EDGE_TO_ACTIVE );
523
+ done :
524
+ #else
399
525
phy_mchp_ksz9131_monitor_work_handler (& data -> monitor_work .work );
526
+ #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */
400
527
401
528
if (ret < 0 ) {
402
529
LOG_ERR ("PHY (%d) init failed" , cfg -> phy_addr );
@@ -413,10 +540,17 @@ static DEVICE_API(ethphy, mchp_ksz9131_phy_api) = {
413
540
.write = phy_mchp_ksz9131_write ,
414
541
};
415
542
543
+ #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (int_gpios )
544
+ #define INTERRUPT_GPIO (n ) .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}),
545
+ #else
546
+ #define INTERRUPT_GPIO (n )
547
+ #endif /* interrupt gpio */
548
+
416
549
#define MICROCHIP_KSZ9131_INIT (n ) \
417
550
static const struct mchp_ksz9131_config mchp_ksz9131_##n##_config = { \
418
551
.phy_addr = DT_INST_REG_ADDR(n), \
419
552
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
553
+ INTERRUPT_GPIO(n) \
420
554
}; \
421
555
\
422
556
static struct mchp_ksz9131_data mchp_ksz9131_##n##_data; \
0 commit comments