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 <[email protected]>
---
 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


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to