From mboxrd@z Thu Jan 1 00:00:00 1970 From: Heiko Schocher Date: Sun, 05 Jul 2015 08:43:48 +0200 Subject: [U-Boot] [PATCH 08/55] i2c: Add a mux for GPIO-based I2C bus arbitration In-Reply-To: <1435882592-487-9-git-send-email-sjg@chromium.org> References: <1435882592-487-1-git-send-email-sjg@chromium.org> <1435882592-487-9-git-send-email-sjg@chromium.org> Message-ID: <5598D224.8070706@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hello Simon, Am 03.07.2015 um 02:15 schrieb Simon Glass: > While I2C supports multi-master buses this is difficult to get right. This What do you mean here? Where are the problems? You have an i2c mux, or? > driver provides a scheme based on two 'claim' GPIOs, one driven by the AP > and one driver by the EC. With these they can communicate and reliably What is AP and EC ? > share the bus. This scheme has minimal overhead and involves very little > code. It is used on snow to permit the EC and the AP to share access to > the main system PMIC and battery. The scheme can survive reboots by either > side without difficulty. > > Signed-off-by: Simon Glass > --- > > drivers/i2c/muxes/Kconfig | 9 ++ > drivers/i2c/muxes/Makefile | 1 + > drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 147 +++++++++++++++++++++++++++++ Nice! Could you add a readme, which explains this a little bit more? > 3 files changed, 157 insertions(+) > create mode 100644 drivers/i2c/muxes/i2c-arb-gpio-challenge.c > > diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig > index a05b32d..bd3e078 100644 > --- a/drivers/i2c/muxes/Kconfig > +++ b/drivers/i2c/muxes/Kconfig > @@ -6,3 +6,12 @@ config I2C_MUX > one of several buses using some sort of control mechanism. The > bus select is handled automatically when that bus is accessed, > using a suitable I2C MUX driver. > + > +config I2C_ARB_GPIO_CHALLENGE > + bool "GPIO-based I2C arbitration" > + depends on I2C_MUX > + help > + If you say yes to this option, support will be included for an > + I2C multimaster arbitration scheme using GPIOs and a challenge & > + response mechanism where masters have to claim the bus by asserting > + a GPIO. > diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile > index 7583e3a..612cc27 100644 > --- a/drivers/i2c/muxes/Makefile > +++ b/drivers/i2c/muxes/Makefile > @@ -3,4 +3,5 @@ > # > # SPDX-License-Identifier: GPL-2.0+ > # > +obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o > obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o > diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c > new file mode 100644 > index 0000000..3f072c7 > --- /dev/null > +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c > @@ -0,0 +1,147 @@ > +/* > + * Copyright (c) 2015 Google, Inc > + * Written by Simon Glass > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct i2c_arbitrator_priv { > + struct gpio_desc ap_claim; > + struct gpio_desc ec_claim; > + uint slew_delay_us; > + uint wait_retry_ms; > + uint wait_free_ms; > +}; > + > +int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus, > + uint channel) > +{ > + struct i2c_arbitrator_priv *priv = dev_get_priv(mux); > + int ret; > + > + debug("%s: %s\n", __func__, mux->name); > + ret = dm_gpio_set_value(&priv->ap_claim, 0); > + udelay(priv->slew_delay_us); > + > + return ret; > +} > + > +int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus, > + uint channel) > +{ > + struct i2c_arbitrator_priv *priv = dev_get_priv(mux); > + unsigned start; > + int ret; > + > + debug("%s: %s\n", __func__, mux->name); > + /* Start a round of trying to claim the bus */ > + start = get_timer(0); > + do { > + unsigned start_retry; > + int waiting = 0; > + > + /* Indicate that we want to claim the bus */ > + ret = dm_gpio_set_value(&priv->ap_claim, 1); > + if (ret) > + goto err; > + udelay(priv->slew_delay_us); > + > + /* Wait for the EC to release it */ > + start_retry = get_timer(0); > + while (get_timer(start_retry) < priv->wait_retry_ms) { > + ret = dm_gpio_get_value(&priv->ec_claim); > + if (ret < 0) { > + goto err; > + } else if (!ret) { > + /* We got it, so return */ > + return 0; > + } > + > + if (!waiting) > + waiting = 1; > + } > + > + /* It didn't release, so give up, wait, and try again */ > + ret = dm_gpio_set_value(&priv->ap_claim, 0); > + if (ret) > + goto err; > + > + mdelay(priv->wait_retry_ms); > + } while (get_timer(start) < priv->wait_free_ms); > + > + /* Give up, release our claim */ > + printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start)); > + ret = -ETIMEDOUT; > + ret = 0; > +err: > + return ret; > +} > + > +static int i2c_arbitrator_probe(struct udevice *dev) > +{ > + struct i2c_arbitrator_priv *priv = dev_get_priv(dev); > + const void *blob = gd->fdt_blob; > + int node = dev->of_offset; > + int ret; > + > + debug("%s: %s\n", __func__, dev->name); > + priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0); > + priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) / > + 1000; > + priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) / > + 1000; > + ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim, > + GPIOD_IS_OUT); > + if (ret) > + goto err; > + ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim, > + GPIOD_IS_IN); What is "our" and "their"? bye, Heiko > + if (ret) > + goto err_ec_gpio; > + > + return 0; > + > +err_ec_gpio: > + dm_gpio_free(dev, &priv->ap_claim); > +err: > + debug("%s: ret=%d\n", __func__, ret); > + return ret; > +} > + > +static int i2c_arbitrator_remove(struct udevice *dev) > +{ > + struct i2c_arbitrator_priv *priv = dev_get_priv(dev); > + > + dm_gpio_free(dev, &priv->ap_claim); > + dm_gpio_free(dev, &priv->ec_claim); > + > + return 0; > +} > + > +static const struct i2c_mux_ops i2c_arbitrator_ops = { > + .select = i2c_arbitrator_select, > + .deselect = i2c_arbitrator_deselect, > +}; > + > +static const struct udevice_id i2c_arbitrator_ids[] = { > + { .compatible = "i2c-arb-gpio-challenge" }, > + { } > +}; > + > +U_BOOT_DRIVER(i2c_arbitrator) = { > + .name = "i2c_arbitrator", > + .id = UCLASS_I2C_MUX, > + .of_match = i2c_arbitrator_ids, > + .probe = i2c_arbitrator_probe, > + .remove = i2c_arbitrator_remove, > + .ops = &i2c_arbitrator_ops, > + .priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv), > +}; > -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany