blob: 3e82898f46e0c9453d83674d6be39d9ad2eb024f [file] [log] [blame]
Alex Marginean3234a5e2019-07-16 11:21:17 +03001// 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
18struct mdio_mux_i2creg_priv {
19 struct udevice *chip;
20 int reg;
21 int mask;
22};
23
24static 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
42static const struct mdio_mux_ops mdio_mux_i2creg_ops = {
43 .select = mdio_mux_i2creg_select,
44};
45
46static 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
96static const struct udevice_id mdio_mux_i2creg_ids[] = {
97 { .compatible = "mdio-mux-i2creg" },
98 { }
99};
100
101U_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};