[U-Boot] [PATCH 08/55] i2c: Add a mux for GPIO-based I2C bus arbitration
Simon Glass
sjg at chromium.org
Mon Jul 6 18:38:27 CEST 2015
Hi Heiko,
On 5 July 2015 at 00:43, Heiko Schocher <hs at 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 <sjg at 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 <sjg at 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
More information about the U-Boot
mailing list