1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
|
// SPDX-License-Identifier: GPL-2.0
/*
* SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
*
* Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
* Copyright (C) 2025 Linus Walleij <linus.walleij@linaro.org>
*
* This file was based on: drivers/spi/at25.c
* Copyright (C) 2006 David Brownell
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bits.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <net/dsa.h>
#define DRV_VERSION "0.1.1"
#define DRV_DESC "Micrel KS8995 Ethernet switch SPI driver"
/* ------------------------------------------------------------------------ */
#define KS8995_REG_ID0 0x00 /* Chip ID0 */
#define KS8995_REG_ID1 0x01 /* Chip ID1 */
#define KS8995_REG_GC0 0x02 /* Global Control 0 */
#define KS8995_GC0_P5_PHY BIT(3) /* Port 5 PHY enabled */
#define KS8995_REG_GC1 0x03 /* Global Control 1 */
#define KS8995_REG_GC2 0x04 /* Global Control 2 */
#define KS8995_GC2_HUGE BIT(2) /* Huge packet support */
#define KS8995_GC2_LEGAL BIT(1) /* Legal size override */
#define KS8995_REG_GC3 0x05 /* Global Control 3 */
#define KS8995_REG_GC4 0x06 /* Global Control 4 */
#define KS8995_GC4_10BT BIT(4) /* Force switch to 10Mbit */
#define KS8995_GC4_MII_FLOW BIT(5) /* MII full-duplex flow control enable */
#define KS8995_GC4_MII_HD BIT(6) /* MII half-duplex mode enable */
#define KS8995_REG_GC5 0x07 /* Global Control 5 */
#define KS8995_REG_GC6 0x08 /* Global Control 6 */
#define KS8995_REG_GC7 0x09 /* Global Control 7 */
#define KS8995_REG_GC8 0x0a /* Global Control 8 */
#define KS8995_REG_GC9 0x0b /* Global Control 9 */
#define KS8995_GC9_SPECIAL BIT(0) /* Special tagging mode (DSA) */
/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */
#define KS8995_REG_PC(p, r) (0x10 + (0x10 * (p)) + (r)) /* Port Control */
#define KS8995_REG_PS(p, r) (0x1e + (0x10 * (p)) + (r)) /* Port Status */
#define KS8995_REG_PC0 0x00 /* Port Control 0 */
#define KS8995_REG_PC1 0x01 /* Port Control 1 */
#define KS8995_REG_PC2 0x02 /* Port Control 2 */
#define KS8995_REG_PC3 0x03 /* Port Control 3 */
#define KS8995_REG_PC4 0x04 /* Port Control 4 */
#define KS8995_REG_PC5 0x05 /* Port Control 5 */
#define KS8995_REG_PC6 0x06 /* Port Control 6 */
#define KS8995_REG_PC7 0x07 /* Port Control 7 */
#define KS8995_REG_PC8 0x08 /* Port Control 8 */
#define KS8995_REG_PC9 0x09 /* Port Control 9 */
#define KS8995_REG_PC10 0x0a /* Port Control 10 */
#define KS8995_REG_PC11 0x0b /* Port Control 11 */
#define KS8995_REG_PC12 0x0c /* Port Control 12 */
#define KS8995_REG_PC13 0x0d /* Port Control 13 */
#define KS8995_PC0_TAG_INS BIT(2) /* Enable tag insertion on port */
#define KS8995_PC0_TAG_REM BIT(1) /* Enable tag removal on port */
#define KS8995_PC0_PRIO_EN BIT(0) /* Enable priority handling */
#define KS8995_PC2_TXEN BIT(2) /* Enable TX on port */
#define KS8995_PC2_RXEN BIT(1) /* Enable RX on port */
#define KS8995_PC2_LEARN_DIS BIT(0) /* Disable learning on port */
#define KS8995_PC13_TXDIS BIT(6) /* Disable transmitter */
#define KS8995_PC13_PWDN BIT(3) /* Power down */
#define KS8995_REG_TPC0 0x60 /* TOS Priority Control 0 */
#define KS8995_REG_TPC1 0x61 /* TOS Priority Control 1 */
#define KS8995_REG_TPC2 0x62 /* TOS Priority Control 2 */
#define KS8995_REG_TPC3 0x63 /* TOS Priority Control 3 */
#define KS8995_REG_TPC4 0x64 /* TOS Priority Control 4 */
#define KS8995_REG_TPC5 0x65 /* TOS Priority Control 5 */
#define KS8995_REG_TPC6 0x66 /* TOS Priority Control 6 */
#define KS8995_REG_TPC7 0x67 /* TOS Priority Control 7 */
#define KS8995_REG_MAC0 0x68 /* MAC address 0 */
#define KS8995_REG_MAC1 0x69 /* MAC address 1 */
#define KS8995_REG_MAC2 0x6a /* MAC address 2 */
#define KS8995_REG_MAC3 0x6b /* MAC address 3 */
#define KS8995_REG_MAC4 0x6c /* MAC address 4 */
#define KS8995_REG_MAC5 0x6d /* MAC address 5 */
#define KS8995_REG_IAC0 0x6e /* Indirect Access Control 0 */
#define KS8995_REG_IAC1 0x6f /* Indirect Access Control 0 */
#define KS8995_REG_IAD7 0x70 /* Indirect Access Data 7 */
#define KS8995_REG_IAD6 0x71 /* Indirect Access Data 6 */
#define KS8995_REG_IAD5 0x72 /* Indirect Access Data 5 */
#define KS8995_REG_IAD4 0x73 /* Indirect Access Data 4 */
#define KS8995_REG_IAD3 0x74 /* Indirect Access Data 3 */
#define KS8995_REG_IAD2 0x75 /* Indirect Access Data 2 */
#define KS8995_REG_IAD1 0x76 /* Indirect Access Data 1 */
#define KS8995_REG_IAD0 0x77 /* Indirect Access Data 0 */
#define KSZ8864_REG_ID1 0xfe /* Chip ID in bit 7 */
#define KS8995_REGS_SIZE 0x80
#define KSZ8864_REGS_SIZE 0x100
#define KSZ8795_REGS_SIZE 0x100
#define ID1_CHIPID_M 0xf
#define ID1_CHIPID_S 4
#define ID1_REVISION_M 0x7
#define ID1_REVISION_S 1
#define ID1_START_SW 1 /* start the switch */
#define FAMILY_KS8995 0x95
#define FAMILY_KSZ8795 0x87
#define CHIPID_M 0
#define KS8995_CHIP_ID 0x00
#define KSZ8864_CHIP_ID 0x01
#define KSZ8795_CHIP_ID 0x09
#define KS8995_CMD_WRITE 0x02U
#define KS8995_CMD_READ 0x03U
#define KS8995_CPU_PORT 4
#define KS8995_NUM_PORTS 5 /* 5 ports including the CPU port */
#define KS8995_RESET_DELAY 10 /* usec */
enum ks8995_chip_variant {
ks8995,
ksz8864,
ksz8795,
max_variant
};
struct ks8995_chip_params {
char *name;
int family_id;
int chip_id;
int regs_size;
int addr_width;
int addr_shift;
};
static const struct ks8995_chip_params ks8995_chip[] = {
[ks8995] = {
.name = "KS8995MA",
.family_id = FAMILY_KS8995,
.chip_id = KS8995_CHIP_ID,
.regs_size = KS8995_REGS_SIZE,
.addr_width = 8,
.addr_shift = 0,
},
[ksz8864] = {
.name = "KSZ8864RMN",
.family_id = FAMILY_KS8995,
.chip_id = KSZ8864_CHIP_ID,
.regs_size = KSZ8864_REGS_SIZE,
.addr_width = 8,
.addr_shift = 0,
},
[ksz8795] = {
.name = "KSZ8795CLX",
.family_id = FAMILY_KSZ8795,
.chip_id = KSZ8795_CHIP_ID,
.regs_size = KSZ8795_REGS_SIZE,
.addr_width = 12,
.addr_shift = 1,
},
};
struct ks8995_switch {
struct spi_device *spi;
struct device *dev;
struct dsa_switch *ds;
struct mutex lock;
struct gpio_desc *reset_gpio;
struct bin_attribute regs_attr;
const struct ks8995_chip_params *chip;
int revision_id;
unsigned int max_mtu[KS8995_NUM_PORTS];
};
static const struct spi_device_id ks8995_id[] = {
{"ks8995", ks8995},
{"ksz8864", ksz8864},
{"ksz8795", ksz8795},
{ }
};
MODULE_DEVICE_TABLE(spi, ks8995_id);
static const struct of_device_id ks8995_spi_of_match[] = {
{ .compatible = "micrel,ks8995" },
{ .compatible = "micrel,ksz8864" },
{ .compatible = "micrel,ksz8795" },
{ },
};
MODULE_DEVICE_TABLE(of, ks8995_spi_of_match);
static inline u8 get_chip_id(u8 val)
{
return (val >> ID1_CHIPID_S) & ID1_CHIPID_M;
}
static inline u8 get_chip_rev(u8 val)
{
return (val >> ID1_REVISION_S) & ID1_REVISION_M;
}
/* create_spi_cmd - create a chip specific SPI command header
* @ks: pointer to switch instance
* @cmd: SPI command for switch
* @address: register address for command
*
* Different chip families use different bit pattern to address the switches
* registers:
*
* KS8995: 8bit command + 8bit address
* KSZ8795: 3bit command + 12bit address + 1bit TR (?)
*/
static inline __be16 create_spi_cmd(struct ks8995_switch *ks, int cmd,
unsigned address)
{
u16 result = cmd;
/* make room for address (incl. address shift) */
result <<= ks->chip->addr_width + ks->chip->addr_shift;
/* add address */
result |= address << ks->chip->addr_shift;
/* SPI protocol needs big endian */
return cpu_to_be16(result);
}
/* ------------------------------------------------------------------------ */
static int ks8995_read(struct ks8995_switch *ks, char *buf,
unsigned offset
|