i2c-mux-uclass.c 4.7 KB

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