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