]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
drivers: net: driver for MDIO muxes controlled over I2C
authorAlex Marginean <alexandru.marginean@nxp.com>
Tue, 16 Jul 2019 08:21:17 +0000 (11:21 +0300)
committerJoe Hershberger <joe.hershberger@ni.com>
Wed, 4 Sep 2019 16:37:19 +0000 (11:37 -0500)
This driver is used for MDIO muxes driven over I2C.  This is currently
used on Freescale LS1028A QDS board, on which the physical MDIO MUX is
controlled by an on-board FPGA which in turn is configured through I2C.

Signed-off-by: Alex Marginean <alexm.osslist@gmail.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/mdio_mux_i2creg.c [new file with mode: 0644]

index 6eb22df528a17aa0a52c07d1c1e612827d52608e..084e09522919b1c46e7627a4d7d992895fdbc48a 100644 (file)
@@ -595,4 +595,12 @@ config FSL_ENETC
          This driver supports the NXP ENETC Ethernet controller found on some
          of the NXP SoCs.
 
+config MDIO_MUX_I2CREG
+       bool "MDIO MUX accessed as a register over I2C"
+       depends on DM_MDIO_MUX && DM_I2C
+       help
+         This driver is used for MDIO muxes driven by writing to a register of
+         an I2C chip.  The board it was developed for uses a mux controlled by
+         on-board FPGA which in turn is accessed as a chip over I2C.
+
 endif # NETDEVICES
index b6e40df5224359233d8953cf88c8826407d243e8..71c0889355c8087894e51208fd5819cc01adc2eb 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_LAN91C96) += lan91c96.o
 obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
 obj-$(CONFIG_MACB) += macb.o
 obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
 obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
 obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
 obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
diff --git a/drivers/net/mdio_mux_i2creg.c b/drivers/net/mdio_mux_i2creg.c
new file mode 100644 (file)
index 0000000..3e82898
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+#include <i2c.h>
+
+/*
+ * This driver is used for MDIO muxes driven by writing to a register of an I2C
+ * chip.  The board it was developed for uses a mux controlled by on-board FPGA
+ * which in turn is accessed as a chip over I2C.
+ */
+
+struct mdio_mux_i2creg_priv {
+       struct udevice *chip;
+       int reg;
+       int mask;
+};
+
+static int mdio_mux_i2creg_select(struct udevice *mux, int cur, int sel)
+{
+       struct mdio_mux_i2creg_priv *priv = dev_get_priv(mux);
+       u8 val, val_old;
+
+       /* if last selection didn't change we're good to go */
+       if (cur == sel)
+               return 0;
+
+       val_old = dm_i2c_reg_read(priv->chip, priv->reg);
+       val = (val_old & ~priv->mask) | (sel & priv->mask);
+       debug("%s: chip %s, reg %x, val %x => %x\n", __func__, priv->chip->name,
+             priv->reg, val_old, val);
+       dm_i2c_reg_write(priv->chip, priv->reg, val);
+
+       return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_i2creg_ops = {
+       .select = mdio_mux_i2creg_select,
+};
+
+static int mdio_mux_i2creg_probe(struct udevice *dev)
+{
+       struct mdio_mux_i2creg_priv *priv = dev_get_priv(dev);
+       ofnode chip_node, bus_node;
+       struct udevice *i2c_bus;
+       u32 reg_mask[2];
+       u32 chip_addr;
+       int err;
+
+       /* read the register addr/mask pair */
+       err = dev_read_u32_array(dev, "mux-reg-masks", reg_mask, 2);
+       if (err) {
+               debug("%s: error reading mux-reg-masks property\n", __func__);
+               return err;
+       }
+
+       /* parent should be an I2C chip, grandparent should be an I2C bus */
+       chip_node = ofnode_get_parent(dev->node);
+       bus_node = ofnode_get_parent(chip_node);
+
+       err = uclass_get_device_by_ofnode(UCLASS_I2C, bus_node, &i2c_bus);
+       if (err) {
+               debug("%s: can't find I2C bus for node %s\n", __func__,
+                     ofnode_get_name(bus_node));
+               return err;
+       }
+
+       err = ofnode_read_u32(chip_node, "reg", &chip_addr);
+       if (err) {
+               debug("%s: can't read chip address in %s\n", __func__,
+                     ofnode_get_name(chip_node));
+               return err;
+       }
+
+       err = i2c_get_chip(i2c_bus, (uint)chip_addr, 1, &priv->chip);
+       if (err) {
+               debug("%s: can't find i2c chip device for addr %x\n", __func__,
+                     chip_addr);
+               return err;
+       }
+
+       priv->reg = (int)reg_mask[0];
+       priv->mask = (int)reg_mask[1];
+
+       debug("%s: chip %s, reg %x, mask %x\n", __func__, priv->chip->name,
+             priv->reg, priv->mask);
+
+       return 0;
+}
+
+static const struct udevice_id mdio_mux_i2creg_ids[] = {
+       { .compatible = "mdio-mux-i2creg" },
+       { }
+};
+
+U_BOOT_DRIVER(mdio_mux_i2creg) = {
+       .name           = "mdio_mux_i2creg",
+       .id             = UCLASS_MDIO_MUX,
+       .of_match       = mdio_mux_i2creg_ids,
+       .probe          = mdio_mux_i2creg_probe,
+       .ops            = &mdio_mux_i2creg_ops,
+       .priv_auto_alloc_size = sizeof(struct mdio_mux_i2creg_priv),
+};