Merge branch 'i2c-mux/for-next' of https://github.com/peda-r/i2c-mux into i2c/for-5.3

I realize that there are changes in drivers/i2c/busses/i2c-i801.c that strictly
speaking don't belong here, but I hope you don't mind. These changes are all
about the interaction with the i2c-mux-gpio code, and I did a test-merge a few
days ago w/o conflicts.

Anyway, the GPIO-work from Linus Walleij (with help from Serge Semin) in the
i2c-mux-gpio and i2c-arb-gpio-challenge drivers is the main feature.
This commit is contained in:
Wolfram Sang 2019-06-29 13:02:48 +02:00
commit 45c9cc681d
7 changed files with 92 additions and 158 deletions

View File

@ -1,7 +1,7 @@
What: /sys/devices/platform/<i2c-demux-name>/available_masters
Date: January 2016
KernelVersion: 4.6
Contact: Wolfram Sang <wsa@the-dreams.de>
Contact: Wolfram Sang <wsa+renesas@sang-engineering.com>
Description:
Reading the file will give you a list of masters which can be
selected for a demultiplexed bus. The format is
@ -12,7 +12,7 @@ Description:
What: /sys/devices/platform/<i2c-demux-name>/current_master
Date: January 2016
KernelVersion: 4.6
Contact: Wolfram Sang <wsa@the-dreams.de>
Contact: Wolfram Sang <wsa+renesas@sang-engineering.com>
Description:
This file selects/shows the active I2C master for a demultiplexed
bus. It uses the <index> value from the file 'available_masters'.

View File

@ -109,7 +109,7 @@
#include <linux/pm_runtime.h>
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_data/i2c-mux-gpio.h>
#endif
@ -278,6 +278,7 @@ struct i801_priv {
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev;
struct gpiod_lookup_table *lookup;
#endif
struct platform_device *tco_pdev;
@ -1406,7 +1407,8 @@ static int i801_add_mux(struct i801_priv *priv)
struct device *dev = &priv->adapter.dev;
const struct i801_mux_config *mux_config;
struct i2c_mux_gpio_platform_data gpio_data;
int err;
struct gpiod_lookup_table *lookup;
int err, i;
if (!priv->mux_drvdata)
return 0;
@ -1418,17 +1420,36 @@ static int i801_add_mux(struct i801_priv *priv)
gpio_data.values = mux_config->values;
gpio_data.n_values = mux_config->n_values;
gpio_data.classes = mux_config->classes;
gpio_data.gpio_chip = mux_config->gpio_chip;
gpio_data.gpios = mux_config->gpios;
gpio_data.n_gpios = mux_config->n_gpios;
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
/* Register the mux device */
/* Register GPIO descriptor lookup table */
lookup = devm_kzalloc(dev,
struct_size(lookup, table, mux_config->n_gpios),
GFP_KERNEL);
if (!lookup)
return -ENOMEM;
lookup->dev_id = "i2c-mux-gpio";
for (i = 0; i < mux_config->n_gpios; i++) {
lookup->table[i].chip_label = mux_config->gpio_chip;
lookup->table[i].chip_hwnum = mux_config->gpios[i];
lookup->table[i].con_id = "mux";
}
gpiod_add_lookup_table(lookup);
priv->lookup = lookup;
/*
* Register the mux device, we use PLATFORM_DEVID_NONE here
* because since we are referring to the GPIO chip by name we are
* anyways in deep trouble if there is more than one of these
* devices, and there should likely only be one platform controller
* hub.
*/
priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
PLATFORM_DEVID_AUTO, &gpio_data,
PLATFORM_DEVID_NONE, &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);
gpiod_remove_lookup_table(lookup);
priv->mux_pdev = NULL;
dev_err(dev, "Failed to register i2c-mux-gpio device\n");
return err;
@ -1441,6 +1462,8 @@ static void i801_del_mux(struct i801_priv *priv)
{
if (priv->mux_pdev)
platform_device_unregister(priv->mux_pdev);
if (priv->lookup)
gpiod_remove_lookup_table(priv->lookup);
}
static unsigned int i801_get_adapter_class(struct i801_priv *priv)

View File

@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
@ -243,8 +244,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
{
struct i2c_mux_core *muxc;
muxc = devm_kzalloc(dev, sizeof(*muxc)
+ max_adapters * sizeof(muxc->adapter[0])
muxc = devm_kzalloc(dev, struct_size(muxc, adapter, max_adapters)
+ sizeof_priv, GFP_KERNEL);
if (!muxc)
return NULL;

View File

@ -15,12 +15,11 @@
*/
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -28,22 +27,16 @@
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
* @our_gpio: GPIO we'll use to claim.
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
* @their_gpio: GPIO that the other side will use to claim.
* @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
* @our_gpio: GPIO descriptor we'll use to claim.
* @their_gpio: GPIO descriptor that the other side will use to claim.
* @slew_delay_us: microseconds to wait for a GPIO to go high.
* @wait_retry_us: we'll attempt another claim after this many microseconds.
* @wait_free_us: we'll give up after this many microseconds.
*/
struct i2c_arbitrator_data {
int our_gpio;
int our_gpio_release;
int their_gpio;
int their_gpio_release;
struct gpio_desc *our_gpio;
struct gpio_desc *their_gpio;
unsigned int slew_delay_us;
unsigned int wait_retry_us;
unsigned int wait_free_us;
@ -64,15 +57,15 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
do {
/* Indicate that we want to claim the bus */
gpio_set_value(arb->our_gpio, !arb->our_gpio_release);
gpiod_set_value(arb->our_gpio, 1);
udelay(arb->slew_delay_us);
/* Wait for the other master to release it */
stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
while (time_before(jiffies, stop_retry)) {
int gpio_val = !!gpio_get_value(arb->their_gpio);
int gpio_val = gpiod_get_value(arb->their_gpio);
if (gpio_val == arb->their_gpio_release) {
if (!gpio_val) {
/* We got it, so return */
return 0;
}
@ -81,13 +74,13 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
}
/* It didn't release, so give up, wait, and try again */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
gpiod_set_value(arb->our_gpio, 0);
usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
} while (time_before(jiffies, stop_time));
/* Give up, release our claim */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
dev_err(muxc->dev, "Could not claim bus, timeout\n");
return -EBUSY;
@ -103,7 +96,7 @@ static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
/* Release the bus and wait for the other master to notice */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
return 0;
@ -116,8 +109,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device_node *parent_np;
struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb;
enum of_gpio_flags gpio_flags;
unsigned long out_init;
struct gpio_desc *dummy;
int ret;
/* We only support probing from device tree; no platform_data */
@ -138,45 +130,28 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, muxc);
/* Request GPIOs */
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
if (!gpio_is_valid(ret)) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error getting our-claim-gpio\n");
return ret;
}
arb->our_gpio = ret;
arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
ret = devm_gpio_request_one(dev, arb->our_gpio, out_init,
"our-claim-gpio");
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error requesting our-claim-gpio\n");
return ret;
/* Request GPIOs, our GPIO as unclaimed to begin with */
arb->our_gpio = devm_gpiod_get(dev, "our-claim", GPIOD_OUT_LOW);
if (IS_ERR(arb->our_gpio)) {
dev_err(dev, "could not get \"our-claim\" GPIO (%ld)\n",
PTR_ERR(arb->our_gpio));
return PTR_ERR(arb->our_gpio);
}
ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags);
if (!gpio_is_valid(ret)) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error getting their-claim-gpio\n");
return ret;
}
arb->their_gpio = ret;
arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN,
"their-claim-gpio");
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error requesting their-claim-gpio\n");
return ret;
arb->their_gpio = devm_gpiod_get(dev, "their-claim", GPIOD_IN);
if (IS_ERR(arb->their_gpio)) {
dev_err(dev, "could not get \"their-claim\" GPIO (%ld)\n",
PTR_ERR(arb->their_gpio));
return PTR_ERR(arb->their_gpio);
}
/* At the moment we only support a single two master (us + 1 other) */
if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) {
dummy = devm_gpiod_get_index(dev, "their-claim", 1, GPIOD_IN);
if (!IS_ERR(dummy)) {
dev_err(dev, "Only one other master is supported\n");
return -EINVAL;
} else if (PTR_ERR(dummy) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
}
/* Arbitration parameters */

View File

@ -14,13 +14,14 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/bits.h>
#include <linux/gpio/consumer.h>
/* FIXME: stop poking around inside gpiolib */
#include "../../gpio/gpiolib.h"
#include <linux/of_gpio.h>
struct gpiomux {
struct i2c_mux_gpio_platform_data data;
unsigned gpio_base;
int ngpios;
struct gpio_desc **gpios;
};
@ -30,8 +31,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
values[0] = val;
gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
values);
gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values);
}
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
@ -52,12 +52,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
static int match_gpio_chip_by_label(struct gpio_chip *chip,
void *data)
{
return !strcmp(chip->label, data);
}
#ifdef CONFIG_OF
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
@ -65,8 +59,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
unsigned *values, *gpios;
int i = 0, ret;
unsigned *values;
int i = 0;
if (!np)
return -ENODEV;
@ -103,29 +97,6 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
if (of_property_read_u32(np, "idle-state", &mux->data.idle))
mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios");
if (mux->data.n_gpios < 0) {
dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n");
return -EINVAL;
}
gpios = devm_kcalloc(&pdev->dev,
mux->data.n_gpios, sizeof(*mux->data.gpios),
GFP_KERNEL);
if (!gpios) {
dev_err(&pdev->dev, "Cannot allocate gpios array");
return -ENOMEM;
}
for (i = 0; i < mux->data.n_gpios; i++) {
ret = of_get_named_gpio(np, "mux-gpios", i);
if (ret < 0)
return ret;
gpios[i] = ret;
}
mux->data.gpios = gpios;
return 0;
}
#else
@ -142,8 +113,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
struct gpiomux *mux;
struct i2c_adapter *parent;
struct i2c_adapter *root;
unsigned initial_state, gpio_base;
int i, ret;
unsigned initial_state;
int i, ngpios, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
@ -158,29 +129,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
sizeof(mux->data));
}
/*
* If a GPIO chip name is provided, the GPIO pin numbers provided are
* relative to its base GPIO number. Otherwise they are absolute.
*/
if (mux->data.gpio_chip) {
struct gpio_chip *gpio;
gpio = gpiochip_find(mux->data.gpio_chip,
match_gpio_chip_by_label);
if (!gpio)
return -EPROBE_DEFER;
gpio_base = gpio->base;
} else {
gpio_base = 0;
ngpios = gpiod_count(&pdev->dev, "mux");
if (ngpios <= 0) {
dev_err(&pdev->dev, "no valid gpios provided\n");
return ngpios ?: -EINVAL;
}
mux->ngpios = ngpios;
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
mux->data.n_gpios * sizeof(*mux->gpios), 0,
ngpios * sizeof(*mux->gpios), 0,
i2c_mux_gpio_select, NULL);
if (!muxc) {
ret = -ENOMEM;
@ -194,7 +155,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
root = i2c_root_adapter(&parent->dev);
muxc->mux_locked = true;
mux->gpio_base = gpio_base;
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
@ -203,34 +163,28 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
initial_state = mux->data.values[0];
}
for (i = 0; i < mux->data.n_gpios; i++) {
for (i = 0; i < ngpios; i++) {
struct device *gpio_dev;
struct gpio_desc *gpio_desc;
struct gpio_desc *gpiod;
enum gpiod_flags flag;
ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n",
mux->data.gpios[i]);
goto err_request_gpio;
if (initial_state & BIT(i))
flag = GPIOD_OUT_HIGH;
else
flag = GPIOD_OUT_LOW;
gpiod = devm_gpiod_get_index(&pdev->dev, "mux", i, flag);
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
goto alloc_failed;
}
ret = gpio_direction_output(gpio_base + mux->data.gpios[i],
initial_state & (1 << i));
if (ret) {
dev_err(&pdev->dev,
"Failed to set direction of GPIO %d to output\n",
mux->data.gpios[i]);
i++; /* gpio_request above succeeded, so must free */
goto err_request_gpio;
}
gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
mux->gpios[i] = gpio_desc;
mux->gpios[i] = gpiod;
if (!muxc->mux_locked)
continue;
gpio_dev = &gpio_desc->gdev->dev;
/* FIXME: find a proper way to access the GPIO device */
gpio_dev = &gpiod->gdev->dev;
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
}
@ -253,10 +207,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
add_adapter_failed:
i2c_mux_del_adapters(muxc);
i = mux->data.n_gpios;
err_request_gpio:
for (; i > 0; i--)
gpio_free(gpio_base + mux->data.gpios[i - 1]);
alloc_failed:
i2c_put_adapter(parent);
@ -266,14 +216,8 @@ alloc_failed:
static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
struct gpiomux *mux = i2c_mux_priv(muxc);
int i;
i2c_mux_del_adapters(muxc);
for (i = 0; i < mux->data.n_gpios; i++)
gpio_free(mux->gpio_base + mux->data.gpios[i]);
i2c_put_adapter(muxc->parent);
return 0;

View File

@ -27,7 +27,7 @@
struct i2c_mux_pinctrl {
struct pinctrl *pinctrl;
struct pinctrl_state **states;
struct pinctrl_state *states[];
};
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
@ -104,14 +104,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(parent);
muxc = i2c_mux_alloc(parent, dev, num_names,
sizeof(*mux) + num_names * sizeof(*mux->states),
struct_size(mux, states, num_names),
0, i2c_mux_pinctrl_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto err_put_parent;
}
mux = i2c_mux_priv(muxc);
mux->states = (struct pinctrl_state **)(mux + 1);
platform_set_drvdata(pdev, muxc);

View File

@ -22,10 +22,6 @@
* position
* @n_values: Number of multiplexer positions (busses to instantiate)
* @classes: Optional I2C auto-detection classes
* @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given
* relative to the base GPIO number of that chip
* @gpios: Array of GPIO numbers used to control MUX
* @n_gpios: Number of GPIOs used to control MUX
* @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
*/
struct i2c_mux_gpio_platform_data {
@ -34,9 +30,6 @@ struct i2c_mux_gpio_platform_data {
const unsigned *values;
int n_values;
const unsigned *classes;
char *gpio_chip;
const unsigned *gpios;
int n_gpios;
unsigned idle;
};