Hi Heiko, On 5 July 2015 at 00:43, Heiko Schocher <h...@denx.de> wrote: > 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 ?
Application Processor, i.e. the main CPU (e.,g. Cortex-A15 SoC) Embedded controller (e.g. Cortex-M3 microcontroller) I'll update the commit message. > >> 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 <s...@chromium.org> >> --- >> >> 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? Will do. > > >> 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 <s...@chromium.org> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#include <common.h> >> +#include <dm.h> >> +#include <errno.h> >> +#include <i2c.h> >> +#include <asm/gpio.h> >> + >> +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"? 'our' means the one 'we' use, i.e. the AP. This is the binding used by the kernel so I have kept it the same. > > 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), >> +}; >> Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot