Skip to content

Commit 328a106

Browse files
rgantoisWolfram Sang
authored andcommitted
i2c: support per-channel ATR alias pools
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. Tested-by: Tomi Valkeinen <[email protected]> Signed-off-by: Romain Gantois <[email protected]> Acked-by: Andi Shyti <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent db1962c commit 328a106

File tree

4 files changed

+91
-35
lines changed

4 files changed

+91
-35
lines changed

drivers/i2c/i2c-atr.c

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ struct i2c_atr_alias_pair {
3737
/**
3838
* struct i2c_atr_alias_pool - Pool of client aliases available for an ATR.
3939
* @size: Total number of aliases
40+
* @shared: Indicates if this alias pool is shared by multiple channels
4041
*
4142
* @lock: Lock protecting @aliases and @use_mask
4243
* @aliases: Array of aliases, must hold exactly @size elements
4344
* @use_mask: Mask of used aliases
4445
*/
4546
struct i2c_atr_alias_pool {
4647
size_t size;
48+
bool shared;
4749

4850
/* Protects aliases and use_mask */
4951
spinlock_t lock;
@@ -58,6 +60,8 @@ struct i2c_atr_alias_pool {
5860
* @chan_id: The ID of this channel
5961
* @alias_pairs: List of @struct i2c_atr_alias_pair containing the
6062
* assigned aliases
63+
* @alias_pool: Pool of available client aliases
64+
*
6165
* @orig_addrs_lock: Mutex protecting @orig_addrs
6266
* @orig_addrs: Buffer used to store the original addresses during transmit
6367
* @orig_addrs_size: Size of @orig_addrs
@@ -68,6 +72,7 @@ struct i2c_atr_chan {
6872
u32 chan_id;
6973

7074
struct list_head alias_pairs;
75+
struct i2c_atr_alias_pool *alias_pool;
7176

7277
/* Lock orig_addrs during xfer */
7378
struct mutex orig_addrs_lock;
@@ -84,7 +89,7 @@ struct i2c_atr_chan {
8489
* @algo: The &struct i2c_algorithm for adapters
8590
* @lock: Lock for the I2C bus segment (see &struct i2c_lock_operations)
8691
* @max_adapters: Maximum number of adapters this I2C ATR can have
87-
* @alias_pool: Pool of available client aliases
92+
* @alias_pool: Optional common pool of available client aliases
8893
* @i2c_nb: Notifier for remote client add & del events
8994
* @adapter: Array of adapters
9095
*/
@@ -107,7 +112,7 @@ struct i2c_atr {
107112
struct i2c_adapter *adapter[] __counted_by(max_adapters);
108113
};
109114

110-
static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases)
115+
static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases, bool shared)
111116
{
112117
struct i2c_atr_alias_pool *alias_pool;
113118
int ret;
@@ -130,6 +135,8 @@ static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases)
130135
goto err_free_aliases;
131136
}
132137

138+
alias_pool->shared = shared;
139+
133140
spin_lock_init(&alias_pool->lock);
134141

135142
return alias_pool;
@@ -357,7 +364,7 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adapter,
357364
u16 alias;
358365
int ret;
359366

360-
ret = i2c_atr_reserve_alias(atr->alias_pool);
367+
ret = i2c_atr_reserve_alias(chan->alias_pool);
361368
if (ret < 0) {
362369
dev_err(atr->dev, "failed to find a free alias\n");
363370
return ret;
@@ -387,7 +394,7 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adapter,
387394
err_free:
388395
kfree(c2a);
389396
err_release_alias:
390-
i2c_atr_release_alias(atr->alias_pool, alias);
397+
i2c_atr_release_alias(chan->alias_pool, alias);
391398

392399
return ret;
393400
}
@@ -408,7 +415,7 @@ static void i2c_atr_detach_addr(struct i2c_adapter *adapter,
408415
return;
409416
}
410417

411-
i2c_atr_release_alias(atr->alias_pool, c2a->alias);
418+
i2c_atr_release_alias(chan->alias_pool, c2a->alias);
412419

413420
dev_dbg(atr->dev,
414421
"chan%u: detached alias 0x%02x from addr 0x%02x\n",
@@ -469,16 +476,20 @@ static int i2c_atr_parse_alias_pool(struct i2c_atr *atr)
469476
u32 *aliases32;
470477
int ret;
471478

472-
ret = fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool");
473-
if (ret < 0) {
474-
dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n",
475-
ret);
476-
return ret;
477-
}
479+
if (!fwnode_property_present(dev_fwnode(dev), "i2c-alias-pool")) {
480+
num_aliases = 0;
481+
} else {
482+
ret = fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool");
483+
if (ret < 0) {
484+
dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n",
485+
ret);
486+
return ret;
487+
}
478488

479-
num_aliases = ret;
489+
num_aliases = ret;
490+
}
480491

481-
alias_pool = i2c_atr_alloc_alias_pool(num_aliases);
492+
alias_pool = i2c_atr_alloc_alias_pool(num_aliases, true);
482493
if (IS_ERR(alias_pool)) {
483494
ret = PTR_ERR(alias_pool);
484495
dev_err(dev, "Failed to allocate alias pool, err %d\n", ret);
@@ -592,15 +603,15 @@ void i2c_atr_delete(struct i2c_atr *atr)
592603
}
593604
EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, "I2C_ATR");
594605

595-
int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
596-
struct device *adapter_parent,
597-
struct fwnode_handle *bus_handle)
606+
int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc)
598607
{
608+
struct fwnode_handle *bus_handle = desc->bus_handle;
599609
struct i2c_adapter *parent = atr->parent;
610+
char symlink_name[ATR_MAX_SYMLINK_LEN];
600611
struct device *dev = atr->dev;
612+
u32 chan_id = desc->chan_id;
601613
struct i2c_atr_chan *chan;
602-
char symlink_name[ATR_MAX_SYMLINK_LEN];
603-
int ret;
614+
int ret, idx;
604615

605616
if (chan_id >= atr->max_adapters) {
606617
dev_err(dev, "No room for more i2c-atr adapters\n");
@@ -616,8 +627,8 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
616627
if (!chan)
617628
return -ENOMEM;
618629

619-
if (!adapter_parent)
620-
adapter_parent = dev;
630+
if (!desc->parent)
631+
desc->parent = dev;
621632

622633
chan->atr = atr;
623634
chan->chan_id = chan_id;
@@ -629,7 +640,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
629640
chan->adap.owner = THIS_MODULE;
630641
chan->adap.algo = &atr->algo;
631642
chan->adap.algo_data = chan;
632-
chan->adap.dev.parent = adapter_parent;
643+
chan->adap.dev.parent = desc->parent;
633644
chan->adap.retries = parent->retries;
634645
chan->adap.timeout = parent->timeout;
635646
chan->adap.quirks = parent->quirks;
@@ -656,13 +667,26 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
656667
fwnode_handle_put(atr_node);
657668
}
658669

670+
if (desc->num_aliases > 0) {
671+
chan->alias_pool = i2c_atr_alloc_alias_pool(desc->num_aliases, false);
672+
if (IS_ERR(chan->alias_pool)) {
673+
ret = PTR_ERR(chan->alias_pool);
674+
goto err_fwnode_put;
675+
}
676+
677+
for (idx = 0; idx < desc->num_aliases; idx++)
678+
chan->alias_pool->aliases[idx] = desc->aliases[idx];
679+
} else {
680+
chan->alias_pool = atr->alias_pool;
681+
}
682+
659683
atr->adapter[chan_id] = &chan->adap;
660684

661685
ret = i2c_add_adapter(&chan->adap);
662686
if (ret) {
663687
dev_err(dev, "failed to add atr-adapter %u (error=%d)\n",
664688
chan_id, ret);
665-
goto err_fwnode_put;
689+
goto err_free_alias_pool;
666690
}
667691

668692
snprintf(symlink_name, sizeof(symlink_name), "channel-%u",
@@ -679,6 +703,9 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
679703

680704
return 0;
681705

706+
err_free_alias_pool:
707+
if (!chan->alias_pool->shared)
708+
i2c_atr_free_alias_pool(chan->alias_pool);
682709
err_fwnode_put:
683710
fwnode_handle_put(dev_fwnode(&chan->adap.dev));
684711
mutex_destroy(&chan->orig_addrs_lock);
@@ -711,6 +738,9 @@ void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id)
711738

712739
i2c_del_adapter(adap);
713740

741+
if (!chan->alias_pool->shared)
742+
i2c_atr_free_alias_pool(chan->alias_pool);
743+
714744
atr->adapter[chan_id] = NULL;
715745

716746
fwnode_handle_put(fwnode);

drivers/media/i2c/ds90ub913.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,15 +670,20 @@ static int ub913_i2c_master_init(struct ub913_data *priv)
670670
static int ub913_add_i2c_adapter(struct ub913_data *priv)
671671
{
672672
struct device *dev = &priv->client->dev;
673+
struct i2c_atr_adap_desc desc = { };
673674
struct fwnode_handle *i2c_handle;
674675
int ret;
675676

676677
i2c_handle = device_get_named_child_node(dev, "i2c");
677678
if (!i2c_handle)
678679
return 0;
679680

680-
ret = i2c_atr_add_adapter(priv->plat_data->atr, priv->plat_data->port,
681-
dev, i2c_handle);
681+
desc.chan_id = priv->plat_data->port;
682+
desc.parent = dev;
683+
desc.bus_handle = i2c_handle;
684+
desc.num_aliases = 0;
685+
686+
ret = i2c_atr_add_adapter(priv->plat_data->atr, &desc);
682687

683688
fwnode_handle_put(i2c_handle);
684689

drivers/media/i2c/ds90ub953.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,15 +1122,20 @@ static int ub953_register_clkout(struct ub953_data *priv)
11221122
static int ub953_add_i2c_adapter(struct ub953_data *priv)
11231123
{
11241124
struct device *dev = &priv->client->dev;
1125+
struct i2c_atr_adap_desc desc = { };
11251126
struct fwnode_handle *i2c_handle;
11261127
int ret;
11271128

11281129
i2c_handle = device_get_named_child_node(dev, "i2c");
11291130
if (!i2c_handle)
11301131
return 0;
11311132

1132-
ret = i2c_atr_add_adapter(priv->plat_data->atr, priv->plat_data->port,
1133-
dev, i2c_handle);
1133+
desc.chan_id = priv->plat_data->port;
1134+
desc.parent = dev;
1135+
desc.bus_handle = i2c_handle;
1136+
desc.num_aliases = 0;
1137+
1138+
ret = i2c_atr_add_adapter(priv->plat_data->atr, &desc);
11341139

11351140
fwnode_handle_put(i2c_handle);
11361141

include/linux/i2c-atr.h

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ struct i2c_atr_ops {
3636
u16 addr);
3737
};
3838

39+
/**
40+
* struct i2c_atr_adap_desc - An ATR downstream bus descriptor
41+
* @chan_id: Index of the new adapter (0 .. max_adapters-1). This value is
42+
* passed to the callbacks in `struct i2c_atr_ops`.
43+
* @parent: The device used as the parent of the new i2c adapter, or NULL
44+
* to use the i2c-atr device as the parent.
45+
* @bus_handle: The fwnode handle that points to the adapter's i2c
46+
* peripherals, or NULL.
47+
* @num_aliases: The number of aliases in this adapter's private alias pool. Set
48+
* to zero if this adapter uses the ATR's global alias pool.
49+
* @aliases: An optional array of private aliases used by the adapter
50+
* instead of the ATR's global pool of aliases. Must contain
51+
* exactly num_aliases entries if num_aliases > 0, is ignored
52+
* otherwise.
53+
*/
54+
struct i2c_atr_adap_desc {
55+
u32 chan_id;
56+
struct device *parent;
57+
struct fwnode_handle *bus_handle;
58+
size_t num_aliases;
59+
u16 *aliases;
60+
};
61+
3962
/**
4063
* i2c_atr_new() - Allocate and initialize an I2C ATR helper.
4164
* @parent: The parent (upstream) adapter
@@ -65,12 +88,7 @@ void i2c_atr_delete(struct i2c_atr *atr);
6588
/**
6689
* i2c_atr_add_adapter - Create a child ("downstream") I2C bus.
6790
* @atr: The I2C ATR
68-
* @chan_id: Index of the new adapter (0 .. max_adapters-1). This value is
69-
* passed to the callbacks in `struct i2c_atr_ops`.
70-
* @adapter_parent: The device used as the parent of the new i2c adapter, or NULL
71-
* to use the i2c-atr device as the parent.
72-
* @bus_handle: The fwnode handle that points to the adapter's i2c
73-
* peripherals, or NULL.
91+
* @desc: An ATR adapter descriptor
7492
*
7593
* After calling this function a new i2c bus will appear. Adding and removing
7694
* devices on the downstream bus will result in calls to the
@@ -85,9 +103,7 @@ void i2c_atr_delete(struct i2c_atr *atr);
85103
*
86104
* Return: 0 on success, a negative error code otherwise.
87105
*/
88-
int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id,
89-
struct device *adapter_parent,
90-
struct fwnode_handle *bus_handle);
106+
int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc);
91107

92108
/**
93109
* i2c_atr_del_adapter - Remove a child ("downstream") I2C bus added by

0 commit comments

Comments
 (0)