[PATCH v1 1/4] i2c: mux: Add i2c-arbitrator 'mux' driver

Doug Anderson dianders at chromium.org
Thu Feb 14 11:34:55 EST 2013


Stephen,

Thank you for the review.  Comments below (including changes I have
done locally).  I probably won't have time to test / repost until
tomorrow.


On Wed, Feb 13, 2013 at 1:02 PM, Stephen Warren <swarren at wwwdotorg.org> wrote:
> On 02/13/2013 11:02 AM, Doug Anderson wrote:
>> The i2c-arbitrator driver implements the arbitration scheme that the
>> Embedded Controller (EC) on the ARM Chromebook expects to use for bus
>> multimastering.  This i2c-arbitrator driver could also be used in
>> other places where standard i2c bus arbitration can't be used and two
>> extra GPIOs are available for arbitration.
>>
>> This driver is based on code that Simon Glass added to the i2c-s3c2410
>> driver in the Chrome OS kernel 3.4 tree.  The current incarnation as a
>> mux driver is as suggested by Grant Likely.  See
>> <https://patchwork.kernel.org/patch/1877311/> for some history.
>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-arbitrator.txt b/Documentation/devicetree/bindings/i2c/i2c-arbitrator.txt
>
>> +This mechanism is used instead of standard i2c multimaster to avoid some of the
>> +subtle driver and silicon bugs that are often present with i2c multimaster.
>
> Being really pick here, but I2C should be capitalized in free-form text.
> There are a few other places where the comment applies.

Done.


>> +Required properties:
>> +- compatible: i2c-arbitrator
>
> That seems pretty generic. What if there are other arbitration schemes?

OK, going to go with i2c-arbitrator-cros-ec.  Hopefully that sounds OK.


>> +- bus-arbitration-gpios: Two GPIOs to use with the GPIO-based bus
>> +    arbitration protocol.  The first should be an output, and is used to
>> +    claim the I2C bus for us (AP_CLAIM).  The second should be an input and
>> +    signals that the other side wants to claim the bus (EC_CLAIM).
>
> Is it worth using two separate properties here, so they each get a
> unique name. That way, nobody has the remember which order the two GPIOs
> come in.

Yes, I think it's better too.  Done.


>> diff --git a/drivers/i2c/muxes/i2c-arbitrator.c b/drivers/i2c/muxes/i2c-arbitrator.c
>
>> +enum {
>> +     I2C_ARB_GPIO_AP,                /* AP claims i2c bus */
>> +     I2C_ARB_GPIO_EC,                /* EC claims i2c bus */
>> +
>> +     I2C_ARB_GPIO_COUNT,
>> +};
>
> Oh, I see from later code that those are indices into the
> bus-arbitration-gpios DT property. I thought they were states in some
> state machine at first. A comment might help here, if you continue to
> use one property.

Removed this bit of code.


>> +static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
>> +{
>> +     const struct i2c_arbitrator_data *arb = data;
>> +     unsigned long stop_retry, stop_time;
>> +
>> +     /* Start a round of trying to claim the bus */
>> +     stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
>> +     do {
>> +             /* Indicate that we want to claim the bus */
>> +             gpio_set_value(arb->ap_gpio, 0);
>
> The GPIO signals appear to be active low in the code. Instead, I think
> it'd make more sense to extract the polarity of the GPIO from DT, using
> of_get_named_gpio_flags().

A little torn here.  It adds a bunch of complexity to the code to
handle this case and there are no known or anticipated users.  I only
wish that the GPIO polarity could be more hidden from drivers (add
functions like gpio_assert, gpio_deassert, etc)...

In any case, I've done it.  I used the "!!" trick a lot to convert
"zero/non-zero" to "0/1" to at least reduce the lines of code a
little.  I think this is common enough that it helps readability
rather than hurting it.


>> +static int i2c_arbitrator_probe(struct platform_device *pdev)
>
>> +     /* Request GPIOs */
>> +     ret = of_get_named_gpio(np, "bus-arbitration-gpios", I2C_ARB_GPIO_AP);
>> +     if (gpio_is_valid(ret)) {
>> +             arb->ap_gpio = ret;
>> +             ret = gpio_request_one(arb->ap_gpio, GPIOF_OUT_INIT_HIGH,
>> +                                    "bus-arbitration-ap");
>> +     }
>> +     if (WARN_ON(ret))
>> +             goto ap_request_failed;
>
> you could use devm_gpio_request_one() and save some cleanup logic.

Whoops, didn't realize that was there.  Done.


>> +     /* Arbitration parameters */
>> +     if (of_property_read_u32(np, "bus-arbitration-slew-delay-us",
>> +                              &arb->slew_delay_us))
>> +             arb->slew_delay_us = 10;
>
> The DT binding document says that property is required. Either the code
> should error out here, or the document updated to indicate that the
> properties are optional, and specify what the defaults are.

Done.  Now optional.


>> +static int i2c_arbitrator_remove(struct platform_device *pdev)
>
>> +     platform_set_drvdata(pdev, NULL);
>
> You shouldn't have to do that; nothing should care what the pdata value
> is while the device isn't probed anyway.

Done.  Code was stolen from i2c_mux_gpio_remove(), so perhaps we
should remove it there too.  I'll send up a quick cleanup patch
tomorrow.


>> +static int __init i2c_arbitrator_init(void)
>> +{
>> +     return platform_driver_register(&i2c_arbitrator_driver);
>> +}
>> +subsys_initcall(i2c_arbitrator_init);
>> +
>> +static void __exit i2c_arbitrator_exit(void)
>> +{
>> +     platform_driver_unregister(&i2c_arbitrator_driver);
>> +}
>> +module_exit(i2c_arbitrator_exit);
>
> You should be able to replace all that with:
>
> module_platform_driver(&i2c_arbitrator_driver);

Sigh.  Yeah, I had that.  ...but it ends up getting initted
significantly later in the init process and that was uncovering bugs
in other drivers where they weren't expressing their dependencies
properly.  I was going to try to fix those bugs separately but it
seemed to make some sense to prioritize this bus a little bit anyway
by using subsys_initcall().  ...but maybe that's just wrong.

Unless you think it's a bug or terrible form to use subsys_initcall()
I'd rather leave that.  Is that OK?


>> +MODULE_LICENSE("GPL");
>
> The header says GPL v2 only, so "GPL v2".

Done.


More information about the devicetree-discuss mailing list