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