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