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