@@ -372,11 +372,12 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
{
int ret;
- mutex_lock(&mux->lock);
+ if (mux->shared)
+ mutex_lock(&mux->lock);
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared)
mutex_unlock(&mux->lock);
return ret;
@@ -399,12 +400,12 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
{
int ret;
- if (!mutex_trylock(&mux->lock))
+ if (mux->shared && !mutex_trylock(&mux->lock))
return -EBUSY;
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared)
mutex_unlock(&mux->lock);
return ret;
@@ -427,7 +428,8 @@ int mux_control_deselect(struct mux_control *mux)
mux->idle_state != mux->cached_state)
ret = mux_control_set(mux, mux->idle_state);
- mutex_unlock(&mux->lock);
+ if (mux->shared)
+ mutex_unlock(&mux->lock);
return ret;
}
@@ -447,18 +449,13 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
return dev ? to_mux_chip(dev) : NULL;
}
-/**
- * mux_control_get() - Get the mux-control for a device.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+static struct mux_control *__mux_control_get(struct device *dev,
+ const char *mux_name, bool shared)
{
struct device_node *np = dev->of_node;
struct of_phandle_args args;
struct mux_chip *mux_chip;
+ struct mux_control *mux;
unsigned int controller;
int index = 0;
int ret;
@@ -505,9 +502,56 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
}
get_device(&mux_chip->dev);
- return &mux_chip->mux[controller];
+
+ mux = &mux_chip->mux[controller];
+
+ ret = atomic_inc_return(&mux->use_count);
+ if (ret == 1 && shared)
+ mux->shared = true;
+ if (ret > 1 && (!shared || !mux->shared)) {
+ atomic_dec(&mux->use_count);
+ put_device(&mux_chip->dev);
+ return ERR_PTR(-EBUSY);
+ }
+
+ return mux;
+}
+
+/**
+ * mux_control_get_shared() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * The returned mux control is in shared mode and can not be controlled from
+ * userspace. The mux control lock is taken when the mux is selected and
+ * released when the mux is deselected.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get_shared(struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(mux_control_get_shared);
+
+/**
+ * mux_control_get_exclusive() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * The returned mux control is in exclusive mode and does not lock the mux
+ * control lock when the mux is selected. The exclusive consumer has to take
+ * care of locking, if necessary.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get_exclusive(struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, false);
}
-EXPORT_SYMBOL_GPL(mux_control_get);
+EXPORT_SYMBOL_GPL(mux_control_get_exclusive);
/**
* mux_control_put() - Put away the mux-control for good.
@@ -517,6 +561,7 @@ EXPORT_SYMBOL_GPL(mux_control_get);
*/
void mux_control_put(struct mux_control *mux)
{
+ atomic_dec(&mux->use_count);
put_device(&mux->chip->dev);
}
EXPORT_SYMBOL_GPL(mux_control_put);
@@ -528,16 +573,9 @@ static void devm_mux_control_release(struct device *dev, void *res)
mux_control_put(mux);
}
-/**
- * devm_mux_control_get() - Get the mux-control for a device, with resource
- * management.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name)
+static struct mux_control *__devm_mux_control_get(struct device *dev,
+ const char *mux_name,
+ bool shared)
{
struct mux_control **ptr, *mux;
@@ -545,7 +583,7 @@ struct mux_control *devm_mux_control_get(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- mux = mux_control_get(dev, mux_name);
+ mux = __mux_control_get(dev, mux_name, shared);
if (IS_ERR(mux)) {
devres_free(ptr);
return mux;
@@ -556,7 +594,36 @@ struct mux_control *devm_mux_control_get(struct device *dev,
return mux;
}
-EXPORT_SYMBOL_GPL(devm_mux_control_get);
+
+/**
+ * devm_mux_control_get_shared() - Get the mux-control for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get_shared(struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_shared);
+
+/**
+ * devm_mux_control_get_exclusive() - Get the mux-control for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, false);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_exclusive);
static int devm_mux_control_match(struct device *dev, void *res, void *data)
{
@@ -23,11 +23,16 @@ int __must_check mux_control_try_select(struct mux_control *mux,
unsigned int state);
int mux_control_deselect(struct mux_control *mux);
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+struct mux_control *mux_control_get_exclusive(struct device *dev,
+ const char *mux_name);
+struct mux_control *mux_control_get_shared(struct device *dev,
+ const char *mux_name);
void mux_control_put(struct mux_control *mux);
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name);
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev,
+ const char *mux_name);
+struct mux_control *devm_mux_control_get_shared(struct device *dev,
+ const char *mux_name);
void devm_mux_control_put(struct device *dev, struct mux_control *mux);
#endif /* _LINUX_MUX_CONSUMER_H */
@@ -31,17 +31,20 @@ struct mux_control_ops {
/**
* struct mux_control - Represents a mux controller.
- * @lock: Protects the mux controller state.
+ * @lock: Protects the mux controller state, if shared.
* @chip: The mux chip that is handling this mux controller.
* @cached_state: The current mux controller state, or -1 if none.
* @states: The number of mux controller states.
* @idle_state: The mux controller state to use when inactive, or one
* of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
+ * @use_count: Number of consumers that have requested this mux.
+ * @shared: True if the mux control was requested as shared and
+ * must therefore be locked.
*
* Mux drivers may only change @states and @idle_state, and may only do so
* between allocation and registration of the mux controller. Specifically,
- * @cached_state is internal to the mux core and should never be written by
- * mux drivers.
+ * @cached_state, @use_count, and @shared are internal to the mux core and
+ * should never be written by mux drivers.
*/
struct mux_control {
struct mutex lock; /* protects the state of the mux */
@@ -51,6 +54,9 @@ struct mux_control {
unsigned int states;
int idle_state;
+
+ atomic_t use_count;
+ bool shared;
};
/**