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