Commit | Line | Data |
---|---|---|
a076a860 LC |
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 | ||
3a133a4e | 97 | struct i2c_adapter *adapter[] __counted_by(max_adapters); |
a076a860 LC |
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", ®); | |
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"); |