Lines Matching +full:parent +full:- +full:locked
4 * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
5 * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
6 * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com>
10 * Supports multi-level mux'ing (mux behind a mux).
13 * i2c-virt.c from Kumar Gala <galak@kernel.crashing.org>
14 * i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
15 * i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com>
24 #include <linux/i2c-mux.h>
42 struct i2c_mux_priv *priv = adap->algo_data; in __i2c_mux_master_xfer()
43 struct i2c_mux_core *muxc = priv->muxc; in __i2c_mux_master_xfer()
44 struct i2c_adapter *parent = muxc->parent; in __i2c_mux_master_xfer() local
49 ret = muxc->select(muxc, priv->chan_id); in __i2c_mux_master_xfer()
51 ret = __i2c_transfer(parent, msgs, num); in __i2c_mux_master_xfer()
52 if (muxc->deselect) in __i2c_mux_master_xfer()
53 muxc->deselect(muxc, priv->chan_id); in __i2c_mux_master_xfer()
61 struct i2c_mux_priv *priv = adap->algo_data; in i2c_mux_master_xfer()
62 struct i2c_mux_core *muxc = priv->muxc; in i2c_mux_master_xfer()
63 struct i2c_adapter *parent = muxc->parent; in i2c_mux_master_xfer() local
68 ret = muxc->select(muxc, priv->chan_id); in i2c_mux_master_xfer()
70 ret = i2c_transfer(parent, msgs, num); in i2c_mux_master_xfer()
71 if (muxc->deselect) in i2c_mux_master_xfer()
72 muxc->deselect(muxc, priv->chan_id); in i2c_mux_master_xfer()
82 struct i2c_mux_priv *priv = adap->algo_data; in __i2c_mux_smbus_xfer()
83 struct i2c_mux_core *muxc = priv->muxc; in __i2c_mux_smbus_xfer()
84 struct i2c_adapter *parent = muxc->parent; in __i2c_mux_smbus_xfer() local
89 ret = muxc->select(muxc, priv->chan_id); in __i2c_mux_smbus_xfer()
91 ret = __i2c_smbus_xfer(parent, addr, flags, in __i2c_mux_smbus_xfer()
93 if (muxc->deselect) in __i2c_mux_smbus_xfer()
94 muxc->deselect(muxc, priv->chan_id); in __i2c_mux_smbus_xfer()
104 struct i2c_mux_priv *priv = adap->algo_data; in i2c_mux_smbus_xfer()
105 struct i2c_mux_core *muxc = priv->muxc; in i2c_mux_smbus_xfer()
106 struct i2c_adapter *parent = muxc->parent; in i2c_mux_smbus_xfer() local
111 ret = muxc->select(muxc, priv->chan_id); in i2c_mux_smbus_xfer()
113 ret = i2c_smbus_xfer(parent, addr, flags, in i2c_mux_smbus_xfer()
115 if (muxc->deselect) in i2c_mux_smbus_xfer()
116 muxc->deselect(muxc, priv->chan_id); in i2c_mux_smbus_xfer()
121 /* Return the parent's functionality */
124 struct i2c_mux_priv *priv = adap->algo_data; in i2c_mux_functionality()
125 struct i2c_adapter *parent = priv->muxc->parent; in i2c_mux_functionality() local
127 return parent->algo->functionality(parent); in i2c_mux_functionality()
130 /* Return all parent classes, merged */
131 static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent) in i2c_mux_parent_classes() argument
136 class |= parent->class; in i2c_mux_parent_classes()
137 parent = i2c_parent_is_i2c_adapter(parent); in i2c_mux_parent_classes()
138 } while (parent); in i2c_mux_parent_classes()
145 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_mux_lock_bus()
146 struct i2c_adapter *parent = priv->muxc->parent; in i2c_mux_lock_bus() local
148 rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter)); in i2c_mux_lock_bus()
151 i2c_lock_bus(parent, flags); in i2c_mux_lock_bus()
156 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_mux_trylock_bus()
157 struct i2c_adapter *parent = priv->muxc->parent; in i2c_mux_trylock_bus() local
159 if (!rt_mutex_trylock(&parent->mux_lock)) in i2c_mux_trylock_bus()
160 return 0; /* mux_lock not locked, failure */ in i2c_mux_trylock_bus()
163 if (i2c_trylock_bus(parent, flags)) in i2c_mux_trylock_bus()
164 return 1; /* parent locked too, success */ in i2c_mux_trylock_bus()
165 rt_mutex_unlock(&parent->mux_lock); in i2c_mux_trylock_bus()
166 return 0; /* parent not locked, failure */ in i2c_mux_trylock_bus()
171 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_mux_unlock_bus()
172 struct i2c_adapter *parent = priv->muxc->parent; in i2c_mux_unlock_bus() local
175 i2c_unlock_bus(parent, flags); in i2c_mux_unlock_bus()
176 rt_mutex_unlock(&parent->mux_lock); in i2c_mux_unlock_bus()
182 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_parent_lock_bus()
183 struct i2c_adapter *parent = priv->muxc->parent; in i2c_parent_lock_bus() local
185 rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter)); in i2c_parent_lock_bus()
186 i2c_lock_bus(parent, flags); in i2c_parent_lock_bus()
192 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_parent_trylock_bus()
193 struct i2c_adapter *parent = priv->muxc->parent; in i2c_parent_trylock_bus() local
195 if (!rt_mutex_trylock(&parent->mux_lock)) in i2c_parent_trylock_bus()
196 return 0; /* mux_lock not locked, failure */ in i2c_parent_trylock_bus()
197 if (i2c_trylock_bus(parent, flags)) in i2c_parent_trylock_bus()
198 return 1; /* parent locked too, success */ in i2c_parent_trylock_bus()
199 rt_mutex_unlock(&parent->mux_lock); in i2c_parent_trylock_bus()
200 return 0; /* parent not locked, failure */ in i2c_parent_trylock_bus()
206 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_parent_unlock_bus()
207 struct i2c_adapter *parent = priv->muxc->parent; in i2c_parent_unlock_bus() local
209 i2c_unlock_bus(parent, flags); in i2c_parent_unlock_bus()
210 rt_mutex_unlock(&parent->mux_lock); in i2c_parent_unlock_bus()
217 * the parent lock_select should ensure that the channel is correctly
223 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_mux_lock_select()
224 struct i2c_mux_core *muxc = priv->muxc; in i2c_mux_lock_select()
225 struct i2c_adapter *parent = muxc->parent; in i2c_mux_lock_select() local
227 rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter)); in i2c_mux_lock_select()
229 adapter = parent->mux_root_ops->lock_select(parent); in i2c_mux_lock_select()
233 ret = muxc->select(muxc, priv->chan_id); in i2c_mux_lock_select()
235 parent->mux_root_ops->unlock_deselect(parent); in i2c_mux_lock_select()
236 rt_mutex_unlock(&parent->mux_lock); in i2c_mux_lock_select()
245 struct i2c_mux_priv *priv = adapter->algo_data; in i2c_mux_unlock_deselect()
246 struct i2c_mux_core *muxc = priv->muxc; in i2c_mux_unlock_deselect()
247 struct i2c_adapter *parent = muxc->parent; in i2c_mux_unlock_deselect() local
249 if (muxc->deselect) in i2c_mux_unlock_deselect()
250 muxc->deselect(muxc, priv->chan_id); in i2c_mux_unlock_deselect()
252 parent->mux_root_ops->unlock_deselect(parent); in i2c_mux_unlock_deselect()
253 rt_mutex_unlock(&parent->mux_lock); in i2c_mux_unlock_deselect()
266 for (i2c = dev; i2c; i2c = i2c->parent) { in i2c_root_adapter()
267 if (i2c->type == &i2c_adapter_type) in i2c_root_adapter()
282 struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, in i2c_mux_alloc() argument
296 muxc->priv = &muxc->adapter[max_adapters]; in i2c_mux_alloc()
298 muxc->parent = parent; in i2c_mux_alloc()
299 muxc->dev = dev; in i2c_mux_alloc()
301 muxc->mux_locked = true; in i2c_mux_alloc()
303 muxc->arbitrator = true; in i2c_mux_alloc()
305 muxc->gate = true; in i2c_mux_alloc()
306 muxc->select = select; in i2c_mux_alloc()
307 muxc->deselect = deselect; in i2c_mux_alloc()
308 muxc->max_adapters = max_adapters; in i2c_mux_alloc()
335 struct i2c_adapter *parent = muxc->parent; in i2c_mux_add_adapter() local
340 if (muxc->num_adapters >= muxc->max_adapters) { in i2c_mux_add_adapter()
341 dev_err(muxc->dev, "No room for more i2c-mux adapters\n"); in i2c_mux_add_adapter()
342 return -EINVAL; in i2c_mux_add_adapter()
347 return -ENOMEM; in i2c_mux_add_adapter()
350 priv->muxc = muxc; in i2c_mux_add_adapter()
351 priv->chan_id = chan_id; in i2c_mux_add_adapter()
356 if (parent->algo->master_xfer) { in i2c_mux_add_adapter()
357 if (muxc->mux_locked) in i2c_mux_add_adapter()
358 priv->algo.master_xfer = i2c_mux_master_xfer; in i2c_mux_add_adapter()
360 priv->algo.master_xfer = __i2c_mux_master_xfer; in i2c_mux_add_adapter()
362 if (parent->algo->master_xfer_atomic) in i2c_mux_add_adapter()
363 priv->algo.master_xfer_atomic = priv->algo.master_xfer; in i2c_mux_add_adapter()
365 if (parent->algo->smbus_xfer) { in i2c_mux_add_adapter()
366 if (muxc->mux_locked) in i2c_mux_add_adapter()
367 priv->algo.smbus_xfer = i2c_mux_smbus_xfer; in i2c_mux_add_adapter()
369 priv->algo.smbus_xfer = __i2c_mux_smbus_xfer; in i2c_mux_add_adapter()
371 if (parent->algo->smbus_xfer_atomic) in i2c_mux_add_adapter()
372 priv->algo.smbus_xfer_atomic = priv->algo.smbus_xfer; in i2c_mux_add_adapter()
374 priv->algo.functionality = i2c_mux_functionality; in i2c_mux_add_adapter()
377 snprintf(priv->adap.name, sizeof(priv->adap.name), in i2c_mux_add_adapter()
378 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id); in i2c_mux_add_adapter()
379 priv->adap.owner = THIS_MODULE; in i2c_mux_add_adapter()
380 priv->adap.algo = &priv->algo; in i2c_mux_add_adapter()
381 priv->adap.algo_data = priv; in i2c_mux_add_adapter()
382 priv->adap.dev.parent = &parent->dev; in i2c_mux_add_adapter()
383 priv->adap.retries = parent->retries; in i2c_mux_add_adapter()
384 priv->adap.timeout = parent->timeout; in i2c_mux_add_adapter()
385 priv->adap.quirks = parent->quirks; in i2c_mux_add_adapter()
386 if (muxc->mux_locked) in i2c_mux_add_adapter()
387 priv->adap.lock_ops = &i2c_mux_lock_ops; in i2c_mux_add_adapter()
389 priv->adap.lock_ops = &i2c_parent_lock_ops; in i2c_mux_add_adapter()
391 priv->adap.mux_root_ops = &i2c_mux_root_ops; in i2c_mux_add_adapter()
394 if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED) in i2c_mux_add_adapter()
395 dev_err(&parent->dev, in i2c_mux_add_adapter()
399 priv->adap.class = class; in i2c_mux_add_adapter()
405 if (muxc->dev->of_node) { in i2c_mux_add_adapter()
406 struct device_node *dev_node = muxc->dev->of_node; in i2c_mux_add_adapter()
410 if (muxc->arbitrator) in i2c_mux_add_adapter()
411 mux_node = of_get_child_by_name(dev_node, "i2c-arb"); in i2c_mux_add_adapter()
412 else if (muxc->gate) in i2c_mux_add_adapter()
413 mux_node = of_get_child_by_name(dev_node, "i2c-gate"); in i2c_mux_add_adapter()
415 mux_node = of_get_child_by_name(dev_node, "i2c-mux"); in i2c_mux_add_adapter()
418 /* A "reg" property indicates an old-style DT entry */ in i2c_mux_add_adapter()
427 else if (muxc->arbitrator || muxc->gate) in i2c_mux_add_adapter()
440 priv->adap.dev.of_node = child; in i2c_mux_add_adapter()
447 if (has_acpi_companion(muxc->dev)) in i2c_mux_add_adapter()
448 acpi_preset_companion(&priv->adap.dev, in i2c_mux_add_adapter()
449 ACPI_COMPANION(muxc->dev), in i2c_mux_add_adapter()
453 priv->adap.nr = force_nr; in i2c_mux_add_adapter()
454 ret = i2c_add_numbered_adapter(&priv->adap); in i2c_mux_add_adapter()
456 dev_err(&parent->dev, in i2c_mux_add_adapter()
457 "failed to add mux-adapter %u as bus %u (error=%d)\n", in i2c_mux_add_adapter()
462 ret = i2c_add_adapter(&priv->adap); in i2c_mux_add_adapter()
464 dev_err(&parent->dev, in i2c_mux_add_adapter()
465 "failed to add mux-adapter %u (error=%d)\n", in i2c_mux_add_adapter()
471 WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj, in i2c_mux_add_adapter()
475 snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id); in i2c_mux_add_adapter()
476 WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj, in i2c_mux_add_adapter()
479 dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", in i2c_mux_add_adapter()
480 i2c_adapter_id(&priv->adap)); in i2c_mux_add_adapter()
482 muxc->adapter[muxc->num_adapters++] = &priv->adap; in i2c_mux_add_adapter()
495 while (muxc->num_adapters) { in i2c_mux_del_adapters()
496 struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters]; in i2c_mux_del_adapters()
497 struct i2c_mux_priv *priv = adap->algo_data; in i2c_mux_del_adapters()
498 struct device_node *np = adap->dev.of_node; in i2c_mux_del_adapters()
500 muxc->adapter[muxc->num_adapters] = NULL; in i2c_mux_del_adapters()
503 "channel-%u", priv->chan_id); in i2c_mux_del_adapters()
504 sysfs_remove_link(&muxc->dev->kobj, symlink_name); in i2c_mux_del_adapters()
506 sysfs_remove_link(&priv->adap.dev.kobj, "mux_device"); in i2c_mux_del_adapters()