Merge branch 'master' of git://git.denx.de/u-boot-i2c
[platform/kernel/u-boot.git] / drivers / i2c / muxes / i2c-mux-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <i2c.h>
11 #include <dm/lists.h>
12 #include <dm/root.h>
13
14 /**
15  * struct i2c_mux: Information the uclass stores about an I2C mux
16  *
17  * @selected:   Currently selected mux, or -1 for none
18  * @i2c_bus: I2C bus to use for communcation
19  */
20 struct i2c_mux {
21         int selected;
22         struct udevice *i2c_bus;
23 };
24
25 /**
26  * struct i2c_mux_bus: Information about each bus the mux controls
27  *
28  * @channel: Channel number used to select this bus
29  */
30 struct i2c_mux_bus {
31         uint channel;
32 };
33
34 /* Find out the mux channel number */
35 static int i2c_mux_child_post_bind(struct udevice *dev)
36 {
37         struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
38         int channel;
39
40         channel = dev_read_u32_default(dev, "reg", -1);
41         if (channel < 0)
42                 return -EINVAL;
43         plat->channel = channel;
44
45         return 0;
46 }
47
48 /* Find the I2C buses selected by this mux */
49 static int i2c_mux_post_bind(struct udevice *mux)
50 {
51         ofnode node;
52         int ret;
53
54         debug("%s: %s\n", __func__, mux->name);
55         /*
56          * There is no compatible string in the sub-nodes, so we must manually
57          * bind these
58          */
59         dev_for_each_subnode(node, mux) {
60                 struct udevice *dev;
61                 const char *name;
62
63                 name = ofnode_get_name(node);
64                 ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name,
65                                                  node, &dev);
66                 debug("   - bind ret=%d, %s\n", ret, dev ? dev->name : NULL);
67                 if (ret)
68                         return ret;
69         }
70
71         return 0;
72 }
73
74 /* Set up the mux ready for use */
75 static int i2c_mux_post_probe(struct udevice *mux)
76 {
77         struct i2c_mux *priv = dev_get_uclass_priv(mux);
78         int ret;
79
80         debug("%s: %s\n", __func__, mux->name);
81         priv->selected = -1;
82
83         /* if parent is of i2c uclass already, we'll take that, otherwise
84          * look if we find an i2c-parent phandle
85          */
86         if (UCLASS_I2C == device_get_uclass_id(mux->parent)) {
87                 priv->i2c_bus = dev_get_parent(mux);
88                 debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus,
89                       priv->i2c_bus->name);
90                 return 0;
91         }
92
93         ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
94                                            &priv->i2c_bus);
95         if (ret)
96                 return ret;
97         debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
98
99         return 0;
100 }
101
102 int i2c_mux_select(struct udevice *dev)
103 {
104         struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
105         struct udevice *mux = dev->parent;
106         struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
107
108         if (!ops->select)
109                 return -ENOSYS;
110
111         return ops->select(mux, dev, plat->channel);
112 }
113
114 int i2c_mux_deselect(struct udevice *dev)
115 {
116         struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
117         struct udevice *mux = dev->parent;
118         struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
119
120         if (!ops->deselect)
121                 return -ENOSYS;
122
123         return ops->deselect(mux, dev, plat->channel);
124 }
125
126 static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
127 {
128         struct udevice *mux = dev->parent;
129         struct i2c_mux *priv = dev_get_uclass_priv(mux);
130         int ret, ret2;
131
132         ret = i2c_mux_select(dev);
133         if (ret)
134                 return ret;
135         ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
136         ret2 = i2c_mux_deselect(dev);
137
138         return ret ? ret : ret2;
139 }
140
141 static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
142                              uint chip_flags)
143 {
144         struct udevice *mux = dev->parent;
145         struct i2c_mux *priv = dev_get_uclass_priv(mux);
146         struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
147         int ret, ret2;
148
149         debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
150         if (!ops->probe_chip)
151                 return -ENOSYS;
152         ret = i2c_mux_select(dev);
153         if (ret)
154                 return ret;
155         ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
156         ret2 = i2c_mux_deselect(dev);
157
158         return ret ? ret : ret2;
159 }
160
161 static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
162                             int nmsgs)
163 {
164         struct udevice *mux = dev->parent;
165         struct i2c_mux *priv = dev_get_uclass_priv(mux);
166         struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
167         int ret, ret2;
168
169         debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
170         if (!ops->xfer)
171                 return -ENOSYS;
172         ret = i2c_mux_select(dev);
173         if (ret)
174                 return ret;
175         ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
176         ret2 = i2c_mux_deselect(dev);
177
178         return ret ? ret : ret2;
179 }
180
181 static const struct dm_i2c_ops i2c_mux_bus_ops = {
182         .xfer           = i2c_mux_bus_xfer,
183         .probe_chip     = i2c_mux_bus_probe,
184         .set_bus_speed  = i2c_mux_bus_set_bus_speed,
185 };
186
187 U_BOOT_DRIVER(i2c_mux_bus) = {
188         .name           = "i2c_mux_bus_drv",
189         .id             = UCLASS_I2C,
190         .ops    = &i2c_mux_bus_ops,
191 };
192
193 UCLASS_DRIVER(i2c_mux) = {
194         .id             = UCLASS_I2C_MUX,
195         .name           = "i2c_mux",
196         .post_bind      = i2c_mux_post_bind,
197         .post_probe     = i2c_mux_post_probe,
198         .per_device_auto_alloc_size = sizeof(struct i2c_mux),
199         .per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
200         .child_post_bind = i2c_mux_child_post_bind,
201 };