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