uboot/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <i2c.h>
  11#include <asm/gpio.h>
  12
  13DECLARE_GLOBAL_DATA_PTR;
  14
  15struct i2c_arbitrator_priv {
  16        struct gpio_desc ap_claim;
  17        struct gpio_desc ec_claim;
  18        uint slew_delay_us;
  19        uint wait_retry_ms;
  20        uint wait_free_ms;
  21};
  22
  23int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
  24                            uint channel)
  25{
  26        struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
  27        int ret;
  28
  29        debug("%s: %s\n", __func__, mux->name);
  30        ret = dm_gpio_set_value(&priv->ap_claim, 0);
  31        udelay(priv->slew_delay_us);
  32
  33        return ret;
  34}
  35
  36int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
  37                          uint channel)
  38{
  39        struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
  40        unsigned start;
  41        int ret;
  42
  43        debug("%s: %s\n", __func__, mux->name);
  44        /* Start a round of trying to claim the bus */
  45        start = get_timer(0);
  46        do {
  47                unsigned start_retry;
  48                int waiting = 0;
  49
  50                /* Indicate that we want to claim the bus */
  51                ret = dm_gpio_set_value(&priv->ap_claim, 1);
  52                if (ret)
  53                        goto err;
  54                udelay(priv->slew_delay_us);
  55
  56                /* Wait for the EC to release it */
  57                start_retry = get_timer(0);
  58                while (get_timer(start_retry) < priv->wait_retry_ms) {
  59                        ret = dm_gpio_get_value(&priv->ec_claim);
  60                        if (ret < 0) {
  61                                goto err;
  62                        } else if (!ret) {
  63                                /* We got it, so return */
  64                                return 0;
  65                        }
  66
  67                        if (!waiting)
  68                                waiting = 1;
  69                }
  70
  71                /* It didn't release, so give up, wait, and try again */
  72                ret = dm_gpio_set_value(&priv->ap_claim, 0);
  73                if (ret)
  74                        goto err;
  75
  76                mdelay(priv->wait_retry_ms);
  77        } while (get_timer(start) < priv->wait_free_ms);
  78
  79        /* Give up, release our claim */
  80        printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
  81        ret = -ETIMEDOUT;
  82        ret = 0;
  83err:
  84        return ret;
  85}
  86
  87static int i2c_arbitrator_probe(struct udevice *dev)
  88{
  89        struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
  90        const void *blob = gd->fdt_blob;
  91        int node = dev_of_offset(dev);
  92        int ret;
  93
  94        debug("%s: %s\n", __func__, dev->name);
  95        priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
  96        priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
  97                1000;
  98        priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
  99                1000;
 100        ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
 101                                   GPIOD_IS_OUT);
 102        if (ret)
 103                goto err;
 104        ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
 105                                   GPIOD_IS_IN);
 106        if (ret)
 107                goto err_ec_gpio;
 108
 109        return 0;
 110
 111err_ec_gpio:
 112        dm_gpio_free(dev, &priv->ap_claim);
 113err:
 114        debug("%s: ret=%d\n", __func__, ret);
 115        return ret;
 116}
 117
 118static int i2c_arbitrator_remove(struct udevice *dev)
 119{
 120        struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
 121
 122        dm_gpio_free(dev, &priv->ap_claim);
 123        dm_gpio_free(dev, &priv->ec_claim);
 124
 125        return 0;
 126}
 127
 128static const struct i2c_mux_ops i2c_arbitrator_ops = {
 129        .select         = i2c_arbitrator_select,
 130        .deselect       = i2c_arbitrator_deselect,
 131};
 132
 133static const struct udevice_id i2c_arbitrator_ids[] = {
 134        { .compatible = "i2c-arb-gpio-challenge" },
 135        { }
 136};
 137
 138U_BOOT_DRIVER(i2c_arbitrator) = {
 139        .name = "i2c_arbitrator",
 140        .id = UCLASS_I2C_MUX,
 141        .of_match = i2c_arbitrator_ids,
 142        .probe = i2c_arbitrator_probe,
 143        .remove = i2c_arbitrator_remove,
 144        .ops = &i2c_arbitrator_ops,
 145        .priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
 146};
 147