Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: i2c: add I2C Address Translator (ATR) support

An ATR is a device that looks similar to an i2c-mux: it has an I2C
slave "upstream" port and N master "downstream" ports, and forwards
transactions from upstream to the appropriate downstream port. But it
is different in that the forwarded transaction has a different slave
address. The address used on the upstream bus is called the "alias"
and is (potentially) different from the physical slave address of the
downstream chip.

Add a helper file (just like i2c-mux.c for a mux or switch) to allow
implementing ATR features in a device driver. The helper takes care of
adapter creation/destruction and translates addresses at each transaction.

Signed-off-by: Luca Ceresoli <luca@lucaceresoli.net>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Wolfram Sang <wsa@kernel.org>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Luca Ceresoli and committed by
Mauro Carvalho Chehab
a076a860 86251cf8

+941
+96
Documentation/i2c/i2c-address-translators.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ======================= 4 + I2C Address Translators 5 + ======================= 6 + 7 + Author: Luca Ceresoli <luca@lucaceresoli.net> 8 + Author: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 9 + 10 + Description 11 + ----------- 12 + 13 + An I2C Address Translator (ATR) is a device with an I2C slave parent 14 + ("upstream") port and N I2C master child ("downstream") ports, and 15 + forwards transactions from upstream to the appropriate downstream port 16 + with a modified slave address. The address used on the parent bus is 17 + called the "alias" and is (potentially) different from the physical 18 + slave address of the child bus. Address translation is done by the 19 + hardware. 20 + 21 + An ATR looks similar to an i2c-mux except: 22 + - the address on the parent and child busses can be different 23 + - there is normally no need to select the child port; the alias used on the 24 + parent bus implies it 25 + 26 + The ATR functionality can be provided by a chip with many other features. 27 + The kernel i2c-atr provides a helper to implement an ATR within a driver. 28 + 29 + The ATR creates a new I2C "child" adapter on each child bus. Adding 30 + devices on the child bus ends up in invoking the driver code to select 31 + an available alias. Maintaining an appropriate pool of available aliases 32 + and picking one for each new device is up to the driver implementer. The 33 + ATR maintains a table of currently assigned alias and uses it to modify 34 + all I2C transactions directed to devices on the child buses. 35 + 36 + A typical example follows. 37 + 38 + Topology:: 39 + 40 + Slave X @ 0x10 41 + .-----. | 42 + .-----. | |---+---- B 43 + | CPU |--A--| ATR | 44 + `-----' | |---+---- C 45 + `-----' | 46 + Slave Y @ 0x10 47 + 48 + Alias table: 49 + 50 + A, B and C are three physical I2C busses, electrically independent from 51 + each other. The ATR receives the transactions initiated on bus A and 52 + propagates them on bus B or bus C or none depending on the device address 53 + in the transaction and based on the alias table. 54 + 55 + Alias table: 56 + 57 + .. table:: 58 + 59 + =============== ===== 60 + Client Alias 61 + =============== ===== 62 + X (bus B, 0x10) 0x20 63 + Y (bus C, 0x10) 0x30 64 + =============== ===== 65 + 66 + Transaction: 67 + 68 + - Slave X driver requests a transaction (on adapter B), slave address 0x10 69 + - ATR driver finds slave X is on bus B and has alias 0x20, rewrites 70 + messages with address 0x20, forwards to adapter A 71 + - Physical I2C transaction on bus A, slave address 0x20 72 + - ATR chip detects transaction on address 0x20, finds it in table, 73 + propagates transaction on bus B with address translated to 0x10, 74 + keeps clock streched on bus A waiting for reply 75 + - Slave X chip (on bus B) detects transaction at its own physical 76 + address 0x10 and replies normally 77 + - ATR chip stops clock stretching and forwards reply on bus A, 78 + with address translated back to 0x20 79 + - ATR driver receives the reply, rewrites messages with address 0x10 80 + as they were initially 81 + - Slave X driver gets back the msgs[], with reply and address 0x10 82 + 83 + Usage: 84 + 85 + 1. In the driver (typically in the probe function) add an ATR by 86 + calling i2c_atr_new() passing attach/detach callbacks 87 + 2. When the attach callback is called pick an appropriate alias, 88 + configure it in the chip and return the chosen alias in the 89 + alias_id parameter 90 + 3. When the detach callback is called, deconfigure the alias from 91 + the chip and put the alias back in the pool for later usage 92 + 93 + I2C ATR functions and data structures 94 + ------------------------------------- 95 + 96 + .. kernel-doc:: include/linux/i2c-atr.h
+1
Documentation/i2c/index.rst
··· 18 18 i2c-topology 19 19 muxes/i2c-mux-gpio 20 20 i2c-sysfs 21 + i2c-address-translators 21 22 22 23 Writing device drivers 23 24 ======================
+8
MAINTAINERS
··· 9670 9670 S: Maintained 9671 9671 F: drivers/i2c/i2c-core-acpi.c 9672 9672 9673 + I2C ADDRESS TRANSLATOR (ATR) 9674 + M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 9675 + R: Luca Ceresoli <luca.ceresoli@bootlin.com> 9676 + L: linux-i2c@vger.kernel.org 9677 + S: Maintained 9678 + F: drivers/i2c/i2c-atr.c 9679 + F: include/linux/i2c-atr.h 9680 + 9673 9681 I2C CONTROLLER DRIVER FOR NVIDIA GPU 9674 9682 M: Ajay Gupta <ajayg@nvidia.com> 9675 9683 L: linux-i2c@vger.kernel.org
+9
drivers/i2c/Kconfig
··· 71 71 72 72 source "drivers/i2c/muxes/Kconfig" 73 73 74 + config I2C_ATR 75 + tristate "I2C Address Translator (ATR) support" 76 + help 77 + Enable support for I2C Address Translator (ATR) chips. 78 + 79 + An ATR allows accessing multiple I2C busses from a single 80 + physical bus via address translation instead of bus selection as 81 + i2c-muxes do. 82 + 74 83 config I2C_HELPER_AUTO 75 84 bool "Autoselect pertinent helper modules" 76 85 default y
+1
drivers/i2c/Makefile
··· 13 13 obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o 14 14 obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o 15 15 obj-$(CONFIG_I2C_MUX) += i2c-mux.o 16 + obj-$(CONFIG_I2C_ATR) += i2c-atr.o 16 17 obj-y += algos/ busses/ muxes/ 17 18 obj-$(CONFIG_I2C_STUB) += i2c-stub.o 18 19 obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
+710
drivers/i2c/i2c-atr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * I2C Address Translator 4 + * 5 + * Copyright (c) 2019,2022 Luca Ceresoli <luca@lucaceresoli.net> 6 + * Copyright (c) 2022,2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7 + * 8 + * Originally based on i2c-mux.c 9 + */ 10 + 11 + #include <linux/fwnode.h> 12 + #include <linux/i2c-atr.h> 13 + #include <linux/i2c.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/slab.h> 18 + #include <linux/spinlock.h> 19 + 20 + #define ATR_MAX_ADAPTERS 100 /* Just a sanity limit */ 21 + #define ATR_MAX_SYMLINK_LEN 11 /* Longest name is 10 chars: "channel-99" */ 22 + 23 + /** 24 + * struct i2c_atr_alias_pair - Holds the alias assigned to a client. 25 + * @node: List node 26 + * @client: Pointer to the client on the child bus 27 + * @alias: I2C alias address assigned by the driver. 28 + * This is the address that will be used to issue I2C transactions 29 + * on the parent (physical) bus. 30 + */ 31 + struct i2c_atr_alias_pair { 32 + struct list_head node; 33 + const struct i2c_client *client; 34 + u16 alias; 35 + }; 36 + 37 + /** 38 + * struct i2c_atr_chan - Data for a channel. 39 + * @adap: The &struct i2c_adapter for the channel 40 + * @atr: The parent I2C ATR 41 + * @chan_id: The ID of this channel 42 + * @alias_list: List of @struct i2c_atr_alias_pair containing the 43 + * assigned aliases 44 + * @orig_addrs_lock: Mutex protecting @orig_addrs 45 + * @orig_addrs: Buffer used to store the original addresses during transmit 46 + * @orig_addrs_size: Size of @orig_addrs 47 + */ 48 + struct i2c_atr_chan { 49 + struct i2c_adapter adap; 50 + struct i2c_atr *atr; 51 + u32 chan_id; 52 + 53 + struct list_head alias_list; 54 + 55 + /* Lock orig_addrs during xfer */ 56 + struct mutex orig_addrs_lock; 57 + u16 *orig_addrs; 58 + unsigned int orig_addrs_size; 59 + }; 60 + 61 + /** 62 + * struct i2c_atr - The I2C ATR instance 63 + * @parent: The parent &struct i2c_adapter 64 + * @dev: The device that owns the I2C ATR instance 65 + * @ops: &struct i2c_atr_ops 66 + * @priv: Private driver data, set with i2c_atr_set_driver_data() 67 + * @algo: The &struct i2c_algorithm for adapters 68 + * @lock: Lock for the I2C bus segment (see &struct i2c_lock_operations) 69 + * @max_adapters: Maximum number of adapters this I2C ATR can have 70 + * @num_aliases: Number of aliases in the aliases array 71 + * @aliases: The aliases array 72 + * @alias_mask_lock: Lock protecting alias_use_mask 73 + * @alias_use_mask: Bitmask for used aliases in aliases array 74 + * @i2c_nb: Notifier for remote client add & del events 75 + * @adapter: Array of adapters 76 + */ 77 + struct i2c_atr { 78 + struct i2c_adapter *parent; 79 + struct device *dev; 80 + const struct i2c_atr_ops *ops; 81 + 82 + void *priv; 83 + 84 + struct i2c_algorithm algo; 85 + /* lock for the I2C bus segment (see struct i2c_lock_operations) */ 86 + struct mutex lock; 87 + int max_adapters; 88 + 89 + size_t num_aliases; 90 + const u16 *aliases; 91 + /* Protects alias_use_mask */ 92 + spinlock_t alias_mask_lock; 93 + unsigned long *alias_use_mask; 94 + 95 + struct notifier_block i2c_nb; 96 + 97 + struct i2c_adapter *adapter[]; 98 + }; 99 + 100 + static struct i2c_atr_alias_pair * 101 + i2c_atr_find_mapping_by_client(const struct list_head *list, 102 + const struct i2c_client *client) 103 + { 104 + struct i2c_atr_alias_pair *c2a; 105 + 106 + list_for_each_entry(c2a, list, node) { 107 + if (c2a->client == client) 108 + return c2a; 109 + } 110 + 111 + return NULL; 112 + } 113 + 114 + static struct i2c_atr_alias_pair * 115 + i2c_atr_find_mapping_by_addr(const struct list_head *list, u16 phys_addr) 116 + { 117 + struct i2c_atr_alias_pair *c2a; 118 + 119 + list_for_each_entry(c2a, list, node) { 120 + if (c2a->client->addr == phys_addr) 121 + return c2a; 122 + } 123 + 124 + return NULL; 125 + } 126 + 127 + /* 128 + * Replace all message addresses with their aliases, saving the original 129 + * addresses. 130 + * 131 + * This function is internal for use in i2c_atr_master_xfer(). It must be 132 + * followed by i2c_atr_unmap_msgs() to restore the original addresses. 133 + */ 134 + static int i2c_atr_map_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs, 135 + int num) 136 + { 137 + struct i2c_atr *atr = chan->atr; 138 + static struct i2c_atr_alias_pair *c2a; 139 + int i; 140 + 141 + /* Ensure we have enough room to save the original addresses */ 142 + if (unlikely(chan->orig_addrs_size < num)) { 143 + u16 *new_buf; 144 + 145 + /* We don't care about old data, hence no realloc() */ 146 + new_buf = kmalloc_array(num, sizeof(*new_buf), GFP_KERNEL); 147 + if (!new_buf) 148 + return -ENOMEM; 149 + 150 + kfree(chan->orig_addrs); 151 + chan->orig_addrs = new_buf; 152 + chan->orig_addrs_size = num; 153 + } 154 + 155 + for (i = 0; i < num; i++) { 156 + chan->orig_addrs[i] = msgs[i].addr; 157 + 158 + c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list, 159 + msgs[i].addr); 160 + if (!c2a) { 161 + dev_err(atr->dev, "client 0x%02x not mapped!\n", 162 + msgs[i].addr); 163 + 164 + while (i--) 165 + msgs[i].addr = chan->orig_addrs[i]; 166 + 167 + return -ENXIO; 168 + } 169 + 170 + msgs[i].addr = c2a->alias; 171 + } 172 + 173 + return 0; 174 + } 175 + 176 + /* 177 + * Restore all message address aliases with the original addresses. This 178 + * function is internal for use in i2c_atr_master_xfer() and for this reason it 179 + * needs no null and size checks on orig_addr. 180 + * 181 + * @see i2c_atr_map_msgs() 182 + */ 183 + static void i2c_atr_unmap_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs, 184 + int num) 185 + { 186 + int i; 187 + 188 + for (i = 0; i < num; i++) 189 + msgs[i].addr = chan->orig_addrs[i]; 190 + } 191 + 192 + static int i2c_atr_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 193 + int num) 194 + { 195 + struct i2c_atr_chan *chan = adap->algo_data; 196 + struct i2c_atr *atr = chan->atr; 197 + struct i2c_adapter *parent = atr->parent; 198 + int ret; 199 + 200 + /* Translate addresses */ 201 + mutex_lock(&chan->orig_addrs_lock); 202 + 203 + ret = i2c_atr_map_msgs(chan, msgs, num); 204 + if (ret < 0) 205 + goto err_unlock; 206 + 207 + /* Perform the transfer */ 208 + ret = i2c_transfer(parent, msgs, num); 209 + 210 + /* Restore addresses */ 211 + i2c_atr_unmap_msgs(chan, msgs, num); 212 + 213 + err_unlock: 214 + mutex_unlock(&chan->orig_addrs_lock); 215 + 216 + return ret; 217 + } 218 + 219 + static int i2c_atr_smbus_xfer(struct i2c_adapter *adap, u16 addr, 220 + unsigned short flags, char read_write, u8 command, 221 + int size, union i2c_smbus_data *data) 222 + { 223 + struct i2c_atr_chan *chan = adap->algo_data; 224 + struct i2c_atr *atr = chan->atr; 225 + struct i2c_adapter *parent = atr->parent; 226 + struct i2c_atr_alias_pair *c2a; 227 + 228 + c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list, addr); 229 + if (!c2a) { 230 + dev_err(atr->dev, "client 0x%02x not mapped!\n", addr); 231 + return -ENXIO; 232 + } 233 + 234 + return i2c_smbus_xfer(parent, c2a->alias, flags, read_write, command, 235 + size, data); 236 + } 237 + 238 + static u32 i2c_atr_functionality(struct i2c_adapter *adap) 239 + { 240 + struct i2c_atr_chan *chan = adap->algo_data; 241 + struct i2c_adapter *parent = chan->atr->parent; 242 + 243 + return parent->algo->functionality(parent); 244 + } 245 + 246 + static void i2c_atr_lock_bus(struct i2c_adapter *adapter, unsigned int flags) 247 + { 248 + struct i2c_atr_chan *chan = adapter->algo_data; 249 + struct i2c_atr *atr = chan->atr; 250 + 251 + mutex_lock(&atr->lock); 252 + } 253 + 254 + static int i2c_atr_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) 255 + { 256 + struct i2c_atr_chan *chan = adapter->algo_data; 257 + struct i2c_atr *atr = chan->atr; 258 + 259 + return mutex_trylock(&atr->lock); 260 + } 261 + 262 + static void i2c_atr_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) 263 + { 264 + struct i2c_atr_chan *chan = adapter->algo_data; 265 + struct i2c_atr *atr = chan->atr; 266 + 267 + mutex_unlock(&atr->lock); 268 + } 269 + 270 + static const struct i2c_lock_operations i2c_atr_lock_ops = { 271 + .lock_bus = i2c_atr_lock_bus, 272 + .trylock_bus = i2c_atr_trylock_bus, 273 + .unlock_bus = i2c_atr_unlock_bus, 274 + }; 275 + 276 + static int i2c_atr_reserve_alias(struct i2c_atr *atr) 277 + { 278 + unsigned long idx; 279 + 280 + spin_lock(&atr->alias_mask_lock); 281 + 282 + idx = find_first_zero_bit(atr->alias_use_mask, atr->num_aliases); 283 + if (idx >= atr->num_aliases) { 284 + spin_unlock(&atr->alias_mask_lock); 285 + dev_err(atr->dev, "failed to find a free alias\n"); 286 + return -EBUSY; 287 + } 288 + 289 + set_bit(idx, atr->alias_use_mask); 290 + 291 + spin_unlock(&atr->alias_mask_lock); 292 + 293 + return atr->aliases[idx]; 294 + } 295 + 296 + static void i2c_atr_release_alias(struct i2c_atr *atr, u16 alias) 297 + { 298 + unsigned int idx; 299 + 300 + spin_lock(&atr->alias_mask_lock); 301 + 302 + for (idx = 0; idx < atr->num_aliases; ++idx) { 303 + if (atr->aliases[idx] == alias) { 304 + clear_bit(idx, atr->alias_use_mask); 305 + spin_unlock(&atr->alias_mask_lock); 306 + return; 307 + } 308 + } 309 + 310 + spin_unlock(&atr->alias_mask_lock); 311 + 312 + /* This should never happen */ 313 + dev_warn(atr->dev, "Unable to find mapped alias\n"); 314 + } 315 + 316 + static int i2c_atr_attach_client(struct i2c_adapter *adapter, 317 + const struct i2c_client *client) 318 + { 319 + struct i2c_atr_chan *chan = adapter->algo_data; 320 + struct i2c_atr *atr = chan->atr; 321 + struct i2c_atr_alias_pair *c2a; 322 + u16 alias; 323 + int ret; 324 + 325 + ret = i2c_atr_reserve_alias(atr); 326 + if (ret < 0) 327 + return ret; 328 + 329 + alias = ret; 330 + 331 + c2a = kzalloc(sizeof(*c2a), GFP_KERNEL); 332 + if (!c2a) { 333 + ret = -ENOMEM; 334 + goto err_release_alias; 335 + } 336 + 337 + ret = atr->ops->attach_client(atr, chan->chan_id, client, alias); 338 + if (ret) 339 + goto err_free; 340 + 341 + dev_dbg(atr->dev, "chan%u: client 0x%02x mapped at alias 0x%02x (%s)\n", 342 + chan->chan_id, client->addr, alias, client->name); 343 + 344 + c2a->client = client; 345 + c2a->alias = alias; 346 + list_add(&c2a->node, &chan->alias_list); 347 + 348 + return 0; 349 + 350 + err_free: 351 + kfree(c2a); 352 + err_release_alias: 353 + i2c_atr_release_alias(atr, alias); 354 + 355 + return ret; 356 + } 357 + 358 + static void i2c_atr_detach_client(struct i2c_adapter *adapter, 359 + const struct i2c_client *client) 360 + { 361 + struct i2c_atr_chan *chan = adapter->algo_data; 362 + struct i2c_atr *atr = chan->atr; 363 + struct i2c_atr_alias_pair *c2a; 364 + 365 + atr->ops->detach_client(atr, chan->chan_id, client); 366 + 367 + c2a = i2c_atr_find_mapping_by_client(&chan->alias_list, client); 368 + if (!c2a) { 369 + /* This should never happen */ 370 + dev_warn(atr->dev, "Unable to find address mapping\n"); 371 + return; 372 + } 373 + 374 + i2c_atr_release_alias(atr, c2a->alias); 375 + 376 + dev_dbg(atr->dev, 377 + "chan%u: client 0x%02x unmapped from alias 0x%02x (%s)\n", 378 + chan->chan_id, client->addr, c2a->alias, client->name); 379 + 380 + list_del(&c2a->node); 381 + kfree(c2a); 382 + } 383 + 384 + static int i2c_atr_bus_notifier_call(struct notifier_block *nb, 385 + unsigned long event, void *device) 386 + { 387 + struct i2c_atr *atr = container_of(nb, struct i2c_atr, i2c_nb); 388 + struct device *dev = device; 389 + struct i2c_client *client; 390 + u32 chan_id; 391 + int ret; 392 + 393 + client = i2c_verify_client(dev); 394 + if (!client) 395 + return NOTIFY_DONE; 396 + 397 + /* Is the client in one of our adapters? */ 398 + for (chan_id = 0; chan_id < atr->max_adapters; ++chan_id) { 399 + if (client->adapter == atr->adapter[chan_id]) 400 + break; 401 + } 402 + 403 + if (chan_id == atr->max_adapters) 404 + return NOTIFY_DONE; 405 + 406 + switch (event) { 407 + case BUS_NOTIFY_ADD_DEVICE: 408 + ret = i2c_atr_attach_client(client->adapter, client); 409 + if (ret) 410 + dev_err(atr->dev, 411 + "Failed to attach remote client '%s': %d\n", 412 + dev_name(dev), ret); 413 + break; 414 + 415 + case BUS_NOTIFY_DEL_DEVICE: 416 + i2c_atr_detach_client(client->adapter, client); 417 + break; 418 + 419 + default: 420 + break; 421 + } 422 + 423 + return NOTIFY_DONE; 424 + } 425 + 426 + static int i2c_atr_parse_alias_pool(struct i2c_atr *atr) 427 + { 428 + struct device *dev = atr->dev; 429 + unsigned long *alias_use_mask; 430 + size_t num_aliases; 431 + unsigned int i; 432 + u32 *aliases32; 433 + u16 *aliases16; 434 + int ret; 435 + 436 + ret = fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool"); 437 + if (ret < 0) { 438 + dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n", 439 + ret); 440 + return ret; 441 + } 442 + 443 + num_aliases = ret; 444 + 445 + if (!num_aliases) 446 + return 0; 447 + 448 + aliases32 = kcalloc(num_aliases, sizeof(*aliases32), GFP_KERNEL); 449 + if (!aliases32) 450 + return -ENOMEM; 451 + 452 + ret = fwnode_property_read_u32_array(dev_fwnode(dev), "i2c-alias-pool", 453 + aliases32, num_aliases); 454 + if (ret < 0) { 455 + dev_err(dev, "Failed to read 'i2c-alias-pool' property: %d\n", 456 + ret); 457 + goto err_free_aliases32; 458 + } 459 + 460 + aliases16 = kcalloc(num_aliases, sizeof(*aliases16), GFP_KERNEL); 461 + if (!aliases16) { 462 + ret = -ENOMEM; 463 + goto err_free_aliases32; 464 + } 465 + 466 + for (i = 0; i < num_aliases; i++) { 467 + if (!(aliases32[i] & 0xffff0000)) { 468 + aliases16[i] = aliases32[i]; 469 + continue; 470 + } 471 + 472 + dev_err(dev, "Failed to parse 'i2c-alias-pool' property: I2C flags are not supported\n"); 473 + ret = -EINVAL; 474 + goto err_free_aliases16; 475 + } 476 + 477 + alias_use_mask = bitmap_zalloc(num_aliases, GFP_KERNEL); 478 + if (!alias_use_mask) { 479 + ret = -ENOMEM; 480 + goto err_free_aliases16; 481 + } 482 + 483 + kfree(aliases32); 484 + 485 + atr->num_aliases = num_aliases; 486 + atr->aliases = aliases16; 487 + atr->alias_use_mask = alias_use_mask; 488 + 489 + dev_dbg(dev, "i2c-alias-pool has %zu aliases", atr->num_aliases); 490 + 491 + return 0; 492 + 493 + err_free_aliases16: 494 + kfree(aliases16); 495 + err_free_aliases32: 496 + kfree(aliases32); 497 + return ret; 498 + } 499 + 500 + struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, 501 + const struct i2c_atr_ops *ops, int max_adapters) 502 + { 503 + struct i2c_atr *atr; 504 + int ret; 505 + 506 + if (max_adapters > ATR_MAX_ADAPTERS) 507 + return ERR_PTR(-EINVAL); 508 + 509 + if (!ops || !ops->attach_client || !ops->detach_client) 510 + return ERR_PTR(-EINVAL); 511 + 512 + atr = kzalloc(struct_size(atr, adapter, max_adapters), GFP_KERNEL); 513 + if (!atr) 514 + return ERR_PTR(-ENOMEM); 515 + 516 + mutex_init(&atr->lock); 517 + spin_lock_init(&atr->alias_mask_lock); 518 + 519 + atr->parent = parent; 520 + atr->dev = dev; 521 + atr->ops = ops; 522 + atr->max_adapters = max_adapters; 523 + 524 + if (parent->algo->master_xfer) 525 + atr->algo.master_xfer = i2c_atr_master_xfer; 526 + if (parent->algo->smbus_xfer) 527 + atr->algo.smbus_xfer = i2c_atr_smbus_xfer; 528 + atr->algo.functionality = i2c_atr_functionality; 529 + 530 + ret = i2c_atr_parse_alias_pool(atr); 531 + if (ret) 532 + goto err_destroy_mutex; 533 + 534 + atr->i2c_nb.notifier_call = i2c_atr_bus_notifier_call; 535 + ret = bus_register_notifier(&i2c_bus_type, &atr->i2c_nb); 536 + if (ret) 537 + goto err_free_aliases; 538 + 539 + return atr; 540 + 541 + err_free_aliases: 542 + bitmap_free(atr->alias_use_mask); 543 + kfree(atr->aliases); 544 + err_destroy_mutex: 545 + mutex_destroy(&atr->lock); 546 + kfree(atr); 547 + 548 + return ERR_PTR(ret); 549 + } 550 + EXPORT_SYMBOL_NS_GPL(i2c_atr_new, I2C_ATR); 551 + 552 + void i2c_atr_delete(struct i2c_atr *atr) 553 + { 554 + unsigned int i; 555 + 556 + for (i = 0; i < atr->max_adapters; ++i) 557 + WARN_ON(atr->adapter[i]); 558 + 559 + bus_unregister_notifier(&i2c_bus_type, &atr->i2c_nb); 560 + bitmap_free(atr->alias_use_mask); 561 + kfree(atr->aliases); 562 + mutex_destroy(&atr->lock); 563 + kfree(atr); 564 + } 565 + EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, I2C_ATR); 566 + 567 + int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, 568 + struct device *adapter_parent, 569 + struct fwnode_handle *bus_handle) 570 + { 571 + struct i2c_adapter *parent = atr->parent; 572 + struct device *dev = atr->dev; 573 + struct i2c_atr_chan *chan; 574 + char symlink_name[ATR_MAX_SYMLINK_LEN]; 575 + int ret; 576 + 577 + if (chan_id >= atr->max_adapters) { 578 + dev_err(dev, "No room for more i2c-atr adapters\n"); 579 + return -EINVAL; 580 + } 581 + 582 + if (atr->adapter[chan_id]) { 583 + dev_err(dev, "Adapter %d already present\n", chan_id); 584 + return -EEXIST; 585 + } 586 + 587 + chan = kzalloc(sizeof(*chan), GFP_KERNEL); 588 + if (!chan) 589 + return -ENOMEM; 590 + 591 + if (!adapter_parent) 592 + adapter_parent = dev; 593 + 594 + chan->atr = atr; 595 + chan->chan_id = chan_id; 596 + INIT_LIST_HEAD(&chan->alias_list); 597 + mutex_init(&chan->orig_addrs_lock); 598 + 599 + snprintf(chan->adap.name, sizeof(chan->adap.name), "i2c-%d-atr-%d", 600 + i2c_adapter_id(parent), chan_id); 601 + chan->adap.owner = THIS_MODULE; 602 + chan->adap.algo = &atr->algo; 603 + chan->adap.algo_data = chan; 604 + chan->adap.dev.parent = adapter_parent; 605 + chan->adap.retries = parent->retries; 606 + chan->adap.timeout = parent->timeout; 607 + chan->adap.quirks = parent->quirks; 608 + chan->adap.lock_ops = &i2c_atr_lock_ops; 609 + 610 + if (bus_handle) { 611 + device_set_node(&chan->adap.dev, fwnode_handle_get(bus_handle)); 612 + } else { 613 + struct fwnode_handle *atr_node; 614 + struct fwnode_handle *child; 615 + u32 reg; 616 + 617 + atr_node = device_get_named_child_node(dev, "i2c-atr"); 618 + 619 + fwnode_for_each_child_node(atr_node, child) { 620 + ret = fwnode_property_read_u32(child, "reg", &reg); 621 + if (ret) 622 + continue; 623 + if (chan_id == reg) 624 + break; 625 + } 626 + 627 + device_set_node(&chan->adap.dev, child); 628 + fwnode_handle_put(atr_node); 629 + } 630 + 631 + atr->adapter[chan_id] = &chan->adap; 632 + 633 + ret = i2c_add_adapter(&chan->adap); 634 + if (ret) { 635 + dev_err(dev, "failed to add atr-adapter %u (error=%d)\n", 636 + chan_id, ret); 637 + goto err_fwnode_put; 638 + } 639 + 640 + snprintf(symlink_name, sizeof(symlink_name), "channel-%u", 641 + chan->chan_id); 642 + 643 + ret = sysfs_create_link(&chan->adap.dev.kobj, &dev->kobj, "atr_device"); 644 + if (ret) 645 + dev_warn(dev, "can't create symlink to atr device\n"); 646 + ret = sysfs_create_link(&dev->kobj, &chan->adap.dev.kobj, symlink_name); 647 + if (ret) 648 + dev_warn(dev, "can't create symlink for channel %u\n", chan_id); 649 + 650 + dev_dbg(dev, "Added ATR child bus %d\n", i2c_adapter_id(&chan->adap)); 651 + 652 + return 0; 653 + 654 + err_fwnode_put: 655 + fwnode_handle_put(dev_fwnode(&chan->adap.dev)); 656 + mutex_destroy(&chan->orig_addrs_lock); 657 + kfree(chan); 658 + return ret; 659 + } 660 + EXPORT_SYMBOL_NS_GPL(i2c_atr_add_adapter, I2C_ATR); 661 + 662 + void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id) 663 + { 664 + char symlink_name[ATR_MAX_SYMLINK_LEN]; 665 + struct i2c_adapter *adap; 666 + struct i2c_atr_chan *chan; 667 + struct fwnode_handle *fwnode; 668 + struct device *dev = atr->dev; 669 + 670 + adap = atr->adapter[chan_id]; 671 + if (!adap) 672 + return; 673 + 674 + chan = adap->algo_data; 675 + fwnode = dev_fwnode(&adap->dev); 676 + 677 + dev_dbg(dev, "Removing ATR child bus %d\n", i2c_adapter_id(adap)); 678 + 679 + snprintf(symlink_name, sizeof(symlink_name), "channel-%u", 680 + chan->chan_id); 681 + sysfs_remove_link(&dev->kobj, symlink_name); 682 + sysfs_remove_link(&chan->adap.dev.kobj, "atr_device"); 683 + 684 + i2c_del_adapter(adap); 685 + 686 + atr->adapter[chan_id] = NULL; 687 + 688 + fwnode_handle_put(fwnode); 689 + mutex_destroy(&chan->orig_addrs_lock); 690 + kfree(chan->orig_addrs); 691 + kfree(chan); 692 + } 693 + EXPORT_SYMBOL_NS_GPL(i2c_atr_del_adapter, I2C_ATR); 694 + 695 + void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data) 696 + { 697 + atr->priv = data; 698 + } 699 + EXPORT_SYMBOL_NS_GPL(i2c_atr_set_driver_data, I2C_ATR); 700 + 701 + void *i2c_atr_get_driver_data(struct i2c_atr *atr) 702 + { 703 + return atr->priv; 704 + } 705 + EXPORT_SYMBOL_NS_GPL(i2c_atr_get_driver_data, I2C_ATR); 706 + 707 + MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>"); 708 + MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); 709 + MODULE_DESCRIPTION("I2C Address Translator"); 710 + MODULE_LICENSE("GPL");
+116
include/linux/i2c-atr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * I2C Address Translator 4 + * 5 + * Copyright (c) 2019,2022 Luca Ceresoli <luca@lucaceresoli.net> 6 + * Copyright (c) 2022,2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7 + * 8 + * Based on i2c-mux.h 9 + */ 10 + 11 + #ifndef _LINUX_I2C_ATR_H 12 + #define _LINUX_I2C_ATR_H 13 + 14 + #include <linux/i2c.h> 15 + #include <linux/types.h> 16 + 17 + struct device; 18 + struct fwnode_handle; 19 + struct i2c_atr; 20 + 21 + /** 22 + * struct i2c_atr_ops - Callbacks from ATR to the device driver. 23 + * @attach_client: Notify the driver of a new device connected on a child 24 + * bus, with the alias assigned to it. The driver must 25 + * configure the hardware to use the alias. 26 + * @detach_client: Notify the driver of a device getting disconnected. The 27 + * driver must configure the hardware to stop using the 28 + * alias. 29 + * 30 + * All these functions return 0 on success, a negative error code otherwise. 31 + */ 32 + struct i2c_atr_ops { 33 + int (*attach_client)(struct i2c_atr *atr, u32 chan_id, 34 + const struct i2c_client *client, u16 alias); 35 + void (*detach_client)(struct i2c_atr *atr, u32 chan_id, 36 + const struct i2c_client *client); 37 + }; 38 + 39 + /** 40 + * i2c_atr_new() - Allocate and initialize an I2C ATR helper. 41 + * @parent: The parent (upstream) adapter 42 + * @dev: The device acting as an ATR 43 + * @ops: Driver-specific callbacks 44 + * @max_adapters: Maximum number of child adapters 45 + * 46 + * The new ATR helper is connected to the parent adapter but has no child 47 + * adapters. Call i2c_atr_add_adapter() to add some. 48 + * 49 + * Call i2c_atr_delete() to remove. 50 + * 51 + * Return: pointer to the new ATR helper object, or ERR_PTR 52 + */ 53 + struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, 54 + const struct i2c_atr_ops *ops, int max_adapters); 55 + 56 + /** 57 + * i2c_atr_delete - Delete an I2C ATR helper. 58 + * @atr: I2C ATR helper to be deleted. 59 + * 60 + * Precondition: all the adapters added with i2c_atr_add_adapter() must be 61 + * removed by calling i2c_atr_del_adapter(). 62 + */ 63 + void i2c_atr_delete(struct i2c_atr *atr); 64 + 65 + /** 66 + * i2c_atr_add_adapter - Create a child ("downstream") I2C bus. 67 + * @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. 74 + * 75 + * After calling this function a new i2c bus will appear. Adding and removing 76 + * devices on the downstream bus will result in calls to the 77 + * &i2c_atr_ops->attach_client and &i2c_atr_ops->detach_client callbacks for the 78 + * driver to assign an alias to the device. 79 + * 80 + * The adapter's fwnode is set to @bus_handle, or if @bus_handle is NULL the 81 + * function looks for a child node whose 'reg' property matches the chan_id 82 + * under the i2c-atr device's 'i2c-atr' node. 83 + * 84 + * Call i2c_atr_del_adapter() to remove the adapter. 85 + * 86 + * Return: 0 on success, a negative error code otherwise. 87 + */ 88 + int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, 89 + struct device *adapter_parent, 90 + struct fwnode_handle *bus_handle); 91 + 92 + /** 93 + * i2c_atr_del_adapter - Remove a child ("downstream") I2C bus added by 94 + * i2c_atr_add_adapter(). If no I2C bus has been added 95 + * this function is a no-op. 96 + * @atr: The I2C ATR 97 + * @chan_id: Index of the adapter to be removed (0 .. max_adapters-1) 98 + */ 99 + void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id); 100 + 101 + /** 102 + * i2c_atr_set_driver_data - Set private driver data to the i2c-atr instance. 103 + * @atr: The I2C ATR 104 + * @data: Pointer to the data to store 105 + */ 106 + void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data); 107 + 108 + /** 109 + * i2c_atr_get_driver_data - Get the stored drive data. 110 + * @atr: The I2C ATR 111 + * 112 + * Return: Pointer to the stored data 113 + */ 114 + void *i2c_atr_get_driver_data(struct i2c_atr *atr); 115 + 116 + #endif /* _LINUX_I2C_ATR_H */