xref: /linux/drivers/net/dsa/ks8995.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
160cbe71fSLinus Walleij // SPDX-License-Identifier: GPL-2.0
260cbe71fSLinus Walleij /*
360cbe71fSLinus Walleij  * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
460cbe71fSLinus Walleij  *
560cbe71fSLinus Walleij  * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
6*a7fe8b26SLinus Walleij  * Copyright (C) 2025 Linus Walleij <linus.walleij@linaro.org>
760cbe71fSLinus Walleij  *
860cbe71fSLinus Walleij  * This file was based on: drivers/spi/at25.c
960cbe71fSLinus Walleij  *     Copyright (C) 2006 David Brownell
1060cbe71fSLinus Walleij  */
1160cbe71fSLinus Walleij 
1260cbe71fSLinus Walleij #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1360cbe71fSLinus Walleij 
14*a7fe8b26SLinus Walleij #include <linux/bits.h>
15*a7fe8b26SLinus Walleij #include <linux/if_bridge.h>
16*a7fe8b26SLinus Walleij #include <linux/if_vlan.h>
1760cbe71fSLinus Walleij #include <linux/types.h>
1860cbe71fSLinus Walleij #include <linux/kernel.h>
1960cbe71fSLinus Walleij #include <linux/module.h>
2060cbe71fSLinus Walleij #include <linux/delay.h>
2160cbe71fSLinus Walleij #include <linux/device.h>
2260cbe71fSLinus Walleij #include <linux/gpio/consumer.h>
2360cbe71fSLinus Walleij #include <linux/of.h>
2460cbe71fSLinus Walleij #include <linux/spi/spi.h>
25*a7fe8b26SLinus Walleij #include <net/dsa.h>
2660cbe71fSLinus Walleij 
2760cbe71fSLinus Walleij #define DRV_VERSION		"0.1.1"
2860cbe71fSLinus Walleij #define DRV_DESC		"Micrel KS8995 Ethernet switch SPI driver"
2960cbe71fSLinus Walleij 
3060cbe71fSLinus Walleij /* ------------------------------------------------------------------------ */
3160cbe71fSLinus Walleij 
3260cbe71fSLinus Walleij #define KS8995_REG_ID0		0x00    /* Chip ID0 */
3360cbe71fSLinus Walleij #define KS8995_REG_ID1		0x01    /* Chip ID1 */
3460cbe71fSLinus Walleij 
3560cbe71fSLinus Walleij #define KS8995_REG_GC0		0x02    /* Global Control 0 */
36*a7fe8b26SLinus Walleij 
37*a7fe8b26SLinus Walleij #define KS8995_GC0_P5_PHY	BIT(3)	/* Port 5 PHY enabled */
38*a7fe8b26SLinus Walleij 
3960cbe71fSLinus Walleij #define KS8995_REG_GC1		0x03    /* Global Control 1 */
4060cbe71fSLinus Walleij #define KS8995_REG_GC2		0x04    /* Global Control 2 */
41*a7fe8b26SLinus Walleij 
42*a7fe8b26SLinus Walleij #define KS8995_GC2_HUGE		BIT(2)	/* Huge packet support */
43*a7fe8b26SLinus Walleij #define KS8995_GC2_LEGAL	BIT(1)	/* Legal size override */
44*a7fe8b26SLinus Walleij 
4560cbe71fSLinus Walleij #define KS8995_REG_GC3		0x05    /* Global Control 3 */
4660cbe71fSLinus Walleij #define KS8995_REG_GC4		0x06    /* Global Control 4 */
47*a7fe8b26SLinus Walleij 
48*a7fe8b26SLinus Walleij #define KS8995_GC4_10BT		BIT(4)	/* Force switch to 10Mbit */
49*a7fe8b26SLinus Walleij #define KS8995_GC4_MII_FLOW	BIT(5)	/* MII full-duplex flow control enable */
50*a7fe8b26SLinus Walleij #define KS8995_GC4_MII_HD	BIT(6)	/* MII half-duplex mode enable */
51*a7fe8b26SLinus Walleij 
5260cbe71fSLinus Walleij #define KS8995_REG_GC5		0x07    /* Global Control 5 */
5360cbe71fSLinus Walleij #define KS8995_REG_GC6		0x08    /* Global Control 6 */
5460cbe71fSLinus Walleij #define KS8995_REG_GC7		0x09    /* Global Control 7 */
5560cbe71fSLinus Walleij #define KS8995_REG_GC8		0x0a    /* Global Control 8 */
5660cbe71fSLinus Walleij #define KS8995_REG_GC9		0x0b    /* Global Control 9 */
5760cbe71fSLinus Walleij 
58*a7fe8b26SLinus Walleij #define KS8995_GC9_SPECIAL	BIT(0)	/* Special tagging mode (DSA) */
59*a7fe8b26SLinus Walleij 
60*a7fe8b26SLinus Walleij /* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */
61*a7fe8b26SLinus Walleij #define KS8995_REG_PC(p, r)	(0x10 + (0x10 * (p)) + (r)) /* Port Control */
62*a7fe8b26SLinus Walleij #define KS8995_REG_PS(p, r)	(0x1e + (0x10 * (p)) + (r)) /* Port Status */
63*a7fe8b26SLinus Walleij 
64*a7fe8b26SLinus Walleij #define KS8995_REG_PC0		0x00    /* Port Control 0 */
65*a7fe8b26SLinus Walleij #define KS8995_REG_PC1		0x01    /* Port Control 1 */
66*a7fe8b26SLinus Walleij #define KS8995_REG_PC2		0x02    /* Port Control 2 */
67*a7fe8b26SLinus Walleij #define KS8995_REG_PC3		0x03    /* Port Control 3 */
68*a7fe8b26SLinus Walleij #define KS8995_REG_PC4		0x04    /* Port Control 4 */
69*a7fe8b26SLinus Walleij #define KS8995_REG_PC5		0x05    /* Port Control 5 */
70*a7fe8b26SLinus Walleij #define KS8995_REG_PC6		0x06    /* Port Control 6 */
71*a7fe8b26SLinus Walleij #define KS8995_REG_PC7		0x07    /* Port Control 7 */
72*a7fe8b26SLinus Walleij #define KS8995_REG_PC8		0x08    /* Port Control 8 */
73*a7fe8b26SLinus Walleij #define KS8995_REG_PC9		0x09    /* Port Control 9 */
74*a7fe8b26SLinus Walleij #define KS8995_REG_PC10		0x0a    /* Port Control 10 */
75*a7fe8b26SLinus Walleij #define KS8995_REG_PC11		0x0b    /* Port Control 11 */
76*a7fe8b26SLinus Walleij #define KS8995_REG_PC12		0x0c    /* Port Control 12 */
77*a7fe8b26SLinus Walleij #define KS8995_REG_PC13		0x0d    /* Port Control 13 */
78*a7fe8b26SLinus Walleij 
79*a7fe8b26SLinus Walleij #define KS8995_PC0_TAG_INS	BIT(2)	/* Enable tag insertion on port */
80*a7fe8b26SLinus Walleij #define KS8995_PC0_TAG_REM	BIT(1)	/* Enable tag removal on port */
81*a7fe8b26SLinus Walleij #define KS8995_PC0_PRIO_EN	BIT(0)	/* Enable priority handling */
82*a7fe8b26SLinus Walleij 
83*a7fe8b26SLinus Walleij #define KS8995_PC2_TXEN		BIT(2)	/* Enable TX on port */
84*a7fe8b26SLinus Walleij #define KS8995_PC2_RXEN		BIT(1)	/* Enable RX on port */
85*a7fe8b26SLinus Walleij #define KS8995_PC2_LEARN_DIS	BIT(0)	/* Disable learning on port */
86*a7fe8b26SLinus Walleij 
87*a7fe8b26SLinus Walleij #define KS8995_PC13_TXDIS	BIT(6)	/* Disable transmitter */
88*a7fe8b26SLinus Walleij #define KS8995_PC13_PWDN	BIT(3)	/* Power down */
8960cbe71fSLinus Walleij 
9060cbe71fSLinus Walleij #define KS8995_REG_TPC0		0x60    /* TOS Priority Control 0 */
9160cbe71fSLinus Walleij #define KS8995_REG_TPC1		0x61    /* TOS Priority Control 1 */
9260cbe71fSLinus Walleij #define KS8995_REG_TPC2		0x62    /* TOS Priority Control 2 */
9360cbe71fSLinus Walleij #define KS8995_REG_TPC3		0x63    /* TOS Priority Control 3 */
9460cbe71fSLinus Walleij #define KS8995_REG_TPC4		0x64    /* TOS Priority Control 4 */
9560cbe71fSLinus Walleij #define KS8995_REG_TPC5		0x65    /* TOS Priority Control 5 */
9660cbe71fSLinus Walleij #define KS8995_REG_TPC6		0x66    /* TOS Priority Control 6 */
9760cbe71fSLinus Walleij #define KS8995_REG_TPC7		0x67    /* TOS Priority Control 7 */
9860cbe71fSLinus Walleij 
9960cbe71fSLinus Walleij #define KS8995_REG_MAC0		0x68    /* MAC address 0 */
10060cbe71fSLinus Walleij #define KS8995_REG_MAC1		0x69    /* MAC address 1 */
10160cbe71fSLinus Walleij #define KS8995_REG_MAC2		0x6a    /* MAC address 2 */
10260cbe71fSLinus Walleij #define KS8995_REG_MAC3		0x6b    /* MAC address 3 */
10360cbe71fSLinus Walleij #define KS8995_REG_MAC4		0x6c    /* MAC address 4 */
10460cbe71fSLinus Walleij #define KS8995_REG_MAC5		0x6d    /* MAC address 5 */
10560cbe71fSLinus Walleij 
10660cbe71fSLinus Walleij #define KS8995_REG_IAC0		0x6e    /* Indirect Access Control 0 */
10760cbe71fSLinus Walleij #define KS8995_REG_IAC1		0x6f    /* Indirect Access Control 0 */
10860cbe71fSLinus Walleij #define KS8995_REG_IAD7		0x70    /* Indirect Access Data 7 */
10960cbe71fSLinus Walleij #define KS8995_REG_IAD6		0x71    /* Indirect Access Data 6 */
11060cbe71fSLinus Walleij #define KS8995_REG_IAD5		0x72    /* Indirect Access Data 5 */
11160cbe71fSLinus Walleij #define KS8995_REG_IAD4		0x73    /* Indirect Access Data 4 */
11260cbe71fSLinus Walleij #define KS8995_REG_IAD3		0x74    /* Indirect Access Data 3 */
11360cbe71fSLinus Walleij #define KS8995_REG_IAD2		0x75    /* Indirect Access Data 2 */
11460cbe71fSLinus Walleij #define KS8995_REG_IAD1		0x76    /* Indirect Access Data 1 */
11560cbe71fSLinus Walleij #define KS8995_REG_IAD0		0x77    /* Indirect Access Data 0 */
11660cbe71fSLinus Walleij 
11760cbe71fSLinus Walleij #define KSZ8864_REG_ID1		0xfe	/* Chip ID in bit 7 */
11860cbe71fSLinus Walleij 
11960cbe71fSLinus Walleij #define KS8995_REGS_SIZE	0x80
12060cbe71fSLinus Walleij #define KSZ8864_REGS_SIZE	0x100
12160cbe71fSLinus Walleij #define KSZ8795_REGS_SIZE	0x100
12260cbe71fSLinus Walleij 
12360cbe71fSLinus Walleij #define ID1_CHIPID_M		0xf
12460cbe71fSLinus Walleij #define ID1_CHIPID_S		4
12560cbe71fSLinus Walleij #define ID1_REVISION_M		0x7
12660cbe71fSLinus Walleij #define ID1_REVISION_S		1
12760cbe71fSLinus Walleij #define ID1_START_SW		1	/* start the switch */
12860cbe71fSLinus Walleij 
12960cbe71fSLinus Walleij #define FAMILY_KS8995		0x95
13060cbe71fSLinus Walleij #define FAMILY_KSZ8795		0x87
13160cbe71fSLinus Walleij #define CHIPID_M		0
13260cbe71fSLinus Walleij #define KS8995_CHIP_ID		0x00
13360cbe71fSLinus Walleij #define KSZ8864_CHIP_ID		0x01
13460cbe71fSLinus Walleij #define KSZ8795_CHIP_ID		0x09
13560cbe71fSLinus Walleij 
13660cbe71fSLinus Walleij #define KS8995_CMD_WRITE	0x02U
13760cbe71fSLinus Walleij #define KS8995_CMD_READ		0x03U
13860cbe71fSLinus Walleij 
139*a7fe8b26SLinus Walleij #define KS8995_CPU_PORT		4
140*a7fe8b26SLinus Walleij #define KS8995_NUM_PORTS	5 /* 5 ports including the CPU port */
14160cbe71fSLinus Walleij #define KS8995_RESET_DELAY	10 /* usec */
14260cbe71fSLinus Walleij 
14360cbe71fSLinus Walleij enum ks8995_chip_variant {
14460cbe71fSLinus Walleij 	ks8995,
14560cbe71fSLinus Walleij 	ksz8864,
14660cbe71fSLinus Walleij 	ksz8795,
14760cbe71fSLinus Walleij 	max_variant
14860cbe71fSLinus Walleij };
14960cbe71fSLinus Walleij 
15060cbe71fSLinus Walleij struct ks8995_chip_params {
15160cbe71fSLinus Walleij 	char *name;
15260cbe71fSLinus Walleij 	int family_id;
15360cbe71fSLinus Walleij 	int chip_id;
15460cbe71fSLinus Walleij 	int regs_size;
15560cbe71fSLinus Walleij 	int addr_width;
15660cbe71fSLinus Walleij 	int addr_shift;
15760cbe71fSLinus Walleij };
15860cbe71fSLinus Walleij 
15960cbe71fSLinus Walleij static const struct ks8995_chip_params ks8995_chip[] = {
16060cbe71fSLinus Walleij 	[ks8995] = {
16160cbe71fSLinus Walleij 		.name = "KS8995MA",
16260cbe71fSLinus Walleij 		.family_id = FAMILY_KS8995,
16360cbe71fSLinus Walleij 		.chip_id = KS8995_CHIP_ID,
16460cbe71fSLinus Walleij 		.regs_size = KS8995_REGS_SIZE,
16560cbe71fSLinus Walleij 		.addr_width = 8,
16660cbe71fSLinus Walleij 		.addr_shift = 0,
16760cbe71fSLinus Walleij 	},
16860cbe71fSLinus Walleij 	[ksz8864] = {
16960cbe71fSLinus Walleij 		.name = "KSZ8864RMN",
17060cbe71fSLinus Walleij 		.family_id = FAMILY_KS8995,
17160cbe71fSLinus Walleij 		.chip_id = KSZ8864_CHIP_ID,
17260cbe71fSLinus Walleij 		.regs_size = KSZ8864_REGS_SIZE,
17360cbe71fSLinus Walleij 		.addr_width = 8,
17460cbe71fSLinus Walleij 		.addr_shift = 0,
17560cbe71fSLinus Walleij 	},
17660cbe71fSLinus Walleij 	[ksz8795] = {
17760cbe71fSLinus Walleij 		.name = "KSZ8795CLX",
17860cbe71fSLinus Walleij 		.family_id = FAMILY_KSZ8795,
17960cbe71fSLinus Walleij 		.chip_id = KSZ8795_CHIP_ID,
18060cbe71fSLinus Walleij 		.regs_size = KSZ8795_REGS_SIZE,
18160cbe71fSLinus Walleij 		.addr_width = 12,
18260cbe71fSLinus Walleij 		.addr_shift = 1,
18360cbe71fSLinus Walleij 	},
18460cbe71fSLinus Walleij };
18560cbe71fSLinus Walleij 
18660cbe71fSLinus Walleij struct ks8995_switch {
18760cbe71fSLinus Walleij 	struct spi_device	*spi;
188*a7fe8b26SLinus Walleij 	struct device		*dev;
189*a7fe8b26SLinus Walleij 	struct dsa_switch	*ds;
19060cbe71fSLinus Walleij 	struct mutex		lock;
19160cbe71fSLinus Walleij 	struct gpio_desc	*reset_gpio;
19260cbe71fSLinus Walleij 	struct bin_attribute	regs_attr;
19360cbe71fSLinus Walleij 	const struct ks8995_chip_params	*chip;
19460cbe71fSLinus Walleij 	int			revision_id;
195*a7fe8b26SLinus Walleij 	unsigned int max_mtu[KS8995_NUM_PORTS];
19660cbe71fSLinus Walleij };
19760cbe71fSLinus Walleij 
19860cbe71fSLinus Walleij static const struct spi_device_id ks8995_id[] = {
19960cbe71fSLinus Walleij 	{"ks8995", ks8995},
20060cbe71fSLinus Walleij 	{"ksz8864", ksz8864},
20160cbe71fSLinus Walleij 	{"ksz8795", ksz8795},
20260cbe71fSLinus Walleij 	{ }
20360cbe71fSLinus Walleij };
20460cbe71fSLinus Walleij MODULE_DEVICE_TABLE(spi, ks8995_id);
20560cbe71fSLinus Walleij 
20660cbe71fSLinus Walleij static const struct of_device_id ks8895_spi_of_match[] = {
20760cbe71fSLinus Walleij 	{ .compatible = "micrel,ks8995" },
20860cbe71fSLinus Walleij 	{ .compatible = "micrel,ksz8864" },
20960cbe71fSLinus Walleij 	{ .compatible = "micrel,ksz8795" },
21060cbe71fSLinus Walleij 	{ },
21160cbe71fSLinus Walleij };
21260cbe71fSLinus Walleij MODULE_DEVICE_TABLE(of, ks8895_spi_of_match);
21360cbe71fSLinus Walleij 
21460cbe71fSLinus Walleij static inline u8 get_chip_id(u8 val)
21560cbe71fSLinus Walleij {
21660cbe71fSLinus Walleij 	return (val >> ID1_CHIPID_S) & ID1_CHIPID_M;
21760cbe71fSLinus Walleij }
21860cbe71fSLinus Walleij 
21960cbe71fSLinus Walleij static inline u8 get_chip_rev(u8 val)
22060cbe71fSLinus Walleij {
22160cbe71fSLinus Walleij 	return (val >> ID1_REVISION_S) & ID1_REVISION_M;
22260cbe71fSLinus Walleij }
22360cbe71fSLinus Walleij 
22460cbe71fSLinus Walleij /* create_spi_cmd - create a chip specific SPI command header
22560cbe71fSLinus Walleij  * @ks: pointer to switch instance
22660cbe71fSLinus Walleij  * @cmd: SPI command for switch
22760cbe71fSLinus Walleij  * @address: register address for command
22860cbe71fSLinus Walleij  *
22960cbe71fSLinus Walleij  * Different chip families use different bit pattern to address the switches
23060cbe71fSLinus Walleij  * registers:
23160cbe71fSLinus Walleij  *
23260cbe71fSLinus Walleij  * KS8995: 8bit command + 8bit address
23360cbe71fSLinus Walleij  * KSZ8795: 3bit command + 12bit address + 1bit TR (?)
23460cbe71fSLinus Walleij  */
23560cbe71fSLinus Walleij static inline __be16 create_spi_cmd(struct ks8995_switch *ks, int cmd,
23660cbe71fSLinus Walleij 				    unsigned address)
23760cbe71fSLinus Walleij {
23860cbe71fSLinus Walleij 	u16 result = cmd;
23960cbe71fSLinus Walleij 
24060cbe71fSLinus Walleij 	/* make room for address (incl. address shift) */
24160cbe71fSLinus Walleij 	result <<= ks->chip->addr_width + ks->chip->addr_shift;
24260cbe71fSLinus Walleij 	/* add address */
24360cbe71fSLinus Walleij 	result |= address << ks->chip->addr_shift;
24460cbe71fSLinus Walleij 	/* SPI protocol needs big endian */
24560cbe71fSLinus Walleij 	return cpu_to_be16(result);
24660cbe71fSLinus Walleij }
24760cbe71fSLinus Walleij /* ------------------------------------------------------------------------ */
24860cbe71fSLinus Walleij static int ks8995_read(struct ks8995_switch *ks, char *buf,
24960cbe71fSLinus Walleij 		 unsigned offset, size_t count)
25060cbe71fSLinus Walleij {
25160cbe71fSLinus Walleij 	__be16 cmd;
25260cbe71fSLinus Walleij 	struct spi_transfer t[2];
25360cbe71fSLinus Walleij 	struct spi_message m;
25460cbe71fSLinus Walleij 	int err;
25560cbe71fSLinus Walleij 
25660cbe71fSLinus Walleij 	cmd = create_spi_cmd(ks, KS8995_CMD_READ, offset);
25760cbe71fSLinus Walleij 	spi_message_init(&m);
25860cbe71fSLinus Walleij 
25960cbe71fSLinus Walleij 	memset(&t, 0, sizeof(t));
26060cbe71fSLinus Walleij 
26160cbe71fSLinus Walleij 	t[0].tx_buf = &cmd;
26260cbe71fSLinus Walleij 	t[0].len = sizeof(cmd);
26360cbe71fSLinus Walleij 	spi_message_add_tail(&t[0], &m);
26460cbe71fSLinus Walleij 
26560cbe71fSLinus Walleij 	t[1].rx_buf = buf;
26660cbe71fSLinus Walleij 	t[1].len = count;
26760cbe71fSLinus Walleij 	spi_message_add_tail(&t[1], &m);
26860cbe71fSLinus Walleij 
26960cbe71fSLinus Walleij 	mutex_lock(&ks->lock);
27060cbe71fSLinus Walleij 	err = spi_sync(ks->spi, &m);
27160cbe71fSLinus Walleij 	mutex_unlock(&ks->lock);
27260cbe71fSLinus Walleij 
27360cbe71fSLinus Walleij 	return err ? err : count;
27460cbe71fSLinus Walleij }
27560cbe71fSLinus Walleij 
27660cbe71fSLinus Walleij static int ks8995_write(struct ks8995_switch *ks, char *buf,
27760cbe71fSLinus Walleij 		 unsigned offset, size_t count)
27860cbe71fSLinus Walleij {
27960cbe71fSLinus Walleij 	__be16 cmd;
28060cbe71fSLinus Walleij 	struct spi_transfer t[2];
28160cbe71fSLinus Walleij 	struct spi_message m;
28260cbe71fSLinus Walleij 	int err;
28360cbe71fSLinus Walleij 
28460cbe71fSLinus Walleij 	cmd = create_spi_cmd(ks, KS8995_CMD_WRITE, offset);
28560cbe71fSLinus Walleij 	spi_message_init(&m);
28660cbe71fSLinus Walleij 
28760cbe71fSLinus Walleij 	memset(&t, 0, sizeof(t));
28860cbe71fSLinus Walleij 
28960cbe71fSLinus Walleij 	t[0].tx_buf = &cmd;
29060cbe71fSLinus Walleij 	t[0].len = sizeof(cmd);
29160cbe71fSLinus Walleij 	spi_message_add_tail(&t[0], &m);
29260cbe71fSLinus Walleij 
29360cbe71fSLinus Walleij 	t[1].tx_buf = buf;
29460cbe71fSLinus Walleij 	t[1].len = count;
29560cbe71fSLinus Walleij 	spi_message_add_tail(&t[1], &m);
29660cbe71fSLinus Walleij 
29760cbe71fSLinus Walleij 	mutex_lock(&ks->lock);
29860cbe71fSLinus Walleij 	err = spi_sync(ks->spi, &m);
29960cbe71fSLinus Walleij 	mutex_unlock(&ks->lock);
30060cbe71fSLinus Walleij 
30160cbe71fSLinus Walleij 	return err ? err : count;
30260cbe71fSLinus Walleij }
30360cbe71fSLinus Walleij 
30460cbe71fSLinus Walleij static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf)
30560cbe71fSLinus Walleij {
30660cbe71fSLinus Walleij 	return ks8995_read(ks, buf, addr, 1) != 1;
30760cbe71fSLinus Walleij }
30860cbe71fSLinus Walleij 
30960cbe71fSLinus Walleij static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val)
31060cbe71fSLinus Walleij {
31160cbe71fSLinus Walleij 	char buf = val;
31260cbe71fSLinus Walleij 
31360cbe71fSLinus Walleij 	return ks8995_write(ks, &buf, addr, 1) != 1;
31460cbe71fSLinus Walleij }
31560cbe71fSLinus Walleij 
31660cbe71fSLinus Walleij /* ------------------------------------------------------------------------ */
31760cbe71fSLinus Walleij 
31860cbe71fSLinus Walleij static int ks8995_stop(struct ks8995_switch *ks)
31960cbe71fSLinus Walleij {
32060cbe71fSLinus Walleij 	return ks8995_write_reg(ks, KS8995_REG_ID1, 0);
32160cbe71fSLinus Walleij }
32260cbe71fSLinus Walleij 
32360cbe71fSLinus Walleij static int ks8995_start(struct ks8995_switch *ks)
32460cbe71fSLinus Walleij {
32560cbe71fSLinus Walleij 	return ks8995_write_reg(ks, KS8995_REG_ID1, 1);
32660cbe71fSLinus Walleij }
32760cbe71fSLinus Walleij 
32860cbe71fSLinus Walleij static int ks8995_reset(struct ks8995_switch *ks)
32960cbe71fSLinus Walleij {
33060cbe71fSLinus Walleij 	int err;
33160cbe71fSLinus Walleij 
33260cbe71fSLinus Walleij 	err = ks8995_stop(ks);
33360cbe71fSLinus Walleij 	if (err)
33460cbe71fSLinus Walleij 		return err;
33560cbe71fSLinus Walleij 
33660cbe71fSLinus Walleij 	udelay(KS8995_RESET_DELAY);
33760cbe71fSLinus Walleij 
33860cbe71fSLinus Walleij 	return ks8995_start(ks);
33960cbe71fSLinus Walleij }
34060cbe71fSLinus Walleij 
34160cbe71fSLinus Walleij /* ks8995_get_revision - get chip revision
34260cbe71fSLinus Walleij  * @ks: pointer to switch instance
34360cbe71fSLinus Walleij  *
34460cbe71fSLinus Walleij  * Verify chip family and id and get chip revision.
34560cbe71fSLinus Walleij  */
34660cbe71fSLinus Walleij static int ks8995_get_revision(struct ks8995_switch *ks)
34760cbe71fSLinus Walleij {
34860cbe71fSLinus Walleij 	int err;
34960cbe71fSLinus Walleij 	u8 id0, id1, ksz8864_id;
35060cbe71fSLinus Walleij 
35160cbe71fSLinus Walleij 	/* read family id */
35260cbe71fSLinus Walleij 	err = ks8995_read_reg(ks, KS8995_REG_ID0, &id0);
35360cbe71fSLinus Walleij 	if (err) {
35460cbe71fSLinus Walleij 		err = -EIO;
35560cbe71fSLinus Walleij 		goto err_out;
35660cbe71fSLinus Walleij 	}
35760cbe71fSLinus Walleij 
35860cbe71fSLinus Walleij 	/* verify family id */
35960cbe71fSLinus Walleij 	if (id0 != ks->chip->family_id) {
36060cbe71fSLinus Walleij 		dev_err(&ks->spi->dev, "chip family id mismatch: expected 0x%02x but 0x%02x read\n",
36160cbe71fSLinus Walleij 			ks->chip->family_id, id0);
36260cbe71fSLinus Walleij 		err = -ENODEV;
36360cbe71fSLinus Walleij 		goto err_out;
36460cbe71fSLinus Walleij 	}
36560cbe71fSLinus Walleij 
36660cbe71fSLinus Walleij 	switch (ks->chip->family_id) {
36760cbe71fSLinus Walleij 	case FAMILY_KS8995:
36860cbe71fSLinus Walleij 		/* try reading chip id at CHIP ID1 */
36960cbe71fSLinus Walleij 		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
37060cbe71fSLinus Walleij 		if (err) {
37160cbe71fSLinus Walleij 			err = -EIO;
37260cbe71fSLinus Walleij 			goto err_out;
37360cbe71fSLinus Walleij 		}
37460cbe71fSLinus Walleij 
37560cbe71fSLinus Walleij 		/* verify chip id */
37660cbe71fSLinus Walleij 		if ((get_chip_id(id1) == CHIPID_M) &&
37760cbe71fSLinus Walleij 		    (get_chip_id(id1) == ks->chip->chip_id)) {
37860cbe71fSLinus Walleij 			/* KS8995MA */
37960cbe71fSLinus Walleij 			ks->revision_id = get_chip_rev(id1);
38060cbe71fSLinus Walleij 		} else if (get_chip_id(id1) != CHIPID_M) {
38160cbe71fSLinus Walleij 			/* KSZ8864RMN */
38260cbe71fSLinus Walleij 			err = ks8995_read_reg(ks, KS8995_REG_ID1, &ksz8864_id);
38360cbe71fSLinus Walleij 			if (err) {
38460cbe71fSLinus Walleij 				err = -EIO;
38560cbe71fSLinus Walleij 				goto err_out;
38660cbe71fSLinus Walleij 			}
38760cbe71fSLinus Walleij 
38860cbe71fSLinus Walleij 			if ((ksz8864_id & 0x80) &&
38960cbe71fSLinus Walleij 			    (ks->chip->chip_id == KSZ8864_CHIP_ID)) {
39060cbe71fSLinus Walleij 				ks->revision_id = get_chip_rev(id1);
39160cbe71fSLinus Walleij 			}
39260cbe71fSLinus Walleij 
39360cbe71fSLinus Walleij 		} else {
39460cbe71fSLinus Walleij 			dev_err(&ks->spi->dev, "unsupported chip id for KS8995 family: 0x%02x\n",
39560cbe71fSLinus Walleij 				id1);
39660cbe71fSLinus Walleij 			err = -ENODEV;
39760cbe71fSLinus Walleij 		}
39860cbe71fSLinus Walleij 		break;
39960cbe71fSLinus Walleij 	case FAMILY_KSZ8795:
40060cbe71fSLinus Walleij 		/* try reading chip id at CHIP ID1 */
40160cbe71fSLinus Walleij 		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
40260cbe71fSLinus Walleij 		if (err) {
40360cbe71fSLinus Walleij 			err = -EIO;
40460cbe71fSLinus Walleij 			goto err_out;
40560cbe71fSLinus Walleij 		}
40660cbe71fSLinus Walleij 
40760cbe71fSLinus Walleij 		if (get_chip_id(id1) == ks->chip->chip_id) {
40860cbe71fSLinus Walleij 			ks->revision_id = get_chip_rev(id1);
40960cbe71fSLinus Walleij 		} else {
41060cbe71fSLinus Walleij 			dev_err(&ks->spi->dev, "unsupported chip id for KSZ8795 family: 0x%02x\n",
41160cbe71fSLinus Walleij 				id1);
41260cbe71fSLinus Walleij 			err = -ENODEV;
41360cbe71fSLinus Walleij 		}
41460cbe71fSLinus Walleij 		break;
41560cbe71fSLinus Walleij 	default:
41660cbe71fSLinus Walleij 		dev_err(&ks->spi->dev, "unsupported family id: 0x%02x\n", id0);
41760cbe71fSLinus Walleij 		err = -ENODEV;
41860cbe71fSLinus Walleij 		break;
41960cbe71fSLinus Walleij 	}
42060cbe71fSLinus Walleij err_out:
42160cbe71fSLinus Walleij 	return err;
42260cbe71fSLinus Walleij }
42360cbe71fSLinus Walleij 
424*a7fe8b26SLinus Walleij static int ks8995_check_config(struct ks8995_switch *ks)
425*a7fe8b26SLinus Walleij {
426*a7fe8b26SLinus Walleij 	int ret;
427*a7fe8b26SLinus Walleij 	u8 val;
428*a7fe8b26SLinus Walleij 
429*a7fe8b26SLinus Walleij 	ret = ks8995_read_reg(ks, KS8995_REG_GC0, &val);
430*a7fe8b26SLinus Walleij 	if (ret) {
431*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to read KS8995_REG_GC0\n");
432*a7fe8b26SLinus Walleij 		return ret;
433*a7fe8b26SLinus Walleij 	}
434*a7fe8b26SLinus Walleij 
435*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "port 5 PHY %senabled\n",
436*a7fe8b26SLinus Walleij 		(val & KS8995_GC0_P5_PHY) ? "" : "not ");
437*a7fe8b26SLinus Walleij 
438*a7fe8b26SLinus Walleij 	val |= KS8995_GC0_P5_PHY;
439*a7fe8b26SLinus Walleij 	ret = ks8995_write_reg(ks, KS8995_REG_GC0, val);
440*a7fe8b26SLinus Walleij 	if (ret)
441*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to set KS8995_REG_GC0\n");
442*a7fe8b26SLinus Walleij 
443*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "set KS8995_REG_GC0 to 0x%02x\n", val);
444*a7fe8b26SLinus Walleij 
445*a7fe8b26SLinus Walleij 	return 0;
446*a7fe8b26SLinus Walleij }
447*a7fe8b26SLinus Walleij 
448*a7fe8b26SLinus Walleij static void
449*a7fe8b26SLinus Walleij ks8995_mac_config(struct phylink_config *config, unsigned int mode,
450*a7fe8b26SLinus Walleij 		  const struct phylink_link_state *state)
451*a7fe8b26SLinus Walleij {
452*a7fe8b26SLinus Walleij }
453*a7fe8b26SLinus Walleij 
454*a7fe8b26SLinus Walleij static void
455*a7fe8b26SLinus Walleij ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev,
456*a7fe8b26SLinus Walleij 		   unsigned int mode, phy_interface_t interface,
457*a7fe8b26SLinus Walleij 		   int speed, int duplex, bool tx_pause, bool rx_pause)
458*a7fe8b26SLinus Walleij {
459*a7fe8b26SLinus Walleij 	struct dsa_port *dp = dsa_phylink_to_port(config);
460*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = dp->ds->priv;
461*a7fe8b26SLinus Walleij 	int port = dp->index;
462*a7fe8b26SLinus Walleij 	int ret;
463*a7fe8b26SLinus Walleij 	u8 val;
464*a7fe8b26SLinus Walleij 
465*a7fe8b26SLinus Walleij 	/* Allow forcing the mode on the fixed CPU port, no autonegotiation.
466*a7fe8b26SLinus Walleij 	 * We assume autonegotiation works on the PHY-facing ports.
467*a7fe8b26SLinus Walleij 	 */
468*a7fe8b26SLinus Walleij 	if (port != KS8995_CPU_PORT)
469*a7fe8b26SLinus Walleij 		return;
470*a7fe8b26SLinus Walleij 
471*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "MAC link up on CPU port (%d)\n", port);
472*a7fe8b26SLinus Walleij 
473*a7fe8b26SLinus Walleij 	ret = ks8995_read_reg(ks, KS8995_REG_GC4, &val);
474*a7fe8b26SLinus Walleij 	if (ret) {
475*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to read KS8995_REG_GC4\n");
476*a7fe8b26SLinus Walleij 		return;
477*a7fe8b26SLinus Walleij 	}
478*a7fe8b26SLinus Walleij 
479*a7fe8b26SLinus Walleij 	/* Conjure port config */
480*a7fe8b26SLinus Walleij 	switch (speed) {
481*a7fe8b26SLinus Walleij 	case SPEED_10:
482*a7fe8b26SLinus Walleij 		dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n");
483*a7fe8b26SLinus Walleij 		val |= KS8995_GC4_10BT;
484*a7fe8b26SLinus Walleij 		break;
485*a7fe8b26SLinus Walleij 	case SPEED_100:
486*a7fe8b26SLinus Walleij 	default:
487*a7fe8b26SLinus Walleij 		dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n");
488*a7fe8b26SLinus Walleij 		val &= ~KS8995_GC4_10BT;
489*a7fe8b26SLinus Walleij 		break;
490*a7fe8b26SLinus Walleij 	}
491*a7fe8b26SLinus Walleij 
492*a7fe8b26SLinus Walleij 	if (duplex == DUPLEX_HALF) {
493*a7fe8b26SLinus Walleij 		dev_dbg(ks->dev, "set switch MII to half duplex\n");
494*a7fe8b26SLinus Walleij 		val |= KS8995_GC4_MII_HD;
495*a7fe8b26SLinus Walleij 	} else {
496*a7fe8b26SLinus Walleij 		dev_dbg(ks->dev, "set switch MII to full duplex\n");
497*a7fe8b26SLinus Walleij 		val &= ~KS8995_GC4_MII_HD;
498*a7fe8b26SLinus Walleij 	}
499*a7fe8b26SLinus Walleij 
500*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "set KS8995_REG_GC4 to %02x\n", val);
501*a7fe8b26SLinus Walleij 
502*a7fe8b26SLinus Walleij 	/* Enable the CPU port */
503*a7fe8b26SLinus Walleij 	ret = ks8995_write_reg(ks, KS8995_REG_GC4, val);
504*a7fe8b26SLinus Walleij 	if (ret)
505*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to set KS8995_REG_GC4\n");
506*a7fe8b26SLinus Walleij }
507*a7fe8b26SLinus Walleij 
508*a7fe8b26SLinus Walleij static void
509*a7fe8b26SLinus Walleij ks8995_mac_link_down(struct phylink_config *config, unsigned int mode,
510*a7fe8b26SLinus Walleij 		     phy_interface_t interface)
511*a7fe8b26SLinus Walleij {
512*a7fe8b26SLinus Walleij 	struct dsa_port *dp = dsa_phylink_to_port(config);
513*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = dp->ds->priv;
514*a7fe8b26SLinus Walleij 	int port = dp->index;
515*a7fe8b26SLinus Walleij 
516*a7fe8b26SLinus Walleij 	if (port != KS8995_CPU_PORT)
517*a7fe8b26SLinus Walleij 		return;
518*a7fe8b26SLinus Walleij 
519*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "MAC link down on CPU port (%d)\n", port);
520*a7fe8b26SLinus Walleij 
521*a7fe8b26SLinus Walleij 	/* Disable the CPU port */
522*a7fe8b26SLinus Walleij }
523*a7fe8b26SLinus Walleij 
524*a7fe8b26SLinus Walleij static const struct phylink_mac_ops ks8995_phylink_mac_ops = {
525*a7fe8b26SLinus Walleij 	.mac_config = ks8995_mac_config,
526*a7fe8b26SLinus Walleij 	.mac_link_up = ks8995_mac_link_up,
527*a7fe8b26SLinus Walleij 	.mac_link_down = ks8995_mac_link_down,
528*a7fe8b26SLinus Walleij };
529*a7fe8b26SLinus Walleij 
530*a7fe8b26SLinus Walleij static enum
531*a7fe8b26SLinus Walleij dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds,
532*a7fe8b26SLinus Walleij 					 int port,
533*a7fe8b26SLinus Walleij 					 enum dsa_tag_protocol mp)
534*a7fe8b26SLinus Walleij {
535*a7fe8b26SLinus Walleij 	/* This switch actually uses the 6 byte KS8995 protocol */
536*a7fe8b26SLinus Walleij 	return DSA_TAG_PROTO_NONE;
537*a7fe8b26SLinus Walleij }
538*a7fe8b26SLinus Walleij 
539*a7fe8b26SLinus Walleij static int ks8995_setup(struct dsa_switch *ds)
540*a7fe8b26SLinus Walleij {
541*a7fe8b26SLinus Walleij 	return 0;
542*a7fe8b26SLinus Walleij }
543*a7fe8b26SLinus Walleij 
544*a7fe8b26SLinus Walleij static int ks8995_port_enable(struct dsa_switch *ds, int port,
545*a7fe8b26SLinus Walleij 			      struct phy_device *phy)
546*a7fe8b26SLinus Walleij {
547*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = ds->priv;
548*a7fe8b26SLinus Walleij 
549*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "enable port %d\n", port);
550*a7fe8b26SLinus Walleij 
551*a7fe8b26SLinus Walleij 	return 0;
552*a7fe8b26SLinus Walleij }
553*a7fe8b26SLinus Walleij 
554*a7fe8b26SLinus Walleij static void ks8995_port_disable(struct dsa_switch *ds, int port)
555*a7fe8b26SLinus Walleij {
556*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = ds->priv;
557*a7fe8b26SLinus Walleij 
558*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "disable port %d\n", port);
559*a7fe8b26SLinus Walleij }
560*a7fe8b26SLinus Walleij 
561*a7fe8b26SLinus Walleij static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port,
562*a7fe8b26SLinus Walleij 					struct switchdev_brport_flags flags,
563*a7fe8b26SLinus Walleij 					struct netlink_ext_ack *extack)
564*a7fe8b26SLinus Walleij {
565*a7fe8b26SLinus Walleij 	/* We support enabling/disabling learning */
566*a7fe8b26SLinus Walleij 	if (flags.mask & ~(BR_LEARNING))
567*a7fe8b26SLinus Walleij 		return -EINVAL;
568*a7fe8b26SLinus Walleij 
569*a7fe8b26SLinus Walleij 	return 0;
570*a7fe8b26SLinus Walleij }
571*a7fe8b26SLinus Walleij 
572*a7fe8b26SLinus Walleij static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port,
573*a7fe8b26SLinus Walleij 				    struct switchdev_brport_flags flags,
574*a7fe8b26SLinus Walleij 				    struct netlink_ext_ack *extack)
575*a7fe8b26SLinus Walleij {
576*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = ds->priv;
577*a7fe8b26SLinus Walleij 	int ret;
578*a7fe8b26SLinus Walleij 	u8 val;
579*a7fe8b26SLinus Walleij 
580*a7fe8b26SLinus Walleij 	if (flags.mask & BR_LEARNING) {
581*a7fe8b26SLinus Walleij 		ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val);
582*a7fe8b26SLinus Walleij 		if (ret) {
583*a7fe8b26SLinus Walleij 			dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port);
584*a7fe8b26SLinus Walleij 			return ret;
585*a7fe8b26SLinus Walleij 		}
586*a7fe8b26SLinus Walleij 
587*a7fe8b26SLinus Walleij 		if (flags.val & BR_LEARNING)
588*a7fe8b26SLinus Walleij 			val &= ~KS8995_PC2_LEARN_DIS;
589*a7fe8b26SLinus Walleij 		else
590*a7fe8b26SLinus Walleij 			val |= KS8995_PC2_LEARN_DIS;
591*a7fe8b26SLinus Walleij 
592*a7fe8b26SLinus Walleij 		ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);
593*a7fe8b26SLinus Walleij 		if (ret) {
594*a7fe8b26SLinus Walleij 			dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port);
595*a7fe8b26SLinus Walleij 			return ret;
596*a7fe8b26SLinus Walleij 		}
597*a7fe8b26SLinus Walleij 	}
598*a7fe8b26SLinus Walleij 
599*a7fe8b26SLinus Walleij 	return 0;
600*a7fe8b26SLinus Walleij }
601*a7fe8b26SLinus Walleij 
602*a7fe8b26SLinus Walleij static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
603*a7fe8b26SLinus Walleij {
604*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = ds->priv;
605*a7fe8b26SLinus Walleij 	int ret;
606*a7fe8b26SLinus Walleij 	u8 val;
607*a7fe8b26SLinus Walleij 
608*a7fe8b26SLinus Walleij 	ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val);
609*a7fe8b26SLinus Walleij 	if (ret) {
610*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port);
611*a7fe8b26SLinus Walleij 		return;
612*a7fe8b26SLinus Walleij 	}
613*a7fe8b26SLinus Walleij 
614*a7fe8b26SLinus Walleij 	/* Set the bits for the different STP states in accordance with
615*a7fe8b26SLinus Walleij 	 * the datasheet, pages 36-37 "Spanning tree support".
616*a7fe8b26SLinus Walleij 	 */
617*a7fe8b26SLinus Walleij 	switch (state) {
618*a7fe8b26SLinus Walleij 	case BR_STATE_DISABLED:
619*a7fe8b26SLinus Walleij 	case BR_STATE_BLOCKING:
620*a7fe8b26SLinus Walleij 	case BR_STATE_LISTENING:
621*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_TXEN;
622*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_RXEN;
623*a7fe8b26SLinus Walleij 		val |= KS8995_PC2_LEARN_DIS;
624*a7fe8b26SLinus Walleij 		break;
625*a7fe8b26SLinus Walleij 	case BR_STATE_LEARNING:
626*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_TXEN;
627*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_RXEN;
628*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_LEARN_DIS;
629*a7fe8b26SLinus Walleij 		break;
630*a7fe8b26SLinus Walleij 	case BR_STATE_FORWARDING:
631*a7fe8b26SLinus Walleij 		val |= KS8995_PC2_TXEN;
632*a7fe8b26SLinus Walleij 		val |= KS8995_PC2_RXEN;
633*a7fe8b26SLinus Walleij 		val &= ~KS8995_PC2_LEARN_DIS;
634*a7fe8b26SLinus Walleij 		break;
635*a7fe8b26SLinus Walleij 	default:
636*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "unknown bridge state requested\n");
637*a7fe8b26SLinus Walleij 		return;
638*a7fe8b26SLinus Walleij 	}
639*a7fe8b26SLinus Walleij 
640*a7fe8b26SLinus Walleij 	ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);
641*a7fe8b26SLinus Walleij 	if (ret) {
642*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port);
643*a7fe8b26SLinus Walleij 		return;
644*a7fe8b26SLinus Walleij 	}
645*a7fe8b26SLinus Walleij 
646*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "set KS8995_REG_PC2 for port %d to %02x\n", port, val);
647*a7fe8b26SLinus Walleij }
648*a7fe8b26SLinus Walleij 
649*a7fe8b26SLinus Walleij static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port,
650*a7fe8b26SLinus Walleij 				    struct phylink_config *config)
651*a7fe8b26SLinus Walleij {
652*a7fe8b26SLinus Walleij 	unsigned long *interfaces = config->supported_interfaces;
653*a7fe8b26SLinus Walleij 
654*a7fe8b26SLinus Walleij 	if (port == KS8995_CPU_PORT)
655*a7fe8b26SLinus Walleij 		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
656*a7fe8b26SLinus Walleij 
657*a7fe8b26SLinus Walleij 	if (port <= 3) {
658*a7fe8b26SLinus Walleij 		/* Internal PHYs */
659*a7fe8b26SLinus Walleij 		__set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);
660*a7fe8b26SLinus Walleij 		/* phylib default */
661*a7fe8b26SLinus Walleij 		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
662*a7fe8b26SLinus Walleij 	}
663*a7fe8b26SLinus Walleij 
664*a7fe8b26SLinus Walleij 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
665*a7fe8b26SLinus Walleij }
666*a7fe8b26SLinus Walleij 
667*a7fe8b26SLinus Walleij /* Huge packet support up to 1916 byte packages "inclusive"
668*a7fe8b26SLinus Walleij  * which means that tags are included. If the bit is not set
669*a7fe8b26SLinus Walleij  * it is 1536 bytes "inclusive". We present the length without
670*a7fe8b26SLinus Walleij  * tags or ethernet headers. The setting affects all ports.
671*a7fe8b26SLinus Walleij  */
672*a7fe8b26SLinus Walleij static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
673*a7fe8b26SLinus Walleij {
674*a7fe8b26SLinus Walleij 	struct ks8995_switch *ks = ds->priv;
675*a7fe8b26SLinus Walleij 	unsigned int max_mtu;
676*a7fe8b26SLinus Walleij 	int ret;
677*a7fe8b26SLinus Walleij 	u8 val;
678*a7fe8b26SLinus Walleij 	int i;
679*a7fe8b26SLinus Walleij 
680*a7fe8b26SLinus Walleij 	ks->max_mtu[port] = new_mtu;
681*a7fe8b26SLinus Walleij 
682*a7fe8b26SLinus Walleij 	/* Roof out the MTU for the entire switch to the greatest
683*a7fe8b26SLinus Walleij 	 * common denominator: the biggest set for any one port will
684*a7fe8b26SLinus Walleij 	 * be the biggest MTU for the switch.
685*a7fe8b26SLinus Walleij 	 */
686*a7fe8b26SLinus Walleij 	max_mtu = ETH_DATA_LEN;
687*a7fe8b26SLinus Walleij 	for (i = 0; i < KS8995_NUM_PORTS; i++) {
688*a7fe8b26SLinus Walleij 		if (ks->max_mtu[i] > max_mtu)
689*a7fe8b26SLinus Walleij 			max_mtu = ks->max_mtu[i];
690*a7fe8b26SLinus Walleij 	}
691*a7fe8b26SLinus Walleij 
692*a7fe8b26SLinus Walleij 	/* Translate to layer 2 size.
693*a7fe8b26SLinus Walleij 	 * Add ethernet and (possible) VLAN headers, and checksum to the size.
694*a7fe8b26SLinus Walleij 	 * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes.
695*a7fe8b26SLinus Walleij 	 */
696*a7fe8b26SLinus Walleij 	max_mtu += VLAN_ETH_HLEN;
697*a7fe8b26SLinus Walleij 	max_mtu += ETH_FCS_LEN;
698*a7fe8b26SLinus Walleij 
699*a7fe8b26SLinus Walleij 	ret = ks8995_read_reg(ks, KS8995_REG_GC2, &val);
700*a7fe8b26SLinus Walleij 	if (ret) {
701*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to read KS8995_REG_GC2\n");
702*a7fe8b26SLinus Walleij 		return ret;
703*a7fe8b26SLinus Walleij 	}
704*a7fe8b26SLinus Walleij 
705*a7fe8b26SLinus Walleij 	if (max_mtu <= 1522) {
706*a7fe8b26SLinus Walleij 		val &= ~KS8995_GC2_HUGE;
707*a7fe8b26SLinus Walleij 		val &= ~KS8995_GC2_LEGAL;
708*a7fe8b26SLinus Walleij 	} else if (max_mtu > 1522 && max_mtu <= 1536) {
709*a7fe8b26SLinus Walleij 		/* This accepts packets up to 1536 bytes */
710*a7fe8b26SLinus Walleij 		val &= ~KS8995_GC2_HUGE;
711*a7fe8b26SLinus Walleij 		val |= KS8995_GC2_LEGAL;
712*a7fe8b26SLinus Walleij 	} else {
713*a7fe8b26SLinus Walleij 		/* This accepts packets up to 1916 bytes */
714*a7fe8b26SLinus Walleij 		val |= KS8995_GC2_HUGE;
715*a7fe8b26SLinus Walleij 		val |= KS8995_GC2_LEGAL;
716*a7fe8b26SLinus Walleij 	}
717*a7fe8b26SLinus Walleij 
718*a7fe8b26SLinus Walleij 	dev_dbg(ks->dev, "new max MTU %d bytes (inclusive)\n", max_mtu);
719*a7fe8b26SLinus Walleij 
720*a7fe8b26SLinus Walleij 	ret = ks8995_write_reg(ks, KS8995_REG_GC2, val);
721*a7fe8b26SLinus Walleij 	if (ret)
722*a7fe8b26SLinus Walleij 		dev_err(ks->dev, "failed to set KS8995_REG_GC2\n");
723*a7fe8b26SLinus Walleij 
724*a7fe8b26SLinus Walleij 	return ret;
725*a7fe8b26SLinus Walleij }
726*a7fe8b26SLinus Walleij 
727*a7fe8b26SLinus Walleij static int ks8995_get_max_mtu(struct dsa_switch *ds, int port)
728*a7fe8b26SLinus Walleij {
729*a7fe8b26SLinus Walleij 	return 1916 - ETH_HLEN - ETH_FCS_LEN;
730*a7fe8b26SLinus Walleij }
731*a7fe8b26SLinus Walleij 
732*a7fe8b26SLinus Walleij static const struct dsa_switch_ops ks8995_ds_ops = {
733*a7fe8b26SLinus Walleij 	.get_tag_protocol = ks8995_get_tag_protocol,
734*a7fe8b26SLinus Walleij 	.setup = ks8995_setup,
735*a7fe8b26SLinus Walleij 	.port_pre_bridge_flags = ks8995_port_pre_bridge_flags,
736*a7fe8b26SLinus Walleij 	.port_bridge_flags = ks8995_port_bridge_flags,
737*a7fe8b26SLinus Walleij 	.port_enable = ks8995_port_enable,
738*a7fe8b26SLinus Walleij 	.port_disable = ks8995_port_disable,
739*a7fe8b26SLinus Walleij 	.port_stp_state_set = ks8995_port_stp_state_set,
740*a7fe8b26SLinus Walleij 	.port_change_mtu = ks8995_change_mtu,
741*a7fe8b26SLinus Walleij 	.port_max_mtu = ks8995_get_max_mtu,
742*a7fe8b26SLinus Walleij 	.phylink_get_caps = ks8995_phylink_get_caps,
743*a7fe8b26SLinus Walleij };
744*a7fe8b26SLinus Walleij 
74560cbe71fSLinus Walleij /* ------------------------------------------------------------------------ */
74660cbe71fSLinus Walleij static int ks8995_probe(struct spi_device *spi)
74760cbe71fSLinus Walleij {
74860cbe71fSLinus Walleij 	struct ks8995_switch *ks;
74960cbe71fSLinus Walleij 	int err;
75060cbe71fSLinus Walleij 	int variant = spi_get_device_id(spi)->driver_data;
75160cbe71fSLinus Walleij 
75260cbe71fSLinus Walleij 	if (variant >= max_variant) {
75360cbe71fSLinus Walleij 		dev_err(&spi->dev, "bad chip variant %d\n", variant);
75460cbe71fSLinus Walleij 		return -ENODEV;
75560cbe71fSLinus Walleij 	}
75660cbe71fSLinus Walleij 
75760cbe71fSLinus Walleij 	ks = devm_kzalloc(&spi->dev, sizeof(*ks), GFP_KERNEL);
75860cbe71fSLinus Walleij 	if (!ks)
75960cbe71fSLinus Walleij 		return -ENOMEM;
76060cbe71fSLinus Walleij 
76160cbe71fSLinus Walleij 	mutex_init(&ks->lock);
76260cbe71fSLinus Walleij 	ks->spi = spi;
763*a7fe8b26SLinus Walleij 	ks->dev = &spi->dev;
76460cbe71fSLinus Walleij 	ks->chip = &ks8995_chip[variant];
76560cbe71fSLinus Walleij 
76660cbe71fSLinus Walleij 	ks->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
76760cbe71fSLinus Walleij 						 GPIOD_OUT_HIGH);
76860cbe71fSLinus Walleij 	err = PTR_ERR_OR_ZERO(ks->reset_gpio);
76960cbe71fSLinus Walleij 	if (err) {
77060cbe71fSLinus Walleij 		dev_err(&spi->dev,
77160cbe71fSLinus Walleij 			"failed to get reset gpio: %d\n", err);
77260cbe71fSLinus Walleij 		return err;
77360cbe71fSLinus Walleij 	}
77460cbe71fSLinus Walleij 
77560cbe71fSLinus Walleij 	err = gpiod_set_consumer_name(ks->reset_gpio, "switch-reset");
77660cbe71fSLinus Walleij 	if (err)
77760cbe71fSLinus Walleij 		return err;
77860cbe71fSLinus Walleij 
779ccf29cb8SLinus Walleij 	if (ks->reset_gpio) {
780ccf29cb8SLinus Walleij 		/*
781ccf29cb8SLinus Walleij 		 * If a reset line was obtained, wait for 100us after
782ccf29cb8SLinus Walleij 		 * de-asserting RESET before accessing any registers, see
783ccf29cb8SLinus Walleij 		 * the KS8995MA datasheet, page 44.
784ccf29cb8SLinus Walleij 		 */
78560cbe71fSLinus Walleij 		gpiod_set_value_cansleep(ks->reset_gpio, 0);
786ccf29cb8SLinus Walleij 		udelay(100);
787ccf29cb8SLinus Walleij 	}
78860cbe71fSLinus Walleij 
78960cbe71fSLinus Walleij 	spi_set_drvdata(spi, ks);
79060cbe71fSLinus Walleij 
79160cbe71fSLinus Walleij 	spi->mode = SPI_MODE_0;
79260cbe71fSLinus Walleij 	spi->bits_per_word = 8;
79360cbe71fSLinus Walleij 	err = spi_setup(spi);
79460cbe71fSLinus Walleij 	if (err) {
79560cbe71fSLinus Walleij 		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
79660cbe71fSLinus Walleij 		return err;
79760cbe71fSLinus Walleij 	}
79860cbe71fSLinus Walleij 
79960cbe71fSLinus Walleij 	err = ks8995_get_revision(ks);
80060cbe71fSLinus Walleij 	if (err)
80160cbe71fSLinus Walleij 		return err;
80260cbe71fSLinus Walleij 
80360cbe71fSLinus Walleij 	err = ks8995_reset(ks);
80460cbe71fSLinus Walleij 	if (err)
80560cbe71fSLinus Walleij 		return err;
80660cbe71fSLinus Walleij 
80760cbe71fSLinus Walleij 	dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n",
80860cbe71fSLinus Walleij 		 ks->chip->name, ks->chip->chip_id, ks->revision_id);
80960cbe71fSLinus Walleij 
810*a7fe8b26SLinus Walleij 	err = ks8995_check_config(ks);
811*a7fe8b26SLinus Walleij 	if (err)
812*a7fe8b26SLinus Walleij 		return err;
813*a7fe8b26SLinus Walleij 
814*a7fe8b26SLinus Walleij 	ks->ds = devm_kzalloc(&spi->dev, sizeof(*ks->ds), GFP_KERNEL);
815*a7fe8b26SLinus Walleij 	if (!ks->ds)
816*a7fe8b26SLinus Walleij 		return -ENOMEM;
817*a7fe8b26SLinus Walleij 
818*a7fe8b26SLinus Walleij 	ks->ds->dev = &spi->dev;
819*a7fe8b26SLinus Walleij 	ks->ds->num_ports = KS8995_NUM_PORTS;
820*a7fe8b26SLinus Walleij 	ks->ds->ops = &ks8995_ds_ops;
821*a7fe8b26SLinus Walleij 	ks->ds->phylink_mac_ops = &ks8995_phylink_mac_ops;
822*a7fe8b26SLinus Walleij 	ks->ds->priv = ks;
823*a7fe8b26SLinus Walleij 
824*a7fe8b26SLinus Walleij 	err = dsa_register_switch(ks->ds);
825*a7fe8b26SLinus Walleij 	if (err)
826*a7fe8b26SLinus Walleij 		return dev_err_probe(&spi->dev, err,
827*a7fe8b26SLinus Walleij 				     "unable to register DSA switch\n");
828*a7fe8b26SLinus Walleij 
82960cbe71fSLinus Walleij 	return 0;
83060cbe71fSLinus Walleij }
83160cbe71fSLinus Walleij 
83260cbe71fSLinus Walleij static void ks8995_remove(struct spi_device *spi)
83360cbe71fSLinus Walleij {
83460cbe71fSLinus Walleij 	struct ks8995_switch *ks = spi_get_drvdata(spi);
83560cbe71fSLinus Walleij 
836*a7fe8b26SLinus Walleij 	dsa_unregister_switch(ks->ds);
83760cbe71fSLinus Walleij 	/* assert reset */
83860cbe71fSLinus Walleij 	gpiod_set_value_cansleep(ks->reset_gpio, 1);
83960cbe71fSLinus Walleij }
84060cbe71fSLinus Walleij 
84160cbe71fSLinus Walleij /* ------------------------------------------------------------------------ */
84260cbe71fSLinus Walleij static struct spi_driver ks8995_driver = {
84360cbe71fSLinus Walleij 	.driver = {
84460cbe71fSLinus Walleij 		.name	    = "spi-ks8995",
84560cbe71fSLinus Walleij 		.of_match_table = ks8895_spi_of_match,
84660cbe71fSLinus Walleij 	},
84760cbe71fSLinus Walleij 	.probe	  = ks8995_probe,
84860cbe71fSLinus Walleij 	.remove	  = ks8995_remove,
84960cbe71fSLinus Walleij 	.id_table = ks8995_id,
85060cbe71fSLinus Walleij };
85160cbe71fSLinus Walleij 
85260cbe71fSLinus Walleij module_spi_driver(ks8995_driver);
85360cbe71fSLinus Walleij 
85460cbe71fSLinus Walleij MODULE_DESCRIPTION(DRV_DESC);
85560cbe71fSLinus Walleij MODULE_VERSION(DRV_VERSION);
85660cbe71fSLinus Walleij MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
85760cbe71fSLinus Walleij MODULE_LICENSE("GPL v2");
858