From patchwork Fri Jul 3 00:15:45 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 490843 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 96DA2140770 for ; Fri, 3 Jul 2015 10:18:31 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b=BtFgPM9Y; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EE0644B6E2; Fri, 3 Jul 2015 02:18:27 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZYJKdF_glASz; Fri, 3 Jul 2015 02:18:27 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D9A424B6F8; Fri, 3 Jul 2015 02:18:03 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0610F4B635 for ; Fri, 3 Jul 2015 02:17:04 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5lQV_wdQ-XZZ for ; Fri, 3 Jul 2015 02:17:03 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ig0-f182.google.com (mail-ig0-f182.google.com [209.85.213.182]) by theia.denx.de (Postfix) with ESMTPS id 53CCD4B692 for ; Fri, 3 Jul 2015 02:16:59 +0200 (CEST) Received: by igcur8 with SMTP id ur8so132334683igc.0 for ; Thu, 02 Jul 2015 17:16:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=V2yYtgk5rl4l/tE0ssOl9oQ7fe1GSmXaPs+M3L7rSLQ=; b=BtFgPM9Y9yON6Ro6NqylJkjtQu6fw0RlBceil+fuiffVRE+1OhItbccCwB5dXjMVQp apnN4jXJo17w7x7BrC3Ki+470Qfrvvuk9MGvJixOPlez8eoqurmgRDO0TK+W3i9rFTEu dRRqhN7z1yS1IU4OXQPgM7Kel6S3tpdadqt8bbG1aDP7WB5yksDNBkAAzUZJWW6QXSiL r+Q44h73Blyarb+nuVrDedhTlrZXlgf3uw4HZfxPsu/gdITOB99XRZsZBdF+UeODSdi1 kZ/RoXDbnJhubrD70uUvGgWpyAYIhcJtyYjx6NtqUegycSwCtZpkrqL4wAWDj3WY/jwO cUJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=V2yYtgk5rl4l/tE0ssOl9oQ7fe1GSmXaPs+M3L7rSLQ=; b=NjVshBQfU1p2tFd3WmArlQB802BrV9KeJ4sISRX47LOxDgz0YKGEPMUOA6JFyhjDsQ VGHjdQ4QAkYigT/k76IdZLWG4ZcZlx4xdjLSA9LxolSkim1XAJNpc7ilVhrkX6EI9NJ0 FMLRWrN9TZMCOrP8hvSUaWYd/1cHcPEFc+02Bxsur/ZjnDkqFnBRvCmnuluVvW35pnYu 0Nd+WTePtGrH1HAn3xiQvEfKqq8sgbas4TreBMm6e7pND8F0a92Wbhe+ograSa9eKqPn 6SR2ZrSFc6avXzF/cvqb8Osh27cgXww08yx2FOFIdZMfK3boiuMv20i58EHGA1FgEzpl ZS1w== X-Gm-Message-State: ALoCoQlBAFBK756R4vnIUg7CGvnLomnwauxtksb1o2kvADNEax6yjSjZdVvkz0uVGXZnJn4GCh6w X-Received: by 10.107.132.211 with SMTP id o80mr33215749ioi.52.1435882618004; Thu, 02 Jul 2015 17:16:58 -0700 (PDT) Received: from kaki.bld.corp.google.com ([172.29.216.32]) by smtp.gmail.com with ESMTPSA id k2sm6545165ige.1.2015.07.02.17.16.54 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 02 Jul 2015 17:16:55 -0700 (PDT) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 97E83220E58; Thu, 2 Jul 2015 18:16:52 -0600 (MDT) From: Simon Glass To: U-Boot Mailing List Date: Thu, 2 Jul 2015 18:15:45 -0600 Message-Id: <1435882592-487-9-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.4.3.573.g4eafbef In-Reply-To: <1435882592-487-1-git-send-email-sjg@chromium.org> References: <1435882592-487-1-git-send-email-sjg@chromium.org> Cc: Tom Rini Subject: [U-Boot] [PATCH 08/55] i2c: Add a mux for GPIO-based I2C bus arbitration X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" While I2C supports multi-master buses this is difficult to get right. This 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 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 +++++++++++++++++++++++++++++ 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); + 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), +};