[PATCH] net: ksz8864: Add support for KSZ87xx switches

Trent Piepho trent.piepho at igorinstitute.com
Mon Oct 11 11:42:13 PDT 2021


This adds support for the ksz8765, ksz8794, and ksz8795 switches.

IDs for OF bindings are added.  The base chip type is "ksz8795", the
same as the Linux driver, for the ksz87xx switches added here.
"ksz8864rmn" is used for the existing switch.

The registers for these switch chips, as least as far as this simple
driver is concerned, are the same as the existing ksz8864 support.

The difference in the ksz87xx chips is the format of the command and
address bytes:

C = command
A = address (used bits)
a = address (unused bits)
p = turn around padding bit

ksz8864: 00000CCC  AAAAAAAA
ksz8795: CCCaaaaA  AAAAAAAp

CCC and AAAAAAAA are the same, it's just where they are that changes.
This is parameterized in the read/write reg functions by using two
values for the address width and pad width.

Signed-off-by: Trent Piepho <trent.piepho at igorinstitute.com>
---
 drivers/net/ksz8864rmn.c | 66 ++++++++++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ksz8864rmn.c b/drivers/net/ksz8864rmn.c
index 85063ff0d..72ab86579 100644
--- a/drivers/net/ksz8864rmn.c
+++ b/drivers/net/ksz8864rmn.c
@@ -31,48 +31,55 @@
 #define CMD_WRITE		0x02
 #define CMD_READ		0x03
 
+enum ksz_type {
+	unknown,
+	ksz87,
+	ksz88
+};
+
 struct micrel_switch_priv {
 	struct cdev             cdev;
 	struct spi_device       *spi;
 	unsigned int		p_enable;
+	unsigned int		addr_width;
+	unsigned int		pad;
 };
 
-static int micrel_switch_read_reg(struct spi_device *spi, uint8_t reg)
+static int micrel_switch_read_reg(const struct micrel_switch_priv *priv, uint8_t reg)
 {
 	uint8_t tx[2];
 	uint8_t rx[1];
 	int ret;
 
-	tx[0] = CMD_READ;
-	tx[1] = reg;
+	tx[0] = CMD_READ << (priv->addr_width + priv->pad - 8) | reg >> (8 - priv->pad);
+	tx[1] = reg << priv->pad;
 
-	ret = spi_write_then_read(spi, tx, 2, rx, 1);
+	ret = spi_write_then_read(priv->spi, tx, 2, rx, 1);
 	if (ret < 0)
 		return ret;
 
 	return rx[0];
 }
 
-static void micrel_switch_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val)
+static void micrel_switch_write_reg(const struct micrel_switch_priv *priv, uint8_t reg, uint8_t val)
 {
 	uint8_t tx[3];
 
-	tx[0] = CMD_WRITE;
-	tx[1] = reg;
+	tx[0] = CMD_WRITE << (priv->addr_width + priv->pad - 8) | reg >> (8 - priv->pad);
+	tx[1] = reg << priv->pad;
 	tx[2] = val;
 
-	spi_write_then_read(spi, tx, 3, NULL, 0);
+	spi_write_then_read(priv->spi, tx, 3, NULL, 0);
 }
 
 static int micrel_switch_enable_set(struct param_d *param, void *_priv)
 {
 	struct micrel_switch_priv *priv = _priv;
-	struct spi_device *spi = priv->spi;
 
 	if (priv->p_enable)
-		micrel_switch_write_reg(spi, REG_ID1, 1);
+		micrel_switch_write_reg(priv, REG_ID1, 1);
 	else
-		micrel_switch_write_reg(spi, REG_ID1, 0);
+		micrel_switch_write_reg(priv, REG_ID1, 0);
 
 	return 0;
 }
@@ -84,7 +91,7 @@ static ssize_t micel_switch_read(struct cdev *cdev, void *_buf, size_t count, lo
 	struct micrel_switch_priv *priv = cdev->priv;
 
 	for (i = 0; i < count; i++) {
-		ret = micrel_switch_read_reg(priv->spi, offset);
+		ret = micrel_switch_read_reg(priv, offset);
 		if (ret < 0)
 			return ret;
 		*buf = ret;
@@ -102,7 +109,7 @@ static ssize_t micel_switch_write(struct cdev *cdev, const void *_buf, size_t co
 	struct micrel_switch_priv *priv = cdev->priv;
 
 	for (i = 0; i < count; i++) {
-		micrel_switch_write_reg(priv->spi, offset, *buf);
+		micrel_switch_write_reg(priv, offset, *buf);
 		buf++;
 		offset++;
 	}
@@ -119,6 +126,11 @@ static int micrel_switch_probe(struct device_d *dev)
 {
 	struct micrel_switch_priv *priv;
 	int ret = 0;
+	enum ksz_type kind = (enum ksz_type)device_get_match_data(dev);
+	uint8_t id;
+
+	if (kind == unknown)
+		return -ENODEV;
 
 	priv = xzalloc(sizeof(*priv));
 
@@ -128,12 +140,27 @@ static int micrel_switch_probe(struct device_d *dev)
 	priv->spi->mode = SPI_MODE_0;
 	priv->spi->bits_per_word = 8;
 
-	ret = micrel_switch_read_reg(priv->spi, REG_ID0);
+	switch (kind) {
+	case ksz87:
+		priv->addr_width = 12;
+		priv->pad = 1;
+		id = 0x87;
+		break;
+	case ksz88:
+		priv->addr_width = 8;
+		priv->pad = 0;
+		id = 0x95;
+		break;
+	default:
+		return -ENODEV;
+	};
+
+	ret = micrel_switch_read_reg(priv, REG_ID0);
 	if (ret < 0) {
 		dev_err(&priv->spi->dev, "failed to read device id\n");
 		return ret;
 	}
-	if (ret != 0x95) {
+	if (ret != id) {
 		dev_err(&priv->spi->dev, "unknown device id: %02x\n", ret);
 		return -ENODEV;
 	}
@@ -149,13 +176,20 @@ static int micrel_switch_probe(struct device_d *dev)
 			NULL, &priv->p_enable, priv);
 
 	priv->p_enable = 1;
-	micrel_switch_write_reg(priv->spi, REG_ID1, 1);
+	micrel_switch_write_reg(priv, REG_ID1, 1);
 
 	return 0;
 }
 
+static const struct platform_device_id ksz_ids[] = {
+	{ .name = "ksz8864rmn", .driver_data = ksz88 },
+	{ .name = "ksz8795", .driver_data = ksz87 },
+	{ }
+};
+
 static struct driver_d micrel_switch_driver = {
 	.name  = "ksz8864rmn",
 	.probe = micrel_switch_probe,
+	.id_table = ksz_ids,
 };
 device_spi_driver(micrel_switch_driver);
-- 
2.31.1




More information about the barebox mailing list