diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index f4355b17bfbf..b7521b7ece37 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -18,9 +18,21 @@ #include #include +static LIST_HEAD(i2c_gpio_scl_list); +static DEFINE_MUTEX(i2c_gpio_scl_list_lock); +static struct lock_class_key i2c_gpio_scl_lock_key; + +struct i2c_gpio_scl_data { + struct fwnode_reference_args args; + struct gpio_desc *gpio; + struct rt_mutex lock; + struct list_head list; + refcount_t ref; +}; + struct i2c_gpio_private_data { struct gpio_desc *sda; - struct gpio_desc *scl; + struct i2c_gpio_scl_data *scl; struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; @@ -31,6 +43,11 @@ struct i2c_gpio_private_data { #endif }; +static inline struct i2c_gpio_private_data *adap_to_priv(struct i2c_adapter *adap) +{ + return container_of(adap, struct i2c_gpio_private_data, adap); +} + /* * Toggle SDA by changing the output value of the pin. This is only * valid for pins configured as open drain (i.e. setting the value @@ -53,7 +70,7 @@ static void i2c_gpio_setscl_val(void *data, int state) { struct i2c_gpio_private_data *priv = data; - gpiod_set_value_cansleep(priv->scl, state); + gpiod_set_value_cansleep(priv->scl->gpio, state); } static int i2c_gpio_getsda(void *data) @@ -67,9 +84,41 @@ static int i2c_gpio_getscl(void *data) { struct i2c_gpio_private_data *priv = data; - return gpiod_get_value_cansleep(priv->scl); + return gpiod_get_value_cansleep(priv->scl->gpio); } +static void i2c_gpio_lock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + /* Take care about adapter lock. See i2c_adapter_lock_bus() and others. */ + rt_mutex_lock_nested(&adap->bus_lock, i2c_adapter_depth(adap)); + rt_mutex_lock(&adap_to_priv(adap)->scl->lock); +} + +static int i2c_gpio_trylock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + if (!rt_mutex_trylock(&adap->bus_lock)) + return 0; + + if (!rt_mutex_trylock(&adap_to_priv(adap)->scl->lock)) { + rt_mutex_unlock(&adap->bus_lock); + return 0; + } + + return 1; +} + +static void i2c_gpio_unlock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + rt_mutex_unlock(&adap_to_priv(adap)->scl->lock); + rt_mutex_unlock(&adap->bus_lock); +} + +static const struct i2c_lock_operations i2c_gpio_lock_ops = { + .lock_bus = i2c_gpio_lock_bus, + .trylock_bus = i2c_gpio_trylock_bus, + .unlock_bus = i2c_gpio_unlock_bus, +}; + #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR #define setsda(bd, val) ((bd)->setsda((bd)->data, val)) @@ -165,14 +214,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv, irqreturn_t handler(int, void*)) { - int ret, irq = gpiod_to_irq(priv->scl); + int ret, irq = gpiod_to_irq(priv->scl->gpio); if (irq < 0) return irq; i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); - ret = gpiod_direction_input(priv->scl); + ret = gpiod_direction_input(priv->scl->gpio); if (ret) goto unlock; @@ -187,7 +236,7 @@ static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv, free_irq(irq, priv); output: - ret = gpiod_direction_output(priv->scl, 1) ?: ret; + ret = gpiod_direction_output(priv->scl->gpio, 1) ?: ret; unlock: i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); @@ -308,13 +357,17 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, struct gpio_desc *retdesc; int ret; - retdesc = devm_gpiod_get(dev, con_id, gflags); + /* + * Don't use resource-managed functions. SCL may be shared across adapters and has + * its own lifetime management. SDA uses the same path for consistency. + */ + retdesc = gpiod_get(dev, con_id, gflags); if (!IS_ERR(retdesc)) { dev_dbg(dev, "got GPIO from name %s\n", con_id); return retdesc; } - retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + retdesc = gpiod_get_index(dev, NULL, index, gflags); if (!IS_ERR(retdesc)) { dev_dbg(dev, "got GPIO from index %u\n", index); return retdesc; @@ -336,6 +389,134 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, return retdesc; } +static struct i2c_gpio_scl_data *i2c_gpio_create_scl(struct device *dev) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_reference_args args; + struct i2c_gpio_scl_data *scl; + bool sharable = false; + int ret; + + /* + * SCL gpios can be shared if they are defined in the devicetree and have at least one + * cell in addition to the phandle. This is usually the pin. To support complex designs + * with arbitrary of_xlate() mappings handle the node cells opaque. + */ + if (fwnode) { + ret = fwnode_property_get_reference_args(fwnode, "scl-gpios", + "#gpio-cells", 0, 0, &args); + if (ret) + /* try the ancient way */ + ret = fwnode_property_get_reference_args(fwnode, "gpios", + "#gpio-cells", 0, 1, &args); + + if (!ret) { + if (args.nargs >= 1) + sharable = true; + else + fwnode_handle_put(args.fwnode); + } + } + + scl = kzalloc(sizeof(*scl), GFP_KERNEL); + if (!scl) { + if (sharable) + fwnode_handle_put(args.fwnode); + return ERR_PTR(-ENOMEM); + } + + if (sharable) { + scl->args.fwnode = args.fwnode; + scl->args.nargs = args.nargs; + memcpy(scl->args.args, args.args, sizeof(args.args[0]) * args.nargs); + } + + rt_mutex_init(&scl->lock); + lockdep_set_class(&scl->lock, &i2c_gpio_scl_lock_key); + refcount_set(&scl->ref, 1); + + return scl; +} + +static void i2c_gpio_free_scl(struct i2c_gpio_scl_data *scl) +{ + if (scl->args.fwnode) + fwnode_handle_put(scl->args.fwnode); + kfree(scl); +} + +static bool i2c_gpio_scl_matches(struct i2c_gpio_scl_data *a, struct i2c_gpio_scl_data *b) +{ + if (!a->args.fwnode || !b->args.fwnode || + a->args.fwnode != b->args.fwnode || a->args.nargs != b->args.nargs) + return false; + + return memcmp(a->args.args, b->args.args, sizeof(a->args.args[0]) * a->args.nargs) == 0; +} + +/* + * Look up an existing or create a new shared SCL structure. Optimistic setup sequence always + * creates and tries to add a new entry to the list. This uses minimum locking and afterwards + * requests the GPIO without a lock held. Concurrent probes for the same SCL pin see the entry + * and do not race into a second gpiod_get(). Until everything is setup they terminate with + * -EPROBE_DEFER. + */ +static struct i2c_gpio_scl_data *i2c_gpio_lookup_scl(struct device *dev, enum gpiod_flags gflags) +{ + struct i2c_gpio_scl_data *scl, *new_scl; + struct gpio_desc *gpio; + + new_scl = i2c_gpio_create_scl(dev); + if (IS_ERR(new_scl)) + return new_scl; + + scoped_guard(mutex, &i2c_gpio_scl_list_lock) { + list_for_each_entry(scl, &i2c_gpio_scl_list, list) { + if (!i2c_gpio_scl_matches(scl, new_scl)) + continue; + + i2c_gpio_free_scl(new_scl); + if (!scl->gpio) + return ERR_PTR(-EPROBE_DEFER); + + refcount_inc(&scl->ref); + if (scl->args.fwnode) + dev_dbg(dev, "reusing shared SCL (%pfwP)\n", scl->args.fwnode); + + return scl; + } + list_add(&new_scl->list, &i2c_gpio_scl_list); + } + + gpio = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(gpio)) { + scoped_guard(mutex, &i2c_gpio_scl_list_lock) + list_del(&new_scl->list); + i2c_gpio_free_scl(new_scl); + + return ERR_CAST(gpio); + } + + scoped_guard(mutex, &i2c_gpio_scl_list_lock) + new_scl->gpio = gpio; + + if (new_scl->args.fwnode) + dev_dbg(dev, "registered shared SCL (%pfwP)\n", new_scl->args.fwnode); + + return new_scl; +} + +static void i2c_gpio_cleanup_scl(struct i2c_gpio_scl_data *scl) +{ + if (!refcount_dec_and_mutex_lock(&scl->ref, &i2c_gpio_scl_list_lock)) + return; + + list_del(&scl->list); + mutex_unlock(&i2c_gpio_scl_list_lock); + gpiod_put(scl->gpio); + i2c_gpio_free_scl(scl); +} + static int i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; @@ -386,15 +567,18 @@ static int i2c_gpio_probe(struct platform_device *pdev) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); - if (IS_ERR(priv->scl)) - return PTR_ERR(priv->scl); + priv->scl = i2c_gpio_lookup_scl(dev, gflags); + if (IS_ERR(priv->scl)) { + ret = PTR_ERR(priv->scl); + goto err_cleanup_sda; + } - if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl->gpio)) dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); else bit_data->can_do_atomic = true; + bit_data->skip_bit_test = !!priv->scl->args.fwnode; bit_data->setsda = i2c_gpio_setsda_val; bit_data->setscl = i2c_gpio_setscl_val; @@ -423,6 +607,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + /* Always use shared SCL aware locking */ + adap->lock_ops = &i2c_gpio_lock_ops; adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON; adap->dev.parent = dev; @@ -431,7 +617,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); if (ret) - return ret; + goto err_cleanup_scl; platform_set_drvdata(pdev, priv); @@ -441,13 +627,20 @@ static int i2c_gpio_probe(struct platform_device *pdev) * from the descriptor, then provide that instead. */ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", - desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl->gpio), pdata->scl_is_output_only ? ", no clock stretching" : ""); i2c_gpio_fault_injector_init(pdev); return 0; + +err_cleanup_scl: + i2c_gpio_cleanup_scl(priv->scl); +err_cleanup_sda: + gpiod_put(priv->sda); + + return ret; } static void i2c_gpio_remove(struct platform_device *pdev) @@ -459,6 +652,8 @@ static void i2c_gpio_remove(struct platform_device *pdev) adap = &priv->adap; i2c_del_adapter(adap); + i2c_gpio_cleanup_scl(priv->scl); + gpiod_put(priv->sda); } static const struct of_device_id i2c_gpio_dt_ids[] = {