linux/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * GPIO-based I2C Arbitration Using a Challenge & Response Mechanism
   4 *
   5 * Copyright (C) 2012 Google, Inc
   6 */
   7
   8#include <linux/delay.h>
   9#include <linux/gpio.h>
  10#include <linux/kernel.h>
  11#include <linux/i2c.h>
  12#include <linux/i2c-mux.h>
  13#include <linux/module.h>
  14#include <linux/of_gpio.h>
  15#include <linux/platform_device.h>
  16#include <linux/slab.h>
  17
  18
  19/**
  20 * struct i2c_arbitrator_data - Driver data for I2C arbitrator
  21 *
  22 * @our_gpio: GPIO we'll use to claim.
  23 * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
  24 *   this then consider it released.
  25 * @their_gpio: GPIO that the other side will use to claim.
  26 * @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
  27 *   this then consider it released.
  28 * @slew_delay_us: microseconds to wait for a GPIO to go high.
  29 * @wait_retry_us: we'll attempt another claim after this many microseconds.
  30 * @wait_free_us: we'll give up after this many microseconds.
  31 */
  32
  33struct i2c_arbitrator_data {
  34        int our_gpio;
  35        int our_gpio_release;
  36        int their_gpio;
  37        int their_gpio_release;
  38        unsigned int slew_delay_us;
  39        unsigned int wait_retry_us;
  40        unsigned int wait_free_us;
  41};
  42
  43
  44/**
  45 * i2c_arbitrator_select - claim the I2C bus
  46 *
  47 * Use the GPIO-based signalling protocol; return -EBUSY if we fail.
  48 */
  49static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
  50{
  51        const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
  52        unsigned long stop_retry, stop_time;
  53
  54        /* Start a round of trying to claim the bus */
  55        stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
  56        do {
  57                /* Indicate that we want to claim the bus */
  58                gpio_set_value(arb->our_gpio, !arb->our_gpio_release);
  59                udelay(arb->slew_delay_us);
  60
  61                /* Wait for the other master to release it */
  62                stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
  63                while (time_before(jiffies, stop_retry)) {
  64                        int gpio_val = !!gpio_get_value(arb->their_gpio);
  65
  66                        if (gpio_val == arb->their_gpio_release) {
  67                                /* We got it, so return */
  68                                return 0;
  69                        }
  70
  71                        usleep_range(50, 200);
  72                }
  73
  74                /* It didn't release, so give up, wait, and try again */
  75                gpio_set_value(arb->our_gpio, arb->our_gpio_release);
  76
  77                usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
  78        } while (time_before(jiffies, stop_time));
  79
  80        /* Give up, release our claim */
  81        gpio_set_value(arb->our_gpio, arb->our_gpio_release);
  82        udelay(arb->slew_delay_us);
  83        dev_err(muxc->dev, "Could not claim bus, timeout\n");
  84        return -EBUSY;
  85}
  86
  87/**
  88 * i2c_arbitrator_deselect - release the I2C bus
  89 *
  90 * Release the I2C bus using the GPIO-based signalling protocol.
  91 */
  92static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
  93{
  94        const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
  95
  96        /* Release the bus and wait for the other master to notice */
  97        gpio_set_value(arb->our_gpio, arb->our_gpio_release);
  98        udelay(arb->slew_delay_us);
  99
 100        return 0;
 101}
 102
 103static int i2c_arbitrator_probe(struct platform_device *pdev)
 104{
 105        struct device *dev = &pdev->dev;
 106        struct device_node *np = dev->of_node;
 107        struct device_node *parent_np;
 108        struct i2c_mux_core *muxc;
 109        struct i2c_arbitrator_data *arb;
 110        enum of_gpio_flags gpio_flags;
 111        unsigned long out_init;
 112        int ret;
 113
 114        /* We only support probing from device tree; no platform_data */
 115        if (!np) {
 116                dev_err(dev, "Cannot find device tree node\n");
 117                return -ENODEV;
 118        }
 119        if (dev_get_platdata(dev)) {
 120                dev_err(dev, "Platform data is not supported\n");
 121                return -EINVAL;
 122        }
 123
 124        muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), I2C_MUX_ARBITRATOR,
 125                             i2c_arbitrator_select, i2c_arbitrator_deselect);
 126        if (!muxc)
 127                return -ENOMEM;
 128        arb = i2c_mux_priv(muxc);
 129
 130        platform_set_drvdata(pdev, muxc);
 131
 132        /* Request GPIOs */
 133        ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
 134        if (!gpio_is_valid(ret)) {
 135                if (ret != -EPROBE_DEFER)
 136                        dev_err(dev, "Error getting our-claim-gpio\n");
 137                return ret;
 138        }
 139        arb->our_gpio = ret;
 140        arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
 141        out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ?
 142                GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
 143        ret = devm_gpio_request_one(dev, arb->our_gpio, out_init,
 144                                    "our-claim-gpio");
 145        if (ret) {
 146                if (ret != -EPROBE_DEFER)
 147                        dev_err(dev, "Error requesting our-claim-gpio\n");
 148                return ret;
 149        }
 150
 151        ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags);
 152        if (!gpio_is_valid(ret)) {
 153                if (ret != -EPROBE_DEFER)
 154                        dev_err(dev, "Error getting their-claim-gpio\n");
 155                return ret;
 156        }
 157        arb->their_gpio = ret;
 158        arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
 159        ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN,
 160                                    "their-claim-gpio");
 161        if (ret) {
 162                if (ret != -EPROBE_DEFER)
 163                        dev_err(dev, "Error requesting their-claim-gpio\n");
 164                return ret;
 165        }
 166
 167        /* At the moment we only support a single two master (us + 1 other) */
 168        if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) {
 169                dev_err(dev, "Only one other master is supported\n");
 170                return -EINVAL;
 171        }
 172
 173        /* Arbitration parameters */
 174        if (of_property_read_u32(np, "slew-delay-us", &arb->slew_delay_us))
 175                arb->slew_delay_us = 10;
 176        if (of_property_read_u32(np, "wait-retry-us", &arb->wait_retry_us))
 177                arb->wait_retry_us = 3000;
 178        if (of_property_read_u32(np, "wait-free-us", &arb->wait_free_us))
 179                arb->wait_free_us = 50000;
 180
 181        /* Find our parent */
 182        parent_np = of_parse_phandle(np, "i2c-parent", 0);
 183        if (!parent_np) {
 184                dev_err(dev, "Cannot parse i2c-parent\n");
 185                return -EINVAL;
 186        }
 187        muxc->parent = of_get_i2c_adapter_by_node(parent_np);
 188        of_node_put(parent_np);
 189        if (!muxc->parent) {
 190                dev_err(dev, "Cannot find parent bus\n");
 191                return -EPROBE_DEFER;
 192        }
 193
 194        /* Actually add the mux adapter */
 195        ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
 196        if (ret)
 197                i2c_put_adapter(muxc->parent);
 198
 199        return ret;
 200}
 201
 202static int i2c_arbitrator_remove(struct platform_device *pdev)
 203{
 204        struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 205
 206        i2c_mux_del_adapters(muxc);
 207        i2c_put_adapter(muxc->parent);
 208        return 0;
 209}
 210
 211static const struct of_device_id i2c_arbitrator_of_match[] = {
 212        { .compatible = "i2c-arb-gpio-challenge", },
 213        {},
 214};
 215MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match);
 216
 217static struct platform_driver i2c_arbitrator_driver = {
 218        .probe  = i2c_arbitrator_probe,
 219        .remove = i2c_arbitrator_remove,
 220        .driver = {
 221                .name   = "i2c-arb-gpio-challenge",
 222                .of_match_table = i2c_arbitrator_of_match,
 223        },
 224};
 225
 226module_platform_driver(i2c_arbitrator_driver);
 227
 228MODULE_DESCRIPTION("GPIO-based I2C Arbitration");
 229MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
 230MODULE_LICENSE("GPL v2");
 231MODULE_ALIAS("platform:i2c-arb-gpio-challenge");
 232