Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * GPIO-based I2C Arbitration Using a Challenge & Response Mechanism
0004  *
0005  * Copyright (C) 2012 Google, Inc
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/kernel.h>
0011 #include <linux/i2c.h>
0012 #include <linux/i2c-mux.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/slab.h>
0016 
0017 
0018 /**
0019  * struct i2c_arbitrator_data - Driver data for I2C arbitrator
0020  *
0021  * @our_gpio: GPIO descriptor we'll use to claim.
0022  * @their_gpio: GPIO descriptor that the other side will use to claim.
0023  * @slew_delay_us: microseconds to wait for a GPIO to go high.
0024  * @wait_retry_us: we'll attempt another claim after this many microseconds.
0025  * @wait_free_us: we'll give up after this many microseconds.
0026  */
0027 
0028 struct i2c_arbitrator_data {
0029     struct gpio_desc *our_gpio;
0030     struct gpio_desc *their_gpio;
0031     unsigned int slew_delay_us;
0032     unsigned int wait_retry_us;
0033     unsigned int wait_free_us;
0034 };
0035 
0036 
0037 /*
0038  * i2c_arbitrator_select - claim the I2C bus
0039  *
0040  * Use the GPIO-based signalling protocol; return -EBUSY if we fail.
0041  */
0042 static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
0043 {
0044     const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
0045     unsigned long stop_retry, stop_time;
0046 
0047     /* Start a round of trying to claim the bus */
0048     stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
0049     do {
0050         /* Indicate that we want to claim the bus */
0051         gpiod_set_value(arb->our_gpio, 1);
0052         udelay(arb->slew_delay_us);
0053 
0054         /* Wait for the other master to release it */
0055         stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
0056         while (time_before(jiffies, stop_retry)) {
0057             int gpio_val = gpiod_get_value(arb->their_gpio);
0058 
0059             if (!gpio_val) {
0060                 /* We got it, so return */
0061                 return 0;
0062             }
0063 
0064             usleep_range(50, 200);
0065         }
0066 
0067         /* It didn't release, so give up, wait, and try again */
0068         gpiod_set_value(arb->our_gpio, 0);
0069 
0070         usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
0071     } while (time_before(jiffies, stop_time));
0072 
0073     /* Give up, release our claim */
0074     gpiod_set_value(arb->our_gpio, 0);
0075     udelay(arb->slew_delay_us);
0076     dev_err(muxc->dev, "Could not claim bus, timeout\n");
0077     return -EBUSY;
0078 }
0079 
0080 /*
0081  * i2c_arbitrator_deselect - release the I2C bus
0082  *
0083  * Release the I2C bus using the GPIO-based signalling protocol.
0084  */
0085 static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
0086 {
0087     const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
0088 
0089     /* Release the bus and wait for the other master to notice */
0090     gpiod_set_value(arb->our_gpio, 0);
0091     udelay(arb->slew_delay_us);
0092 
0093     return 0;
0094 }
0095 
0096 static int i2c_arbitrator_probe(struct platform_device *pdev)
0097 {
0098     struct device *dev = &pdev->dev;
0099     struct device_node *np = dev->of_node;
0100     struct device_node *parent_np;
0101     struct i2c_mux_core *muxc;
0102     struct i2c_arbitrator_data *arb;
0103     struct gpio_desc *dummy;
0104     int ret;
0105 
0106     /* We only support probing from device tree; no platform_data */
0107     if (!np) {
0108         dev_err(dev, "Cannot find device tree node\n");
0109         return -ENODEV;
0110     }
0111     if (dev_get_platdata(dev)) {
0112         dev_err(dev, "Platform data is not supported\n");
0113         return -EINVAL;
0114     }
0115 
0116     muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), I2C_MUX_ARBITRATOR,
0117                  i2c_arbitrator_select, i2c_arbitrator_deselect);
0118     if (!muxc)
0119         return -ENOMEM;
0120     arb = i2c_mux_priv(muxc);
0121 
0122     platform_set_drvdata(pdev, muxc);
0123 
0124     /* Request GPIOs, our GPIO as unclaimed to begin with */
0125     arb->our_gpio = devm_gpiod_get(dev, "our-claim", GPIOD_OUT_LOW);
0126     if (IS_ERR(arb->our_gpio)) {
0127         dev_err(dev, "could not get \"our-claim\" GPIO (%ld)\n",
0128             PTR_ERR(arb->our_gpio));
0129         return PTR_ERR(arb->our_gpio);
0130     }
0131 
0132     arb->their_gpio = devm_gpiod_get(dev, "their-claim", GPIOD_IN);
0133     if (IS_ERR(arb->their_gpio)) {
0134         dev_err(dev, "could not get \"their-claim\" GPIO (%ld)\n",
0135             PTR_ERR(arb->their_gpio));
0136         return PTR_ERR(arb->their_gpio);
0137     }
0138 
0139     /* At the moment we only support a single two master (us + 1 other) */
0140     dummy = devm_gpiod_get_index(dev, "their-claim", 1, GPIOD_IN);
0141     if (!IS_ERR(dummy)) {
0142         dev_err(dev, "Only one other master is supported\n");
0143         return -EINVAL;
0144     } else if (PTR_ERR(dummy) == -EPROBE_DEFER) {
0145         return -EPROBE_DEFER;
0146     }
0147 
0148     /* Arbitration parameters */
0149     if (of_property_read_u32(np, "slew-delay-us", &arb->slew_delay_us))
0150         arb->slew_delay_us = 10;
0151     if (of_property_read_u32(np, "wait-retry-us", &arb->wait_retry_us))
0152         arb->wait_retry_us = 3000;
0153     if (of_property_read_u32(np, "wait-free-us", &arb->wait_free_us))
0154         arb->wait_free_us = 50000;
0155 
0156     /* Find our parent */
0157     parent_np = of_parse_phandle(np, "i2c-parent", 0);
0158     if (!parent_np) {
0159         dev_err(dev, "Cannot parse i2c-parent\n");
0160         return -EINVAL;
0161     }
0162     muxc->parent = of_get_i2c_adapter_by_node(parent_np);
0163     of_node_put(parent_np);
0164     if (!muxc->parent) {
0165         dev_err(dev, "Cannot find parent bus\n");
0166         return -EPROBE_DEFER;
0167     }
0168 
0169     /* Actually add the mux adapter */
0170     ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
0171     if (ret)
0172         i2c_put_adapter(muxc->parent);
0173 
0174     return ret;
0175 }
0176 
0177 static int i2c_arbitrator_remove(struct platform_device *pdev)
0178 {
0179     struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
0180 
0181     i2c_mux_del_adapters(muxc);
0182     i2c_put_adapter(muxc->parent);
0183     return 0;
0184 }
0185 
0186 static const struct of_device_id i2c_arbitrator_of_match[] = {
0187     { .compatible = "i2c-arb-gpio-challenge", },
0188     {},
0189 };
0190 MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match);
0191 
0192 static struct platform_driver i2c_arbitrator_driver = {
0193     .probe  = i2c_arbitrator_probe,
0194     .remove = i2c_arbitrator_remove,
0195     .driver = {
0196         .name   = "i2c-arb-gpio-challenge",
0197         .of_match_table = i2c_arbitrator_of_match,
0198     },
0199 };
0200 
0201 module_platform_driver(i2c_arbitrator_driver);
0202 
0203 MODULE_DESCRIPTION("GPIO-based I2C Arbitration");
0204 MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
0205 MODULE_LICENSE("GPL v2");
0206 MODULE_ALIAS("platform:i2c-arb-gpio-challenge");