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