From nobody Sun Nov 24 01:37:20 2024 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3235B19750B; Mon, 18 Nov 2024 10:13:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731924804; cv=none; b=eb/oTfb3IOZgf3/T5CDRP4qkvzTjKJHdZpQQVi447lvCE8Npqv/mV7iAbLAErfp/Rn+Omn49n7uhWGZ2Qjoz9ukjckshNkOA2wHOBlrYACj0RXibw51zt6cFv7rajaRBmA3/Se/yaKyV87LMDWz9qfdf23BUoQiNfajvige9Q+0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731924804; c=relaxed/simple; bh=PGesAr6Cw9Hdn+1PvTh4nOqXk2JX6YrH15uSEM3L1hw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Bfx/+FYQM+uh9HCyRHuAli/H9vRFqY9ghpyGKHRV1rBBaQtCbURx4QVFe56FwUFO7fM81ZlQF5d+x1vkoi/IhKJwYchn+NHFc/bPFsZlAjVP1KB3zhZR6Tk0PzreLCWgiZX5SqI61fqQTI7jqkx++CgqG/fQkvBi9xvBywA7zY8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=XWiEFEFp; arc=none smtp.client-ip=217.70.183.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="XWiEFEFp" Received: by mail.gandi.net (Postfix) with ESMTPSA id 515EF1BF20D; Mon, 18 Nov 2024 10:13:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1731924799; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SjvACWeOBtIlxQ+9E7kITjN5s4TisAetZ11z5E/CII4=; b=XWiEFEFpZr8jfg3jiomMszjzPpmcAHtAR8/dZXhYhN0eQKTzty7jBnppgpvi1Mi124ysOb 3OlWAt3vsniYykvtR5UWtyhXM6HAkB5GHrFToXurNQQY1kZwr/Wz8JOeXFz8plgEkedotm rAWvg5wexiuwm6iJ3zDtbyAg088tpDGVwuVS15Gfs9LBbN4DjKAFCN5J2PhNtyIc/3gsa/ P6SskMtybg2LHRQzKJKbvHoi3xUFLjjakyCngblTdoG8tcXvNiU9q1J3FFnGYkb3fF5ZaU H6jFXvBXdUJyXhXcbboiFz/6N8RqtOUZbstfHc7lpzNRwQJlHrs2CXxGm+wW+Q== From: Romain Gantois Date: Mon, 18 Nov 2024 11:13:06 +0100 Subject: [PATCH v2 7/9] i2c: support per-channel ATR alias pools Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241118-fpc202-v2-7-744e4f192a2d@bootlin.com> References: <20241118-fpc202-v2-0-744e4f192a2d@bootlin.com> In-Reply-To: <20241118-fpc202-v2-0-744e4f192a2d@bootlin.com> To: Wolfram Sang , Tomi Valkeinen , Luca Ceresoli , Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Derek Kiernan , Dragan Cvetic , Arnd Bergmann , Greg Kroah-Hartman , Mauro Carvalho Chehab , Linus Walleij , Bartosz Golaszewski Cc: Thomas Petazzoni , Kory Maincent , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-media@vger.kernel.org, linux-gpio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.2 X-GND-Sasl: romain.gantois@bootlin.com Some I2C address translators (ATRs) assign each of their remote peripheral aliases to a specific channel. To properly handle these devices, add support for having separate alias pools for each ATR channel. This is achieved by allowing callers of i2c_atr_add_adapter to pass an optional alias list. If present, this list will be used to populate the channel's alias pool. Otherwise, the common alias pool will be used. Signed-off-by: Romain Gantois --- drivers/i2c/i2c-atr.c | 68 ++++++++++++++++++++++++++++++---------= ---- drivers/media/i2c/ds90ub913.c | 9 ++++-- drivers/media/i2c/ds90ub953.c | 9 ++++-- include/linux/i2c-atr.h | 34 ++++++++++++++++------ 4 files changed, 87 insertions(+), 33 deletions(-) diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c index 84d82c09708ae39cf5501a1fb67e8f2af2bb5446..f7c4d39ad3b48ad64be25b84623= 94e569aee57d4 100644 --- a/drivers/i2c/i2c-atr.c +++ b/drivers/i2c/i2c-atr.c @@ -37,6 +37,7 @@ struct i2c_atr_alias_pair { /** * struct i2c_atr_alias_pool - Pool of client aliases available for an ATR. * @size: Total number of aliases + * @shared: Indicates if this alias pool is shared by multiple channels * * @lock: Lock protecting @aliases and @use_mask * @aliases: Array of aliases, must hold exactly @size elements @@ -44,6 +45,7 @@ struct i2c_atr_alias_pair { */ struct i2c_atr_alias_pool { size_t size; + bool shared; =20 /* Protects aliases and use_mask */ spinlock_t lock; @@ -58,6 +60,8 @@ struct i2c_atr_alias_pool { * @chan_id: The ID of this channel * @alias_pairs: List of @struct i2c_atr_alias_pair containing the * assigned aliases + * @alias_pool: Pool of available client aliases + * * @orig_addrs_lock: Mutex protecting @orig_addrs * @orig_addrs: Buffer used to store the original addresses during tr= ansmit * @orig_addrs_size: Size of @orig_addrs @@ -68,6 +72,7 @@ struct i2c_atr_chan { u32 chan_id; =20 struct list_head alias_pairs; + struct i2c_atr_alias_pool *alias_pool; =20 /* Lock orig_addrs during xfer */ struct mutex orig_addrs_lock; @@ -84,7 +89,7 @@ struct i2c_atr_chan { * @algo: The &struct i2c_algorithm for adapters * @lock: Lock for the I2C bus segment (see &struct i2c_lock_operatio= ns) * @max_adapters: Maximum number of adapters this I2C ATR can have - * @alias_pool: Pool of available client aliases + * @alias_pool: Optional common pool of available client aliases * @i2c_nb: Notifier for remote client add & del events * @adapter: Array of adapters */ @@ -357,7 +362,7 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adap= ter, u16 alias; int ret; =20 - ret =3D i2c_atr_reserve_alias(atr->alias_pool); + ret =3D i2c_atr_reserve_alias(chan->alias_pool); if (ret < 0) { dev_err(atr->dev, "failed to find a free alias\n"); return ret; @@ -387,7 +392,7 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adap= ter, err_free: kfree(c2a); err_release_alias: - i2c_atr_release_alias(atr->alias_pool, alias); + i2c_atr_release_alias(chan->alias_pool, alias); =20 return ret; } @@ -408,7 +413,7 @@ static void i2c_atr_detach_addr(struct i2c_adapter *ada= pter, return; } =20 - i2c_atr_release_alias(atr->alias_pool, c2a->alias); + i2c_atr_release_alias(chan->alias_pool, c2a->alias); =20 dev_dbg(atr->dev, "chan%u: addr 0x%02x unmapped from alias 0x%02x\n", @@ -469,14 +474,18 @@ static int i2c_atr_parse_alias_pool(struct i2c_atr *a= tr) u32 *aliases32; int ret; =20 - ret =3D fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool"); - if (ret < 0) { - dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n", - ret); - return ret; - } + if (!fwnode_property_present(dev_fwnode(dev), "i2c-alias-pool")) { + num_aliases =3D 0; + } else { + ret =3D fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool"); + if (ret < 0) { + dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n", + ret); + return ret; + } =20 - num_aliases =3D ret; + num_aliases =3D ret; + } =20 alias_pool =3D i2c_atr_alloc_alias_pool(num_aliases); if (IS_ERR(alias_pool)) { @@ -592,15 +601,15 @@ void i2c_atr_delete(struct i2c_atr *atr) } EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, I2C_ATR); =20 -int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, - struct device *adapter_parent, - struct fwnode_handle *bus_handle) +int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *des= c) { + struct fwnode_handle *bus_handle =3D desc->bus_handle; struct i2c_adapter *parent =3D atr->parent; + char symlink_name[ATR_MAX_SYMLINK_LEN]; struct device *dev =3D atr->dev; + u32 chan_id =3D desc->chan_id; struct i2c_atr_chan *chan; - char symlink_name[ATR_MAX_SYMLINK_LEN]; - int ret; + int ret, idx; =20 if (chan_id >=3D atr->max_adapters) { dev_err(dev, "No room for more i2c-atr adapters\n"); @@ -616,8 +625,8 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_i= d, if (!chan) return -ENOMEM; =20 - if (!adapter_parent) - adapter_parent =3D dev; + if (!desc->parent) + desc->parent =3D dev; =20 chan->atr =3D atr; chan->chan_id =3D chan_id; @@ -629,7 +638,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_i= d, chan->adap.owner =3D THIS_MODULE; chan->adap.algo =3D &atr->algo; chan->adap.algo_data =3D chan; - chan->adap.dev.parent =3D adapter_parent; + chan->adap.dev.parent =3D desc->parent; chan->adap.retries =3D parent->retries; chan->adap.timeout =3D parent->timeout; chan->adap.quirks =3D parent->quirks; @@ -656,13 +665,26 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan= _id, fwnode_handle_put(atr_node); } =20 + if (desc->num_aliases > 0) { + chan->alias_pool =3D i2c_atr_alloc_alias_pool(desc->num_aliases); + if (IS_ERR(chan->alias_pool)) { + ret =3D PTR_ERR(chan->alias_pool); + goto err_fwnode_put; + } + + for (idx =3D 0; idx < desc->num_aliases; idx++) + chan->alias_pool->aliases[idx] =3D desc->aliases[idx]; + } else { + chan->alias_pool =3D atr->alias_pool; + } + atr->adapter[chan_id] =3D &chan->adap; =20 ret =3D i2c_add_adapter(&chan->adap); if (ret) { dev_err(dev, "failed to add atr-adapter %u (error=3D%d)\n", chan_id, ret); - goto err_fwnode_put; + goto err_free_alias_pool; } =20 snprintf(symlink_name, sizeof(symlink_name), "channel-%u", @@ -679,6 +701,9 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_i= d, =20 return 0; =20 +err_free_alias_pool: + if (!chan->alias_pool->shared) + i2c_atr_free_alias_pool(chan->alias_pool); err_fwnode_put: fwnode_handle_put(dev_fwnode(&chan->adap.dev)); mutex_destroy(&chan->orig_addrs_lock); @@ -711,6 +736,9 @@ void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_= id) =20 i2c_del_adapter(adap); =20 + if (!chan->alias_pool->shared) + i2c_atr_free_alias_pool(chan->alias_pool); + atr->adapter[chan_id] =3D NULL; =20 fwnode_handle_put(fwnode); diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 8eed4a200fd89b5af1fc4578cb865bf1408acd76..1bb4efa44ede1267e15d29e0ce3= 965372bf3bb89 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -656,6 +656,7 @@ static int ub913_i2c_master_init(struct ub913_data *pri= v) static int ub913_add_i2c_adapter(struct ub913_data *priv) { struct device *dev =3D &priv->client->dev; + struct i2c_atr_adap_desc desc =3D { }; struct fwnode_handle *i2c_handle; int ret; =20 @@ -663,8 +664,12 @@ static int ub913_add_i2c_adapter(struct ub913_data *pr= iv) if (!i2c_handle) return 0; =20 - ret =3D i2c_atr_add_adapter(priv->plat_data->atr, priv->plat_data->port, - dev, i2c_handle); + desc.chan_id =3D priv->plat_data->port; + desc.parent =3D dev; + desc.bus_handle =3D i2c_handle; + desc.num_aliases =3D 0; + + ret =3D i2c_atr_add_adapter(priv->plat_data->atr, &desc); =20 fwnode_handle_put(i2c_handle); =20 diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 16f88db1498162cb795b1dcbe45bff90dd8ce431..e7cdb5d07a0378eab7aeeba36af= dec319565c110 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -1103,6 +1103,7 @@ static int ub953_register_clkout(struct ub953_data *p= riv) static int ub953_add_i2c_adapter(struct ub953_data *priv) { struct device *dev =3D &priv->client->dev; + struct i2c_atr_adap_desc desc =3D { }; struct fwnode_handle *i2c_handle; int ret; =20 @@ -1110,8 +1111,12 @@ static int ub953_add_i2c_adapter(struct ub953_data *= priv) if (!i2c_handle) return 0; =20 - ret =3D i2c_atr_add_adapter(priv->plat_data->atr, priv->plat_data->port, - dev, i2c_handle); + desc.chan_id =3D priv->plat_data->port; + desc.parent =3D dev; + desc.bus_handle =3D i2c_handle; + desc.num_aliases =3D 0; + + ret =3D i2c_atr_add_adapter(priv->plat_data->atr, &desc); =20 fwnode_handle_put(i2c_handle); =20 diff --git a/include/linux/i2c-atr.h b/include/linux/i2c-atr.h index 14c1f9175c0db6a8a9c6ef5d771ae68361132a76..1c3a5bcd939fc56f4a6ca1b6a5c= c0ac2c17083b7 100644 --- a/include/linux/i2c-atr.h +++ b/include/linux/i2c-atr.h @@ -36,6 +36,29 @@ struct i2c_atr_ops { u16 addr); }; =20 +/** + * struct i2c_atr_adap_desc - An ATR downstream bus descriptor + * @chan_id: Index of the new adapter (0 .. max_adapters-1). This = value is + * passed to the callbacks in `struct i2c_atr_ops`. + * @parent: The device used as the parent of the new i2c adapter, = or NULL + * to use the i2c-atr device as the parent. + * @bus_handle: The fwnode handle that points to the adapter's i2c + * peripherals, or NULL. + * @num_aliases: The number of aliases in this adapter's private alias = pool. Set + * to zero if this adapter uses the ATR's global alias po= ol. + * @aliases: An optional array of private aliases used by the adapt= er + * instead of the ATR's global pool of aliases. Must cont= ain + * exactly num_aliases entries if num_aliases > 0, is ign= ored + * otherwise. + */ +struct i2c_atr_adap_desc { + u32 chan_id; + struct device *parent; + struct fwnode_handle *bus_handle; + size_t num_aliases; + u16 *aliases; +}; + /** * i2c_atr_new() - Allocate and initialize an I2C ATR helper. * @parent: The parent (upstream) adapter @@ -65,12 +88,7 @@ void i2c_atr_delete(struct i2c_atr *atr); /** * i2c_atr_add_adapter - Create a child ("downstream") I2C bus. * @atr: The I2C ATR - * @chan_id: Index of the new adapter (0 .. max_adapters-1). This valu= e is - * passed to the callbacks in `struct i2c_atr_ops`. - * @adapter_parent: The device used as the parent of the new i2c adapter, = or NULL - * to use the i2c-atr device as the parent. - * @bus_handle: The fwnode handle that points to the adapter's i2c - * peripherals, or NULL. + * @desc: An ATR adapter descriptor * * After calling this function a new i2c bus will appear. Adding and remov= ing * devices on the downstream bus will result in calls to the @@ -85,9 +103,7 @@ void i2c_atr_delete(struct i2c_atr *atr); * * Return: 0 on success, a negative error code otherwise. */ -int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, - struct device *adapter_parent, - struct fwnode_handle *bus_handle); +int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *des= c); =20 /** * i2c_atr_del_adapter - Remove a child ("downstream") I2C bus added by --=20 2.47.0