uboot/drivers/net/mdio_mux_i2creg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2019
   4 * Alex Marginean, NXP
   5 */
   6
   7#include <dm.h>
   8#include <errno.h>
   9#include <log.h>
  10#include <miiphy.h>
  11#include <i2c.h>
  12
  13/*
  14 * This driver is used for MDIO muxes driven by writing to a register of an I2C
  15 * chip.  The board it was developed for uses a mux controlled by on-board FPGA
  16 * which in turn is accessed as a chip over I2C.
  17 */
  18
  19struct mdio_mux_i2creg_priv {
  20        struct udevice *chip;
  21        int reg;
  22        int mask;
  23};
  24
  25static int mdio_mux_i2creg_select(struct udevice *mux, int cur, int sel)
  26{
  27        struct mdio_mux_i2creg_priv *priv = dev_get_priv(mux);
  28        u8 val, val_old;
  29
  30        /* if last selection didn't change we're good to go */
  31        if (cur == sel)
  32                return 0;
  33
  34        val_old = dm_i2c_reg_read(priv->chip, priv->reg);
  35        val = (val_old & ~priv->mask) | (sel & priv->mask);
  36        debug("%s: chip %s, reg %x, val %x => %x\n", __func__, priv->chip->name,
  37              priv->reg, val_old, val);
  38        dm_i2c_reg_write(priv->chip, priv->reg, val);
  39
  40        return 0;
  41}
  42
  43static const struct mdio_mux_ops mdio_mux_i2creg_ops = {
  44        .select = mdio_mux_i2creg_select,
  45};
  46
  47static int mdio_mux_i2creg_probe(struct udevice *dev)
  48{
  49        struct mdio_mux_i2creg_priv *priv = dev_get_priv(dev);
  50        ofnode chip_node, bus_node;
  51        struct udevice *i2c_bus;
  52        u32 reg_mask[2];
  53        u32 chip_addr;
  54        int err;
  55
  56        /* read the register addr/mask pair */
  57        err = dev_read_u32_array(dev, "mux-reg-masks", reg_mask, 2);
  58        if (err) {
  59                debug("%s: error reading mux-reg-masks property\n", __func__);
  60                return err;
  61        }
  62
  63        /* parent should be an I2C chip, grandparent should be an I2C bus */
  64        chip_node = ofnode_get_parent(dev_ofnode(dev));
  65        bus_node = ofnode_get_parent(chip_node);
  66
  67        err = uclass_get_device_by_ofnode(UCLASS_I2C, bus_node, &i2c_bus);
  68        if (err) {
  69                debug("%s: can't find I2C bus for node %s\n", __func__,
  70                      ofnode_get_name(bus_node));
  71                return err;
  72        }
  73
  74        err = ofnode_read_u32(chip_node, "reg", &chip_addr);
  75        if (err) {
  76                debug("%s: can't read chip address in %s\n", __func__,
  77                      ofnode_get_name(chip_node));
  78                return err;
  79        }
  80
  81        err = i2c_get_chip(i2c_bus, (uint)chip_addr, 1, &priv->chip);
  82        if (err) {
  83                debug("%s: can't find i2c chip device for addr %x\n", __func__,
  84                      chip_addr);
  85                return err;
  86        }
  87
  88        priv->reg = (int)reg_mask[0];
  89        priv->mask = (int)reg_mask[1];
  90
  91        debug("%s: chip %s, reg %x, mask %x\n", __func__, priv->chip->name,
  92              priv->reg, priv->mask);
  93
  94        return 0;
  95}
  96
  97static const struct udevice_id mdio_mux_i2creg_ids[] = {
  98        { .compatible = "mdio-mux-i2creg" },
  99        { }
 100};
 101
 102U_BOOT_DRIVER(mdio_mux_i2creg) = {
 103        .name           = "mdio_mux_i2creg",
 104        .id             = UCLASS_MDIO_MUX,
 105        .of_match       = mdio_mux_i2creg_ids,
 106        .probe          = mdio_mux_i2creg_probe,
 107        .ops            = &mdio_mux_i2creg_ops,
 108        .priv_auto      = sizeof(struct mdio_mux_i2creg_priv),
 109};
 110