All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 01/14] mux: core: Add mux_control_get_optional() API
@ 2017-09-22 18:37 ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb, Stephen Boyd

From: Stephen Boyd <stephen.boyd@linaro.org>

Sometimes drivers only use muxes under certain scenarios. For
example, the chipidea usb controller may be connected to a usb
switch on some platforms, and connected directly to a usb port on
others. The driver won't know one way or the other though, so add
a mux_control_get_optional() API that allows the driver to
differentiate errors getting the mux from there not being a mux
for the driver to use at all.

Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 Documentation/driver-model/devres.txt |   1 +
 drivers/mux/core.c                    | 104 +++++++++++++++++++++++++++-------
 include/linux/mux/consumer.h          |   4 ++
 3 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 69f08c0f23a8..5e41f3ac8a05 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -343,6 +343,7 @@ MUX
   devm_mux_chip_alloc()
   devm_mux_chip_register()
   devm_mux_control_get()
+  devm_mux_control_get_optional()
 
 PER-CPU MEM
   devm_alloc_percpu()
diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 6e5cf9d9cd99..244bceb17877 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -289,6 +289,9 @@ EXPORT_SYMBOL_GPL(devm_mux_chip_register);
  */
 unsigned int mux_control_states(struct mux_control *mux)
 {
+	if (!mux)
+		return 0;
+
 	return mux->states;
 }
 EXPORT_SYMBOL_GPL(mux_control_states);
@@ -338,6 +341,9 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
 {
 	int ret;
 
+	if (!mux)
+		return 0;
+
 	ret = down_killable(&mux->lock);
 	if (ret < 0)
 		return ret;
@@ -370,6 +376,9 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
 {
 	int ret;
 
+	if (!mux)
+		return 0;
+
 	if (down_trylock(&mux->lock))
 		return -EBUSY;
 
@@ -398,6 +407,9 @@ int mux_control_deselect(struct mux_control *mux)
 {
 	int ret = 0;
 
+	if (!mux)
+		return 0;
+
 	if (mux->idle_state != MUX_IDLE_AS_IS &&
 	    mux->idle_state != mux->cached_state)
 		ret = mux_control_set(mux, mux->idle_state);
@@ -423,14 +435,8 @@ 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 optional)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
@@ -442,16 +448,22 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (mux_name) {
 		index = of_property_match_string(np, "mux-control-names",
 						 mux_name);
+		if ((index == -EINVAL || index == -ENODATA) && optional)
+			return NULL;
 		if (index < 0) {
 			dev_err(dev, "mux controller '%s' not found\n",
 				mux_name);
 			return ERR_PTR(index);
 		}
+		/* OF does point to a mux, so it's no longer optional */
+		optional = false;
 	}
 
 	ret = of_parse_phandle_with_args(np,
 					 "mux-controls", "#mux-control-cells",
 					 index, &args);
+	if (ret == -ENOENT && optional)
+		return NULL;
 	if (ret) {
 		dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n",
 			np, mux_name ?: "", index);
@@ -484,8 +496,35 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 
 	return &mux_chip->mux[controller];
 }
+
+/**
+ * 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)
+{
+	return __mux_control_get(dev, mux_name, false);
+}
 EXPORT_SYMBOL_GPL(mux_control_get);
 
+/**
+ * mux_control_get_optional() - Get the optional mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: NULL if no mux with the provided name is found, a pointer to
+ * the named mux-control or an ERR_PTR with a negative errno.
+ */
+struct mux_control *
+mux_control_get_optional(struct device *dev, const char *mux_name)
+{
+	return __mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(mux_control_get_optional);
+
 /**
  * mux_control_put() - Put away the mux-control for good.
  * @mux: The mux-control to put away.
@@ -494,6 +533,9 @@ EXPORT_SYMBOL_GPL(mux_control_get);
  */
 void mux_control_put(struct mux_control *mux)
 {
+	if (!mux)
+		return;
+
 	put_device(&mux->chip->dev);
 }
 EXPORT_SYMBOL_GPL(mux_control_put);
@@ -505,16 +547,8 @@ 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 optional)
 {
 	struct mux_control **ptr, *mux;
 
@@ -522,8 +556,8 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	mux = mux_control_get(dev, mux_name);
-	if (IS_ERR(mux)) {
+	mux = __mux_control_get(dev, mux_name, optional);
+	if (IS_ERR_OR_NULL(mux)) {
 		devres_free(ptr);
 		return mux;
 	}
@@ -533,8 +567,38 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 
 	return 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)
+{
+	return __devm_mux_control_get(dev, mux_name, false);
+}
 EXPORT_SYMBOL_GPL(devm_mux_control_get);
 
+/**
+ * devm_mux_control_get_optional() - Get the optional 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: NULL if no mux with the provided name is found, a pointer to
+ * the named mux-control or an ERR_PTR with a negative errno.
+ */
+struct mux_control *
+devm_mux_control_get_optional(struct device *dev, const char *mux_name)
+{
+	return __devm_mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_optional);
+
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
  * the non-modular case - that the subsystem is initialized when mux consumers
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index ea96d4c82be7..fc98547bf494 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -26,9 +26,13 @@ int __must_check mux_control_try_select(struct mux_control *mux,
 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_optional(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_optional(struct device *dev,
+						  const char *mux_name);
 
 #endif /* _LINUX_MUX_CONSUMER_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 01/14] mux: core: Add mux_control_get_optional() API
@ 2017-09-22 18:37 ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb, Stephen Boyd

From: Stephen Boyd <stephen.boyd@linaro.org>

Sometimes drivers only use muxes under certain scenarios. For
example, the chipidea usb controller may be connected to a usb
switch on some platforms, and connected directly to a usb port on
others. The driver won't know one way or the other though, so add
a mux_control_get_optional() API that allows the driver to
differentiate errors getting the mux from there not being a mux
for the driver to use at all.

Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 Documentation/driver-model/devres.txt |   1 +
 drivers/mux/core.c                    | 104 +++++++++++++++++++++++++++-------
 include/linux/mux/consumer.h          |   4 ++
 3 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 69f08c0f23a8..5e41f3ac8a05 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -343,6 +343,7 @@ MUX
   devm_mux_chip_alloc()
   devm_mux_chip_register()
   devm_mux_control_get()
+  devm_mux_control_get_optional()
 
 PER-CPU MEM
   devm_alloc_percpu()
diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 6e5cf9d9cd99..244bceb17877 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -289,6 +289,9 @@ EXPORT_SYMBOL_GPL(devm_mux_chip_register);
  */
 unsigned int mux_control_states(struct mux_control *mux)
 {
+	if (!mux)
+		return 0;
+
 	return mux->states;
 }
 EXPORT_SYMBOL_GPL(mux_control_states);
@@ -338,6 +341,9 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
 {
 	int ret;
 
+	if (!mux)
+		return 0;
+
 	ret = down_killable(&mux->lock);
 	if (ret < 0)
 		return ret;
@@ -370,6 +376,9 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
 {
 	int ret;
 
+	if (!mux)
+		return 0;
+
 	if (down_trylock(&mux->lock))
 		return -EBUSY;
 
@@ -398,6 +407,9 @@ int mux_control_deselect(struct mux_control *mux)
 {
 	int ret = 0;
 
+	if (!mux)
+		return 0;
+
 	if (mux->idle_state != MUX_IDLE_AS_IS &&
 	    mux->idle_state != mux->cached_state)
 		ret = mux_control_set(mux, mux->idle_state);
@@ -423,14 +435,8 @@ 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 optional)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
@@ -442,16 +448,22 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (mux_name) {
 		index = of_property_match_string(np, "mux-control-names",
 						 mux_name);
+		if ((index == -EINVAL || index == -ENODATA) && optional)
+			return NULL;
 		if (index < 0) {
 			dev_err(dev, "mux controller '%s' not found\n",
 				mux_name);
 			return ERR_PTR(index);
 		}
+		/* OF does point to a mux, so it's no longer optional */
+		optional = false;
 	}
 
 	ret = of_parse_phandle_with_args(np,
 					 "mux-controls", "#mux-control-cells",
 					 index, &args);
+	if (ret == -ENOENT && optional)
+		return NULL;
 	if (ret) {
 		dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n",
 			np, mux_name ?: "", index);
@@ -484,8 +496,35 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 
 	return &mux_chip->mux[controller];
 }
+
+/**
+ * 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)
+{
+	return __mux_control_get(dev, mux_name, false);
+}
 EXPORT_SYMBOL_GPL(mux_control_get);
 
+/**
+ * mux_control_get_optional() - Get the optional mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: NULL if no mux with the provided name is found, a pointer to
+ * the named mux-control or an ERR_PTR with a negative errno.
+ */
+struct mux_control *
+mux_control_get_optional(struct device *dev, const char *mux_name)
+{
+	return __mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(mux_control_get_optional);
+
 /**
  * mux_control_put() - Put away the mux-control for good.
  * @mux: The mux-control to put away.
@@ -494,6 +533,9 @@ EXPORT_SYMBOL_GPL(mux_control_get);
  */
 void mux_control_put(struct mux_control *mux)
 {
+	if (!mux)
+		return;
+
 	put_device(&mux->chip->dev);
 }
 EXPORT_SYMBOL_GPL(mux_control_put);
@@ -505,16 +547,8 @@ 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 optional)
 {
 	struct mux_control **ptr, *mux;
 
@@ -522,8 +556,8 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	mux = mux_control_get(dev, mux_name);
-	if (IS_ERR(mux)) {
+	mux = __mux_control_get(dev, mux_name, optional);
+	if (IS_ERR_OR_NULL(mux)) {
 		devres_free(ptr);
 		return mux;
 	}
@@ -533,8 +567,38 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 
 	return 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)
+{
+	return __devm_mux_control_get(dev, mux_name, false);
+}
 EXPORT_SYMBOL_GPL(devm_mux_control_get);
 
+/**
+ * devm_mux_control_get_optional() - Get the optional 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: NULL if no mux with the provided name is found, a pointer to
+ * the named mux-control or an ERR_PTR with a negative errno.
+ */
+struct mux_control *
+devm_mux_control_get_optional(struct device *dev, const char *mux_name)
+{
+	return __devm_mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_optional);
+
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
  * the non-modular case - that the subsystem is initialized when mux consumers
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index ea96d4c82be7..fc98547bf494 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -26,9 +26,13 @@ int __must_check mux_control_try_select(struct mux_control *mux,
 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_optional(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_optional(struct device *dev,
+						  const char *mux_name);
 
 #endif /* _LINUX_MUX_CONSUMER_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 02/14] mux: core: Add explicit hook to leave the mux as-is on init/registration
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

From: Peter Rosin <peda@axentia.se>

A board may need a mux controller to stay as-is for a while longer, e.g.
if setting the normally preferred idle state destroys booting.

The mechanism provided here is not perfect in two ways.
1. As soon as the mux controller is registered, some mux consumer can
   access it and set a state that destroys booting all the same.
2. The mux controller might linger in a state that is not the
   preferred idle state indefinitely, if no mux consumer ever selects
   and then deselects the mux.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/mux/core.c         | 3 +++
 include/linux/mux/driver.h | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 244bceb17877..d0ad56abca2a 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -155,6 +155,9 @@ int mux_chip_register(struct mux_chip *mux_chip)
 	for (i = 0; i < mux_chip->controllers; ++i) {
 		struct mux_control *mux = &mux_chip->mux[i];
 
+		if (mux->init_as_is)
+			continue;
+
 		if (mux->idle_state == mux->cached_state)
 			continue;
 
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 35c3579c3304..21cf6041a962 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -36,6 +36,9 @@ struct mux_control_ops {
  * @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.
+ * @init_as_is:		Set to true to have the core leave the mux controller
+ *			state as-is until first selection. If @idle_state is
+ *			MUX_IDLE_AS_IS, @init_as_is is irrelevant.
  *
  * Mux drivers may only change @states and @idle_state, and may only do so
  * between allocation and registration of the mux controller. Specifically,
@@ -50,6 +53,7 @@ struct mux_control {
 
 	unsigned int states;
 	int idle_state;
+	bool init_as_is;
 };
 
 /**
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 02/14] mux: core: Add explicit hook to leave the mux as-is on init/registration
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

From: Peter Rosin <peda@axentia.se>

A board may need a mux controller to stay as-is for a while longer, e.g.
if setting the normally preferred idle state destroys booting.

The mechanism provided here is not perfect in two ways.
1. As soon as the mux controller is registered, some mux consumer can
   access it and set a state that destroys booting all the same.
2. The mux controller might linger in a state that is not the
   preferred idle state indefinitely, if no mux consumer ever selects
   and then deselects the mux.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/mux/core.c         | 3 +++
 include/linux/mux/driver.h | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 244bceb17877..d0ad56abca2a 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -155,6 +155,9 @@ int mux_chip_register(struct mux_chip *mux_chip)
 	for (i = 0; i < mux_chip->controllers; ++i) {
 		struct mux_control *mux = &mux_chip->mux[i];
 
+		if (mux->init_as_is)
+			continue;
+
 		if (mux->idle_state == mux->cached_state)
 			continue;
 
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 35c3579c3304..21cf6041a962 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -36,6 +36,9 @@ struct mux_control_ops {
  * @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.
+ * @init_as_is:		Set to true to have the core leave the mux controller
+ *			state as-is until first selection. If @idle_state is
+ *			MUX_IDLE_AS_IS, @init_as_is is irrelevant.
  *
  * Mux drivers may only change @states and @idle_state, and may only do so
  * between allocation and registration of the mux controller. Specifically,
@@ -50,6 +53,7 @@ struct mux_control {
 
 	unsigned int states;
 	int idle_state;
+	bool init_as_is;
 };
 
 /**
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 03/14] mux: core: Add of_mux_control_get helper function
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Currently the mux_control_get implementation only deals with getting
mux controllers on DT platforms. This commit renames the current
implementation to of_mux_control_get to reflect this and makes
mux_control_get a wrapper around of_mux_control_get.

This is a preparation patch for adding support for getting muxes on
non DT platforms.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/mux/core.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index d0ad56abca2a..8c0a4c83cdc5 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -439,7 +439,7 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 }
 
 static struct mux_control *
-__mux_control_get(struct device *dev, const char *mux_name, bool optional)
+of_mux_control_get(struct device *dev, const char *mux_name, bool optional)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
@@ -500,6 +500,16 @@ __mux_control_get(struct device *dev, const char *mux_name, bool optional)
 	return &mux_chip->mux[controller];
 }
 
+static struct mux_control *
+__mux_control_get(struct device *dev, const char *mux_name, bool optional)
+{
+	/* look up via DT first */
+	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+		return of_mux_control_get(dev, mux_name, optional);
+
+	return optional ? NULL : ERR_PTR(-ENODEV);
+}
+
 /**
  * mux_control_get() - Get the mux-control for a device.
  * @dev: The device that needs a mux-control.
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 03/14] mux: core: Add of_mux_control_get helper function
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

Currently the mux_control_get implementation only deals with getting
mux controllers on DT platforms. This commit renames the current
implementation to of_mux_control_get to reflect this and makes
mux_control_get a wrapper around of_mux_control_get.

This is a preparation patch for adding support for getting muxes on
non DT platforms.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/mux/core.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index d0ad56abca2a..8c0a4c83cdc5 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -439,7 +439,7 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 }
 
 static struct mux_control *
-__mux_control_get(struct device *dev, const char *mux_name, bool optional)
+of_mux_control_get(struct device *dev, const char *mux_name, bool optional)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
@@ -500,6 +500,16 @@ __mux_control_get(struct device *dev, const char *mux_name, bool optional)
 	return &mux_chip->mux[controller];
 }
 
+static struct mux_control *
+__mux_control_get(struct device *dev, const char *mux_name, bool optional)
+{
+	/* look up via DT first */
+	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+		return of_mux_control_get(dev, mux_name, optional);
+
+	return optional ? NULL : ERR_PTR(-ENODEV);
+}
+
 /**
  * mux_control_get() - Get the mux-control for a device.
  * @dev: The device that needs a mux-control.
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 04/14] mux: core: Add support for getting a mux controller on a non DT platform
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

On non DT platforms we cannot get the mux_chip by pnode. Other subsystems
(regulator, clock, pwm) have the same problem and solve this by allowing
platform / board-setup code to add entries to a lookup table and then use
this table to look things up.

This commit adds support for getting a mux controller on a non DT platform
following this pattern. It is based on a simplified version of the pwm
subsys lookup code, the dev_id and mux_name parts of a lookup table entry
are mandatory in the mux-core implementation.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Fixup some kerneldoc comments, add kerneldoc comment to structs
-Minor code-style tweaks
---
 drivers/mux/core.c           | 93 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mux/consumer.h | 19 +++++++++
 2 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 8c0a4c83cdc5..c9afc79196f0 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -24,6 +24,9 @@
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 
+static DEFINE_MUTEX(mux_lookup_lock);
+static LIST_HEAD(mux_lookup_list);
+
 /*
  * The idle-as-is "state" is not an actual state that may be selected, it
  * only implies that the state should not be changed. So, use that state
@@ -423,6 +426,23 @@ int mux_control_deselect(struct mux_control *mux)
 }
 EXPORT_SYMBOL_GPL(mux_control_deselect);
 
+static int parent_name_match(struct device *dev, const void *data)
+{
+	const char *parent_name = dev_name(dev->parent);
+	const char *name = data;
+
+	return strcmp(parent_name, name) == 0;
+}
+
+static struct mux_chip *mux_chip_get_by_name(const char *name)
+{
+	struct device *dev;
+
+	dev = class_find_device(&mux_class, NULL, name, parent_name_match);
+
+	return dev ? to_mux_chip(dev) : NULL;
+}
+
 static int of_dev_node_match(struct device *dev, const void *data)
 {
 	return dev->of_node == data;
@@ -503,12 +523,83 @@ of_mux_control_get(struct device *dev, const char *mux_name, bool optional)
 static struct mux_control *
 __mux_control_get(struct device *dev, const char *mux_name, bool optional)
 {
+	struct mux_lookup *m, *chosen = NULL;
+	const char *dev_id = dev_name(dev);
+	struct mux_chip *mux_chip;
+
 	/* look up via DT first */
 	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
 		return of_mux_control_get(dev, mux_name, optional);
 
-	return optional ? NULL : ERR_PTR(-ENODEV);
+	/*
+	 * For non DT we look up the provider in the static table typically
+	 * provided by board setup code.
+	 *
+	 * If a match is found, the provider mux chip is looked up by name
+	 * and a mux-control is requested using the table provided index.
+	 */
+	mutex_lock(&mux_lookup_lock);
+	list_for_each_entry(m, &mux_lookup_list, list) {
+		if (WARN_ON(!m->dev_id || !m->mux_name || !m->provider))
+			continue;
+
+		if (!strcmp(m->dev_id, dev_id) &&
+		    !strcmp(m->mux_name, mux_name))
+		{
+			chosen = m;
+			break;
+		}
+	}
+	mutex_unlock(&mux_lookup_lock);
+
+	if (!chosen)
+		return optional ? NULL : ERR_PTR(-ENODEV);
+
+	mux_chip = mux_chip_get_by_name(chosen->provider);
+	if (!mux_chip)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (chosen->index >= mux_chip->controllers) {
+		dev_err(dev, "Mux lookup table index out of bounds %u >= %u\n",
+			chosen->index, mux_chip->controllers);
+		put_device(&mux_chip->dev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return &mux_chip->mux[chosen->index];
+}
+
+/**
+ * mux_add_table() - Register consumer to mux-controller mappings
+ * @table: array of mappings to register
+ * @num: number of mappings in table
+ */
+void mux_add_table(struct mux_lookup *table, size_t num)
+{
+	mutex_lock(&mux_lookup_lock);
+
+	for (; num--; table++)
+		list_add_tail(&table->list, &mux_lookup_list);
+
+	mutex_unlock(&mux_lookup_lock);
+}
+EXPORT_SYMBOL_GPL(mux_add_table);
+
+/**
+ * mux_remove_table() - Unregister consumer to mux-controller mappings
+ * @table: array of mappings to unregister
+ * @num: number of mappings in table
+ */
+void mux_remove_table(struct mux_lookup *table, size_t num)
+{
+	mutex_lock(&mux_lookup_lock);
+
+	for (; num--; table++)
+		list_del(&table->list);
+
+	mutex_unlock(&mux_lookup_lock);
 }
+EXPORT_SYMBOL_GPL(mux_remove_table);
 
 /**
  * mux_control_get() - Get the mux-control for a device.
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index fc98547bf494..eaa6d239c4f5 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -18,6 +18,25 @@
 struct device;
 struct mux_control;
 
+/**
+ * struct mux_lookup -	Mux consumer to mux-controller lookup table entry
+ * @list:		List head, internal use only.
+ * @provider:		dev_name() of the mux-chip's parent-dev.
+ * @index:		mux-controller's index in the mux-chip's mux array
+ * @dev_id:		dev_name() of the consumer to map to this controller
+ * @mux_name		name the consumer passes to mux_control_get
+ */
+struct mux_lookup {
+	struct list_head list;
+	const char *provider;
+	unsigned int index;
+	const char *dev_id;
+	const char *mux_name;
+};
+
+void mux_add_table(struct mux_lookup *table, size_t num);
+void mux_remove_table(struct mux_lookup *table, size_t num);
+
 unsigned int mux_control_states(struct mux_control *mux);
 int __must_check mux_control_select(struct mux_control *mux,
 				    unsigned int state);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 04/14] mux: core: Add support for getting a mux controller on a non DT platform
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

On non DT platforms we cannot get the mux_chip by pnode. Other subsystems
(regulator, clock, pwm) have the same problem and solve this by allowing
platform / board-setup code to add entries to a lookup table and then use
this table to look things up.

This commit adds support for getting a mux controller on a non DT platform
following this pattern. It is based on a simplified version of the pwm
subsys lookup code, the dev_id and mux_name parts of a lookup table entry
are mandatory in the mux-core implementation.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Fixup some kerneldoc comments, add kerneldoc comment to structs
-Minor code-style tweaks
---
 drivers/mux/core.c           | 93 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mux/consumer.h | 19 +++++++++
 2 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 8c0a4c83cdc5..c9afc79196f0 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -24,6 +24,9 @@
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 
+static DEFINE_MUTEX(mux_lookup_lock);
+static LIST_HEAD(mux_lookup_list);
+
 /*
  * The idle-as-is "state" is not an actual state that may be selected, it
  * only implies that the state should not be changed. So, use that state
@@ -423,6 +426,23 @@ int mux_control_deselect(struct mux_control *mux)
 }
 EXPORT_SYMBOL_GPL(mux_control_deselect);
 
+static int parent_name_match(struct device *dev, const void *data)
+{
+	const char *parent_name = dev_name(dev->parent);
+	const char *name = data;
+
+	return strcmp(parent_name, name) == 0;
+}
+
+static struct mux_chip *mux_chip_get_by_name(const char *name)
+{
+	struct device *dev;
+
+	dev = class_find_device(&mux_class, NULL, name, parent_name_match);
+
+	return dev ? to_mux_chip(dev) : NULL;
+}
+
 static int of_dev_node_match(struct device *dev, const void *data)
 {
 	return dev->of_node == data;
@@ -503,12 +523,83 @@ of_mux_control_get(struct device *dev, const char *mux_name, bool optional)
 static struct mux_control *
 __mux_control_get(struct device *dev, const char *mux_name, bool optional)
 {
+	struct mux_lookup *m, *chosen = NULL;
+	const char *dev_id = dev_name(dev);
+	struct mux_chip *mux_chip;
+
 	/* look up via DT first */
 	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
 		return of_mux_control_get(dev, mux_name, optional);
 
-	return optional ? NULL : ERR_PTR(-ENODEV);
+	/*
+	 * For non DT we look up the provider in the static table typically
+	 * provided by board setup code.
+	 *
+	 * If a match is found, the provider mux chip is looked up by name
+	 * and a mux-control is requested using the table provided index.
+	 */
+	mutex_lock(&mux_lookup_lock);
+	list_for_each_entry(m, &mux_lookup_list, list) {
+		if (WARN_ON(!m->dev_id || !m->mux_name || !m->provider))
+			continue;
+
+		if (!strcmp(m->dev_id, dev_id) &&
+		    !strcmp(m->mux_name, mux_name))
+		{
+			chosen = m;
+			break;
+		}
+	}
+	mutex_unlock(&mux_lookup_lock);
+
+	if (!chosen)
+		return optional ? NULL : ERR_PTR(-ENODEV);
+
+	mux_chip = mux_chip_get_by_name(chosen->provider);
+	if (!mux_chip)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (chosen->index >= mux_chip->controllers) {
+		dev_err(dev, "Mux lookup table index out of bounds %u >= %u\n",
+			chosen->index, mux_chip->controllers);
+		put_device(&mux_chip->dev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return &mux_chip->mux[chosen->index];
+}
+
+/**
+ * mux_add_table() - Register consumer to mux-controller mappings
+ * @table: array of mappings to register
+ * @num: number of mappings in table
+ */
+void mux_add_table(struct mux_lookup *table, size_t num)
+{
+	mutex_lock(&mux_lookup_lock);
+
+	for (; num--; table++)
+		list_add_tail(&table->list, &mux_lookup_list);
+
+	mutex_unlock(&mux_lookup_lock);
+}
+EXPORT_SYMBOL_GPL(mux_add_table);
+
+/**
+ * mux_remove_table() - Unregister consumer to mux-controller mappings
+ * @table: array of mappings to unregister
+ * @num: number of mappings in table
+ */
+void mux_remove_table(struct mux_lookup *table, size_t num)
+{
+	mutex_lock(&mux_lookup_lock);
+
+	for (; num--; table++)
+		list_del(&table->list);
+
+	mutex_unlock(&mux_lookup_lock);
 }
+EXPORT_SYMBOL_GPL(mux_remove_table);
 
 /**
  * mux_control_get() - Get the mux-control for a device.
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index fc98547bf494..eaa6d239c4f5 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -18,6 +18,25 @@
 struct device;
 struct mux_control;
 
+/**
+ * struct mux_lookup -	Mux consumer to mux-controller lookup table entry
+ * @list:		List head, internal use only.
+ * @provider:		dev_name() of the mux-chip's parent-dev.
+ * @index:		mux-controller's index in the mux-chip's mux array
+ * @dev_id:		dev_name() of the consumer to map to this controller
+ * @mux_name		name the consumer passes to mux_control_get
+ */
+struct mux_lookup {
+	struct list_head list;
+	const char *provider;
+	unsigned int index;
+	const char *dev_id;
+	const char *mux_name;
+};
+
+void mux_add_table(struct mux_lookup *table, size_t num);
+void mux_remove_table(struct mux_lookup *table, size_t num);
+
 unsigned int mux_control_states(struct mux_control *mux);
 int __must_check mux_control_select(struct mux_control *mux,
 				    unsigned int state);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 05/14] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Add MUX_USB_* and MUX_TYPEC_* state constant defines, which can be used by
USB device/host, resp. Type-C polarity/role/altmode mux drivers and
consumers to ensure that they agree on the meaning of the
mux_control_select() state argument.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Start numbering of defines at 0 not 1
-Use a new usb.h header, rather then adding these to consumer.h
-Add separate MUX_USB_* and MUX_TYPEC_* defines

Changes in v3:
-Simplify MUX_TYPEC_* states, drop having separate USB HOST / DEVICE states
---
 include/linux/mux/usb.h | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 include/linux/mux/usb.h

diff --git a/include/linux/mux/usb.h b/include/linux/mux/usb.h
new file mode 100644
index 000000000000..2fec06846e14
--- /dev/null
+++ b/include/linux/mux/usb.h
@@ -0,0 +1,31 @@
+/*
+ * mux/usb.h - definitions for USB multiplexers
+ *
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_MUX_USB_H
+#define _LINUX_MUX_USB_H
+
+/* Mux state values for USB device/host role muxes */
+#define MUX_USB_DEVICE		(0) /* USB device mode */
+#define MUX_USB_HOST		(1) /* USB host mode */
+#define MUX_USB_STATES		(2)
+
+/*
+ * Mux state values for Type-C polarity/role/altmode muxes.
+ *
+ * MUX_TYPEC_POLARITY_INV may be or-ed together with any other mux-state as
+ * inverted-polarity (Type-C plugged in upside down) can happen with any
+ * other mux-state.
+ */
+#define MUX_TYPEC_POLARITY_INV		BIT(0)   /* Polarity inverted bit */
+#define MUX_TYPEC_USB			(0 << 1) /* USB only mode */
+#define MUX_TYPEC_USB_AND_DP		(1 << 1) /* USB host + 2 lanes DP */
+#define MUX_TYPEC_DP			(2 << 1) /* 4 lanes Display Port */
+#define MUX_TYPEC_STATES		(3 << 1)
+
+#endif /* _LINUX_MUX_TYPEC_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 05/14] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

Add MUX_USB_* and MUX_TYPEC_* state constant defines, which can be used by
USB device/host, resp. Type-C polarity/role/altmode mux drivers and
consumers to ensure that they agree on the meaning of the
mux_control_select() state argument.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Start numbering of defines at 0 not 1
-Use a new usb.h header, rather then adding these to consumer.h
-Add separate MUX_USB_* and MUX_TYPEC_* defines

Changes in v3:
-Simplify MUX_TYPEC_* states, drop having separate USB HOST / DEVICE states
---
 include/linux/mux/usb.h | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 include/linux/mux/usb.h

diff --git a/include/linux/mux/usb.h b/include/linux/mux/usb.h
new file mode 100644
index 000000000000..2fec06846e14
--- /dev/null
+++ b/include/linux/mux/usb.h
@@ -0,0 +1,31 @@
+/*
+ * mux/usb.h - definitions for USB multiplexers
+ *
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_MUX_USB_H
+#define _LINUX_MUX_USB_H
+
+/* Mux state values for USB device/host role muxes */
+#define MUX_USB_DEVICE		(0) /* USB device mode */
+#define MUX_USB_HOST		(1) /* USB host mode */
+#define MUX_USB_STATES		(2)
+
+/*
+ * Mux state values for Type-C polarity/role/altmode muxes.
+ *
+ * MUX_TYPEC_POLARITY_INV may be or-ed together with any other mux-state as
+ * inverted-polarity (Type-C plugged in upside down) can happen with any
+ * other mux-state.
+ */
+#define MUX_TYPEC_POLARITY_INV		BIT(0)   /* Polarity inverted bit */
+#define MUX_TYPEC_USB			(0 << 1) /* USB only mode */
+#define MUX_TYPEC_USB_AND_DP		(1 << 1) /* USB host + 2 lanes DP */
+#define MUX_TYPEC_DP			(2 << 1) /* 4 lanes Display Port */
+#define MUX_TYPEC_STATES		(3 << 1)
+
+#endif /* _LINUX_MUX_TYPEC_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 06/14] xhci: Add option to get next extended capability in list by passing id = 0
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb, Mathias Nyman

From: Mathias Nyman <mathias.nyman@linux.intel.com>

Modify xhci_find_next_ext_cap(base, offset, id) to return the next
capability offset if 0 is passed for id. Otherwise it will behave as
previously and return the offset of the next capability with matching id

capability id 0 is not used by xhci (reserved)

This is useful when we want to loop through all capabilities.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/host/xhci-ext-caps.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 28deea584884..c1b404224839 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -96,7 +96,8 @@
  * @base	PCI MMIO registers base address.
  * @start	address at which to start looking, (0 or HCC_PARAMS to start at
  *		beginning of list)
- * @id		Extended capability ID to search for.
+ * @id		Extended capability ID to search for, or 0 for the next
+ *		capability
  *
  * Returns the offset of the next matching extended capability structure.
  * Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL,
@@ -122,7 +123,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
 		val = readl(base + offset);
 		if (val == ~0)
 			return 0;
-		if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
+		if (offset != start && (id == 0 || XHCI_EXT_CAPS_ID(val) == id))
 			return offset;
 
 		next = XHCI_EXT_CAPS_NEXT(val);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 06/14] xhci: Add option to get next extended capability in list by passing id = 0
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Mathias Nyman,
	Greg Kroah-Hartman, linux-usb, linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

From: Mathias Nyman <mathias.nyman@linux.intel.com>

Modify xhci_find_next_ext_cap(base, offset, id) to return the next
capability offset if 0 is passed for id. Otherwise it will behave as
previously and return the offset of the next capability with matching id

capability id 0 is not used by xhci (reserved)

This is useful when we want to loop through all capabilities.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/host/xhci-ext-caps.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 28deea584884..c1b404224839 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -96,7 +96,8 @@
  * @base	PCI MMIO registers base address.
  * @start	address at which to start looking, (0 or HCC_PARAMS to start at
  *		beginning of list)
- * @id		Extended capability ID to search for.
+ * @id		Extended capability ID to search for, or 0 for the next
+ *		capability
  *
  * Returns the offset of the next matching extended capability structure.
  * Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL,
@@ -122,7 +123,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
 		val = readl(base + offset);
 		if (val == ~0)
 			return 0;
-		if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
+		if (offset != start && (id == 0 || XHCI_EXT_CAPS_ID(val) == id))
 			return offset;
 
 		next = XHCI_EXT_CAPS_NEXT(val);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 07/14] xhci: Add Intel cherrytrail extended cap / otg phy mux handling
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

The Intel cherrytrail xhci controller has an extended cap mmio-range
which contains registers to control the muxing to the xhci (host mode)
or the dwc3 (device mode) and vbus-detection for the otg usb-phy.

Having a mux driver included in the xhci code (or under drivers/usb/host)
is not desirable. So this commit adds a simple handler for this extended
capability, which creates a platform device with the caps mmio region as
resource, this allows us to write a separate platform mux driver for the
mux.

Note this commit adds a call to the new xhci_ext_cap_init() function
to xhci_pci_probe(), it is added here because xhci_ext_cap_init() must
be called only once. If in the future we also want to handle ext-caps
on non pci XHCI HCDs from xhci_ext_cap_init() a call to it should also
be added to other bus probe paths.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Check xHCI controller PCI device-id instead of only checking for the
 Intel Extended capability ID, as the Extended capability ID is used on
 other model Intel xHCI controllers too

Changes in v3:
-Add a new generic xhci_ext_cap_init() function and handle the new
 XHCI_INTEL_CHT_USB_MUX quirk there.
---
 drivers/usb/host/Makefile        |  2 +-
 drivers/usb/host/xhci-ext-caps.c | 88 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-ext-caps.h |  2 +
 drivers/usb/host/xhci-pci.c      |  5 +++
 drivers/usb/host/xhci.h          |  2 +
 5 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/xhci-ext-caps.c

diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index cf2691fffcc0..59329a9cf392 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -10,7 +10,7 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
 
 fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
 
-xhci-hcd-y := xhci.o xhci-mem.o
+xhci-hcd-y := xhci.o xhci-mem.o xhci-ext-caps.o
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
 xhci-hcd-y += xhci-trace.o
 ifneq ($(CONFIG_USB_XHCI_MTK), )
diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
new file mode 100644
index 000000000000..8bc4787afdd0
--- /dev/null
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -0,0 +1,88 @@
+/*
+ * XHCI extended capability handling
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include "xhci.h"
+
+static void xhci_intel_unregister_pdev(void *arg)
+{
+	platform_device_unregister(arg);
+}
+
+static int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci, u32 cap_offset)
+{
+	struct usb_hcd *hcd = xhci_to_hcd(xhci);
+	struct device *dev = hcd->self.controller;
+	struct platform_device *pdev;
+	struct resource	res = { 0, };
+	int ret;
+
+	pdev = platform_device_alloc("intel_cht_usb_mux", PLATFORM_DEVID_NONE);
+	if (!pdev) {
+		xhci_err(xhci, "couldn't allocate intel_cht_usb_mux pdev\n");
+		return -ENOMEM;
+	}
+
+	res.start = hcd->rsrc_start + cap_offset;
+	res.end	  = res.start + 0x3ff;
+	res.name  = "intel_cht_usb_mux";
+	res.flags = IORESOURCE_MEM;
+
+	ret = platform_device_add_resources(pdev, &res, 1);
+	if (ret) {
+		dev_err(dev, "couldn't add resources to intel_cht_usb_mux pdev\n");
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	pdev->dev.parent = dev;
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		dev_err(dev, "couldn't register intel_cht_usb_mux pdev\n");
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);
+	if (ret) {
+		dev_err(dev, "couldn't add unregister action for intel_cht_usb_mux pdev\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int xhci_ext_cap_init(struct xhci_hcd *xhci)
+{
+	void __iomem *base = &xhci->cap_regs->hc_capbase;
+	u32 cap_offset, val;
+	int ret;
+
+	cap_offset = xhci_find_next_ext_cap(base, 0, 0);
+
+	while (cap_offset) {
+		val = readl(base + cap_offset);
+
+		switch (XHCI_EXT_CAPS_ID(val)) {
+		case XHCI_EXT_CAPS_VENDOR_INTEL:
+			if (xhci->quirks & XHCI_INTEL_CHT_USB_MUX) {
+				ret = xhci_create_intel_cht_mux_pdev(
+							    xhci, cap_offset);
+				if (ret)
+					return ret;
+			}
+			break;
+		}
+		cap_offset = xhci_find_next_ext_cap(base, cap_offset, 0);
+	}
+
+	return 0;
+}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index c1b404224839..872fbec1347f 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -51,6 +51,8 @@
 #define XHCI_EXT_CAPS_ROUTE	5
 /* IDs 6-9 reserved */
 #define XHCI_EXT_CAPS_DEBUG	10
+/* Vendor caps */
+#define XHCI_EXT_CAPS_VENDOR_INTEL	192
 /* USB Legacy Support Capability - section 7.1.1 */
 #define XHCI_HC_BIOS_OWNED	(1 << 16)
 #define XHCI_HC_OS_OWNED	(1 << 24)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 8071c8fdd15e..f088c5012503 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -188,6 +188,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 		 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
 		xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
+		xhci->quirks |= XHCI_INTEL_CHT_USB_MUX;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 	    (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
@@ -315,6 +316,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto dealloc_usb2_hcd;
 	}
 
+	retval = xhci_ext_cap_init(xhci);
+	if (retval)
+		goto put_usb3_hcd;
+
 	retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
 			IRQF_SHARED);
 	if (retval)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2abaa4d6d39d..0b3ed0044b4d 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1828,6 +1828,7 @@ struct xhci_hcd {
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7	(1 << 26)
 #define XHCI_U2_DISABLE_WAKE	(1 << 27)
 #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL	(1 << 28)
+#define XHCI_INTEL_CHT_USB_MUX	(1 << 29)
 
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
@@ -2012,6 +2013,7 @@ void xhci_init_driver(struct hc_driver *drv,
 		      const struct xhci_driver_overrides *over);
 int xhci_disable_slot(struct xhci_hcd *xhci,
 			struct xhci_command *command, u32 slot_id);
+int xhci_ext_cap_init(struct xhci_hcd *xhci);
 
 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 07/14] xhci: Add Intel cherrytrail extended cap / otg phy mux handling
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

The Intel cherrytrail xhci controller has an extended cap mmio-range
which contains registers to control the muxing to the xhci (host mode)
or the dwc3 (device mode) and vbus-detection for the otg usb-phy.

Having a mux driver included in the xhci code (or under drivers/usb/host)
is not desirable. So this commit adds a simple handler for this extended
capability, which creates a platform device with the caps mmio region as
resource, this allows us to write a separate platform mux driver for the
mux.

Note this commit adds a call to the new xhci_ext_cap_init() function
to xhci_pci_probe(), it is added here because xhci_ext_cap_init() must
be called only once. If in the future we also want to handle ext-caps
on non pci XHCI HCDs from xhci_ext_cap_init() a call to it should also
be added to other bus probe paths.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Check xHCI controller PCI device-id instead of only checking for the
 Intel Extended capability ID, as the Extended capability ID is used on
 other model Intel xHCI controllers too

Changes in v3:
-Add a new generic xhci_ext_cap_init() function and handle the new
 XHCI_INTEL_CHT_USB_MUX quirk there.
---
 drivers/usb/host/Makefile        |  2 +-
 drivers/usb/host/xhci-ext-caps.c | 88 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-ext-caps.h |  2 +
 drivers/usb/host/xhci-pci.c      |  5 +++
 drivers/usb/host/xhci.h          |  2 +
 5 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/xhci-ext-caps.c

diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index cf2691fffcc0..59329a9cf392 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -10,7 +10,7 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
 
 fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
 
-xhci-hcd-y := xhci.o xhci-mem.o
+xhci-hcd-y := xhci.o xhci-mem.o xhci-ext-caps.o
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
 xhci-hcd-y += xhci-trace.o
 ifneq ($(CONFIG_USB_XHCI_MTK), )
diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
new file mode 100644
index 000000000000..8bc4787afdd0
--- /dev/null
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -0,0 +1,88 @@
+/*
+ * XHCI extended capability handling
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include "xhci.h"
+
+static void xhci_intel_unregister_pdev(void *arg)
+{
+	platform_device_unregister(arg);
+}
+
+static int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci, u32 cap_offset)
+{
+	struct usb_hcd *hcd = xhci_to_hcd(xhci);
+	struct device *dev = hcd->self.controller;
+	struct platform_device *pdev;
+	struct resource	res = { 0, };
+	int ret;
+
+	pdev = platform_device_alloc("intel_cht_usb_mux", PLATFORM_DEVID_NONE);
+	if (!pdev) {
+		xhci_err(xhci, "couldn't allocate intel_cht_usb_mux pdev\n");
+		return -ENOMEM;
+	}
+
+	res.start = hcd->rsrc_start + cap_offset;
+	res.end	  = res.start + 0x3ff;
+	res.name  = "intel_cht_usb_mux";
+	res.flags = IORESOURCE_MEM;
+
+	ret = platform_device_add_resources(pdev, &res, 1);
+	if (ret) {
+		dev_err(dev, "couldn't add resources to intel_cht_usb_mux pdev\n");
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	pdev->dev.parent = dev;
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		dev_err(dev, "couldn't register intel_cht_usb_mux pdev\n");
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);
+	if (ret) {
+		dev_err(dev, "couldn't add unregister action for intel_cht_usb_mux pdev\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int xhci_ext_cap_init(struct xhci_hcd *xhci)
+{
+	void __iomem *base = &xhci->cap_regs->hc_capbase;
+	u32 cap_offset, val;
+	int ret;
+
+	cap_offset = xhci_find_next_ext_cap(base, 0, 0);
+
+	while (cap_offset) {
+		val = readl(base + cap_offset);
+
+		switch (XHCI_EXT_CAPS_ID(val)) {
+		case XHCI_EXT_CAPS_VENDOR_INTEL:
+			if (xhci->quirks & XHCI_INTEL_CHT_USB_MUX) {
+				ret = xhci_create_intel_cht_mux_pdev(
+							    xhci, cap_offset);
+				if (ret)
+					return ret;
+			}
+			break;
+		}
+		cap_offset = xhci_find_next_ext_cap(base, cap_offset, 0);
+	}
+
+	return 0;
+}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index c1b404224839..872fbec1347f 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -51,6 +51,8 @@
 #define XHCI_EXT_CAPS_ROUTE	5
 /* IDs 6-9 reserved */
 #define XHCI_EXT_CAPS_DEBUG	10
+/* Vendor caps */
+#define XHCI_EXT_CAPS_VENDOR_INTEL	192
 /* USB Legacy Support Capability - section 7.1.1 */
 #define XHCI_HC_BIOS_OWNED	(1 << 16)
 #define XHCI_HC_OS_OWNED	(1 << 24)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 8071c8fdd15e..f088c5012503 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -188,6 +188,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 		 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
 		xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
+		xhci->quirks |= XHCI_INTEL_CHT_USB_MUX;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
 	    (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
@@ -315,6 +316,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto dealloc_usb2_hcd;
 	}
 
+	retval = xhci_ext_cap_init(xhci);
+	if (retval)
+		goto put_usb3_hcd;
+
 	retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
 			IRQF_SHARED);
 	if (retval)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2abaa4d6d39d..0b3ed0044b4d 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1828,6 +1828,7 @@ struct xhci_hcd {
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7	(1 << 26)
 #define XHCI_U2_DISABLE_WAKE	(1 << 27)
 #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL	(1 << 28)
+#define XHCI_INTEL_CHT_USB_MUX	(1 << 29)
 
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
@@ -2012,6 +2013,7 @@ void xhci_init_driver(struct hc_driver *drv,
 		      const struct xhci_driver_overrides *over);
 int xhci_disable_slot(struct xhci_hcd *xhci,
 			struct xhci_command *command, u32 slot_id);
+int xhci_ext_cap_init(struct xhci_hcd *xhci);
 
 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 08/14] mux: Add Intel Cherrytrail USB mux driver
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Intel Cherrytrail SoCs have an internal USB mux for muxing the otg-port
USB data lines between the xHCI host controller and the dwc3 gadget
controller. On some Cherrytrail systems this mux is controlled through
AML code reacting on a GPIO IRQ connected to the USB OTG id pin (through
an _AIE ACPI method) so things just work.

But on other Cherrytrail systems we need to control the mux ourselves
this driver exports the mux through the mux subsys, so that other drivers
can control it if necessary.

This driver also updates the vbus-valid reporting to the dwc3 gadget
controller, as this uses the same registers as the mux. This is needed
for gadget/device mode to work properly (even on systems which control
the mux from their AML code).

Note this depends on the xhci driver registering a platform device
named "intel_cht_usb_mux", which has an IOMEM resource 0 which points
to the Intel Vendor Defined XHCI extended capabilities region.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Complete rewrite as a stand-alone platform-driver rather then as a phy
 driver, since this is just a mux, not a phy

Changes in v3:
-Make this a mux subsys driver instead of listening to USB_HOST extcon
 cable events and responding to those

Changes in v4 (of patch, v2 of new mux based series):
-Rename C-file to use - in name
-Add MAINTAINERS entry
-Various code-style fixes

Changes in v3 of new mux based series:
-Various code-style fixes
-Use new init_as_is mux flag
---
 MAINTAINERS                     |   5 +
 drivers/mux/Kconfig             |  11 ++
 drivers/mux/Makefile            |  10 +-
 drivers/mux/intel-cht-usb-mux.c | 251 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 273 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mux/intel-cht-usb-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 04e7a5b9d6bd..6cfa0e5f2d2b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9176,6 +9176,11 @@ F:	include/linux/dt-bindings/mux/
 F:	include/linux/mux/
 F:	drivers/mux/
 
+MULTIPLEXER SUBSYSTEM INTEL CHT USB MUX DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+S:	Maintained
+F:	drivers/mux/intel-cht-usb-mux.c
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 19e4e904c9bf..ebc04ae7ff30 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -34,6 +34,17 @@ config MUX_GPIO
 	  To compile the driver as a module, choose M here: the module will
 	  be called mux-gpio.
 
+config MUX_INTEL_CHT_USB_MUX
+	tristate "Intel Cherrytrail USB Multiplexer"
+	depends on ACPI && X86 && EXTCON
+	help
+	  This driver adds support for the internal USB mux for muxing the OTG
+	  USB data lines between the xHCI host controller and the dwc3 gadget
+	  controller found on Intel Cherrytrail SoCs.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-intel-cht-usb-mux.
+
 config MUX_MMIO
 	tristate "MMIO register bitfield-controlled Multiplexer"
 	depends on (OF && MFD_SYSCON) || COMPILE_TEST
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 0e1e59760e3f..6cf41be2754f 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -5,9 +5,11 @@
 mux-core-objs			:= core.o
 mux-adg792a-objs		:= adg792a.o
 mux-gpio-objs			:= gpio.o
+mux-intel-cht-usb-mux-objs	:= intel-cht-usb-mux.o
 mux-mmio-objs			:= mmio.o
 
-obj-$(CONFIG_MULTIPLEXER)	+= mux-core.o
-obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
-obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
-obj-$(CONFIG_MUX_MMIO)		+= mux-mmio.o
+obj-$(CONFIG_MULTIPLEXER)		+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)		+= mux-adg792a.o
+obj-$(CONFIG_MUX_GPIO)			+= mux-gpio.o
+obj-$(CONFIG_MUX_INTEL_CHT_USB_MUX)	+= mux-intel-cht-usb-mux.o
+obj-$(CONFIG_MUX_MMIO)			+= mux-mmio.o
diff --git a/drivers/mux/intel-cht-usb-mux.c b/drivers/mux/intel-cht-usb-mux.c
new file mode 100644
index 000000000000..726facefd479
--- /dev/null
+++ b/drivers/mux/intel-cht-usb-mux.c
@@ -0,0 +1,251 @@
+/*
+ * Intel Cherrytrail USB OTG MUX driver
+ *
+ * Copyright (c) 2016-2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Loosely based on android x86 kernel code which is:
+ *
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Author: Wu, Hao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/mux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+/* register definition */
+#define DUAL_ROLE_CFG0			0x68
+#define SW_VBUS_VALID			(1 << 24)
+#define SW_IDPIN_EN			(1 << 21)
+#define SW_IDPIN			(1 << 20)
+
+#define DUAL_ROLE_CFG1			0x6c
+#define HOST_MODE			(1 << 29)
+
+#define DUAL_ROLE_CFG1_POLL_TIMEOUT	1000
+
+#define DRV_NAME			"intel_cht_usb_mux"
+
+struct intel_cht_usb_data {
+	struct mutex cfg0_lock;
+	void __iomem *base;
+	struct extcon_dev *vbus_extcon;
+	struct notifier_block vbus_nb;
+	struct work_struct vbus_work;
+};
+
+struct intel_cht_extcon_info {
+	const char *hid;
+	int hrv;
+	const char *extcon;
+};
+
+static const struct intel_cht_extcon_info vbus_providers[] = {
+	{ .hid = "INT33F4", .hrv = -1, .extcon = "axp288_extcon" },
+	{ .hid = "INT34D3", .hrv =  3, .extcon = "cht_wcove_pwrsrc" },
+};
+
+static int intel_cht_usb_set_mux(struct mux_control *mux, int state)
+{
+	struct intel_cht_usb_data *data = mux_chip_priv(mux->chip);
+	unsigned long timeout;
+	bool host_mode;
+	u32 val;
+
+	mutex_lock(&data->cfg0_lock);
+
+	/* Set idpin value as requested */
+	val = readl(data->base + DUAL_ROLE_CFG0);
+	if (state == MUX_USB_DEVICE) {
+		val |= SW_IDPIN;
+		host_mode = false;
+	} else {
+		val &= ~SW_IDPIN;
+		host_mode = true;
+	}
+	val |= SW_IDPIN_EN;
+	writel(val, data->base + DUAL_ROLE_CFG0);
+
+	mutex_unlock(&data->cfg0_lock);
+
+	/* In most case it takes about 600ms to finish mode switching */
+	timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch.*/
+	do {
+		val = readl(data->base + DUAL_ROLE_CFG1);
+		if (!!(val & HOST_MODE) == host_mode)
+			return 0;
+
+		/* Interval for polling is set to about 5 - 10 ms */
+		usleep_range(5000, 10000);
+	} while (time_before(jiffies, timeout));
+
+	dev_warn(&mux->chip->dev, "Timeout waiting for mux to switch\n");
+	return -ETIMEDOUT;
+}
+
+static void intel_cht_usb_set_vbus_valid(struct intel_cht_usb_data *data,
+					     bool valid)
+{
+	u32 val;
+
+	mutex_lock(&data->cfg0_lock);
+
+	val = readl(data->base + DUAL_ROLE_CFG0);
+	if (valid)
+		val |= SW_VBUS_VALID;
+	else
+		val &= ~SW_VBUS_VALID;
+
+	val |= SW_IDPIN_EN;
+	writel(val, data->base + DUAL_ROLE_CFG0);
+
+	mutex_unlock(&data->cfg0_lock);
+}
+
+static void intel_cht_usb_vbus_work(struct work_struct *work)
+{
+	struct intel_cht_usb_data *data =
+		container_of(work, struct intel_cht_usb_data, vbus_work);
+	const unsigned int vbus_cables[] = {
+		EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP,
+		EXTCON_CHG_USB_ACA, EXTCON_CHG_USB_FAST,
+	};
+	bool vbus_present = false;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vbus_cables); i++) {
+		if (extcon_get_state(data->vbus_extcon, vbus_cables[i]) > 0) {
+			vbus_present = true;
+			break;
+		}
+	}
+
+	intel_cht_usb_set_vbus_valid(data, vbus_present);
+}
+
+static int intel_cht_usb_vbus_extcon_evt(struct notifier_block *nb,
+					     unsigned long event, void *param)
+{
+	struct intel_cht_usb_data *data =
+		container_of(nb, struct intel_cht_usb_data, vbus_nb);
+
+	schedule_work(&data->vbus_work);
+
+	return NOTIFY_OK;
+}
+
+static const struct mux_control_ops intel_cht_usb_ops = {
+	.set = intel_cht_usb_set_mux,
+};
+
+static int intel_cht_usb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct intel_cht_usb_data *data;
+	struct mux_chip *mux_chip;
+	struct resource *res;
+	resource_size_t size;
+	int i, ret;
+
+	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*data));
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	mux_chip->ops = &intel_cht_usb_ops;
+	mux_chip->mux[0].idle_state = MUX_USB_DEVICE;
+	/* Keep initial state as is, for e.g. booting from an USB disk */
+	mux_chip->mux[0].init_as_is = true;
+	mux_chip->mux[0].states = MUX_USB_STATES;
+	data = mux_chip_priv(mux_chip);
+	mutex_init(&data->cfg0_lock);
+
+	/*
+	 * Besides controlling the mux we also need to control the vbus_valid
+	 * flag for device/gadget mode to work properly. To do this we monitor
+	 * the extcon interface exported by the PMIC drivers for the PMICs used
+	 * with the Cherry Trail SoC.
+	 *
+	 * We try to get the extcon_dev before registering the mux as this
+	 * may lead to us exiting with -EPROBE_DEFER.
+	 */
+	for (i = 0 ; i < ARRAY_SIZE(vbus_providers); i++) {
+		if (!acpi_dev_present(vbus_providers[i].hid, NULL,
+				      vbus_providers[i].hrv))
+			continue;
+
+		data->vbus_extcon = extcon_get_extcon_dev(
+						vbus_providers[i].extcon);
+		if (data->vbus_extcon == NULL)
+			return -EPROBE_DEFER;
+
+		dev_info(dev, "using extcon '%s' for vbus-valid\n",
+			 vbus_providers[i].extcon);
+		break;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	size = (res->end + 1) - res->start;
+	data->base = devm_ioremap_nocache(dev, res->start, size);
+	if (IS_ERR(data->base)) {
+		ret = PTR_ERR(data->base);
+		dev_err(dev, "can't iomap registers: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	if (data->vbus_extcon) {
+		INIT_WORK(&data->vbus_work, intel_cht_usb_vbus_work);
+		data->vbus_nb.notifier_call = intel_cht_usb_vbus_extcon_evt;
+		ret = devm_extcon_register_notifier_all(dev, data->vbus_extcon,
+							&data->vbus_nb);
+		if (ret) {
+			dev_err(dev, "can't register vbus extcon notifier: %d\n",
+				ret);
+			return ret;
+		}
+
+		/* Sync initial mode */
+		schedule_work(&data->vbus_work);
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id intel_cht_usb_table[] = {
+	{ .name = DRV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, intel_cht_usb_table);
+
+static struct platform_driver intel_cht_usb_driver = {
+	.driver = {
+		.name = DRV_NAME,
+	},
+	.id_table = intel_cht_usb_table,
+	.probe = intel_cht_usb_probe,
+};
+
+module_platform_driver(intel_cht_usb_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel Cherrytrail USB mux driver");
+MODULE_LICENSE("GPL");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 08/14] mux: Add Intel Cherrytrail USB mux driver
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

Intel Cherrytrail SoCs have an internal USB mux for muxing the otg-port
USB data lines between the xHCI host controller and the dwc3 gadget
controller. On some Cherrytrail systems this mux is controlled through
AML code reacting on a GPIO IRQ connected to the USB OTG id pin (through
an _AIE ACPI method) so things just work.

But on other Cherrytrail systems we need to control the mux ourselves
this driver exports the mux through the mux subsys, so that other drivers
can control it if necessary.

This driver also updates the vbus-valid reporting to the dwc3 gadget
controller, as this uses the same registers as the mux. This is needed
for gadget/device mode to work properly (even on systems which control
the mux from their AML code).

Note this depends on the xhci driver registering a platform device
named "intel_cht_usb_mux", which has an IOMEM resource 0 which points
to the Intel Vendor Defined XHCI extended capabilities region.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Complete rewrite as a stand-alone platform-driver rather then as a phy
 driver, since this is just a mux, not a phy

Changes in v3:
-Make this a mux subsys driver instead of listening to USB_HOST extcon
 cable events and responding to those

Changes in v4 (of patch, v2 of new mux based series):
-Rename C-file to use - in name
-Add MAINTAINERS entry
-Various code-style fixes

Changes in v3 of new mux based series:
-Various code-style fixes
-Use new init_as_is mux flag
---
 MAINTAINERS                     |   5 +
 drivers/mux/Kconfig             |  11 ++
 drivers/mux/Makefile            |  10 +-
 drivers/mux/intel-cht-usb-mux.c | 251 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 273 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mux/intel-cht-usb-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 04e7a5b9d6bd..6cfa0e5f2d2b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9176,6 +9176,11 @@ F:	include/linux/dt-bindings/mux/
 F:	include/linux/mux/
 F:	drivers/mux/
 
+MULTIPLEXER SUBSYSTEM INTEL CHT USB MUX DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+S:	Maintained
+F:	drivers/mux/intel-cht-usb-mux.c
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 19e4e904c9bf..ebc04ae7ff30 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -34,6 +34,17 @@ config MUX_GPIO
 	  To compile the driver as a module, choose M here: the module will
 	  be called mux-gpio.
 
+config MUX_INTEL_CHT_USB_MUX
+	tristate "Intel Cherrytrail USB Multiplexer"
+	depends on ACPI && X86 && EXTCON
+	help
+	  This driver adds support for the internal USB mux for muxing the OTG
+	  USB data lines between the xHCI host controller and the dwc3 gadget
+	  controller found on Intel Cherrytrail SoCs.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-intel-cht-usb-mux.
+
 config MUX_MMIO
 	tristate "MMIO register bitfield-controlled Multiplexer"
 	depends on (OF && MFD_SYSCON) || COMPILE_TEST
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 0e1e59760e3f..6cf41be2754f 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -5,9 +5,11 @@
 mux-core-objs			:= core.o
 mux-adg792a-objs		:= adg792a.o
 mux-gpio-objs			:= gpio.o
+mux-intel-cht-usb-mux-objs	:= intel-cht-usb-mux.o
 mux-mmio-objs			:= mmio.o
 
-obj-$(CONFIG_MULTIPLEXER)	+= mux-core.o
-obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
-obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
-obj-$(CONFIG_MUX_MMIO)		+= mux-mmio.o
+obj-$(CONFIG_MULTIPLEXER)		+= mux-core.o
+obj-$(CONFIG_MUX_ADG792A)		+= mux-adg792a.o
+obj-$(CONFIG_MUX_GPIO)			+= mux-gpio.o
+obj-$(CONFIG_MUX_INTEL_CHT_USB_MUX)	+= mux-intel-cht-usb-mux.o
+obj-$(CONFIG_MUX_MMIO)			+= mux-mmio.o
diff --git a/drivers/mux/intel-cht-usb-mux.c b/drivers/mux/intel-cht-usb-mux.c
new file mode 100644
index 000000000000..726facefd479
--- /dev/null
+++ b/drivers/mux/intel-cht-usb-mux.c
@@ -0,0 +1,251 @@
+/*
+ * Intel Cherrytrail USB OTG MUX driver
+ *
+ * Copyright (c) 2016-2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Loosely based on android x86 kernel code which is:
+ *
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Author: Wu, Hao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/mux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+/* register definition */
+#define DUAL_ROLE_CFG0			0x68
+#define SW_VBUS_VALID			(1 << 24)
+#define SW_IDPIN_EN			(1 << 21)
+#define SW_IDPIN			(1 << 20)
+
+#define DUAL_ROLE_CFG1			0x6c
+#define HOST_MODE			(1 << 29)
+
+#define DUAL_ROLE_CFG1_POLL_TIMEOUT	1000
+
+#define DRV_NAME			"intel_cht_usb_mux"
+
+struct intel_cht_usb_data {
+	struct mutex cfg0_lock;
+	void __iomem *base;
+	struct extcon_dev *vbus_extcon;
+	struct notifier_block vbus_nb;
+	struct work_struct vbus_work;
+};
+
+struct intel_cht_extcon_info {
+	const char *hid;
+	int hrv;
+	const char *extcon;
+};
+
+static const struct intel_cht_extcon_info vbus_providers[] = {
+	{ .hid = "INT33F4", .hrv = -1, .extcon = "axp288_extcon" },
+	{ .hid = "INT34D3", .hrv =  3, .extcon = "cht_wcove_pwrsrc" },
+};
+
+static int intel_cht_usb_set_mux(struct mux_control *mux, int state)
+{
+	struct intel_cht_usb_data *data = mux_chip_priv(mux->chip);
+	unsigned long timeout;
+	bool host_mode;
+	u32 val;
+
+	mutex_lock(&data->cfg0_lock);
+
+	/* Set idpin value as requested */
+	val = readl(data->base + DUAL_ROLE_CFG0);
+	if (state == MUX_USB_DEVICE) {
+		val |= SW_IDPIN;
+		host_mode = false;
+	} else {
+		val &= ~SW_IDPIN;
+		host_mode = true;
+	}
+	val |= SW_IDPIN_EN;
+	writel(val, data->base + DUAL_ROLE_CFG0);
+
+	mutex_unlock(&data->cfg0_lock);
+
+	/* In most case it takes about 600ms to finish mode switching */
+	timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch.*/
+	do {
+		val = readl(data->base + DUAL_ROLE_CFG1);
+		if (!!(val & HOST_MODE) == host_mode)
+			return 0;
+
+		/* Interval for polling is set to about 5 - 10 ms */
+		usleep_range(5000, 10000);
+	} while (time_before(jiffies, timeout));
+
+	dev_warn(&mux->chip->dev, "Timeout waiting for mux to switch\n");
+	return -ETIMEDOUT;
+}
+
+static void intel_cht_usb_set_vbus_valid(struct intel_cht_usb_data *data,
+					     bool valid)
+{
+	u32 val;
+
+	mutex_lock(&data->cfg0_lock);
+
+	val = readl(data->base + DUAL_ROLE_CFG0);
+	if (valid)
+		val |= SW_VBUS_VALID;
+	else
+		val &= ~SW_VBUS_VALID;
+
+	val |= SW_IDPIN_EN;
+	writel(val, data->base + DUAL_ROLE_CFG0);
+
+	mutex_unlock(&data->cfg0_lock);
+}
+
+static void intel_cht_usb_vbus_work(struct work_struct *work)
+{
+	struct intel_cht_usb_data *data =
+		container_of(work, struct intel_cht_usb_data, vbus_work);
+	const unsigned int vbus_cables[] = {
+		EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP,
+		EXTCON_CHG_USB_ACA, EXTCON_CHG_USB_FAST,
+	};
+	bool vbus_present = false;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vbus_cables); i++) {
+		if (extcon_get_state(data->vbus_extcon, vbus_cables[i]) > 0) {
+			vbus_present = true;
+			break;
+		}
+	}
+
+	intel_cht_usb_set_vbus_valid(data, vbus_present);
+}
+
+static int intel_cht_usb_vbus_extcon_evt(struct notifier_block *nb,
+					     unsigned long event, void *param)
+{
+	struct intel_cht_usb_data *data =
+		container_of(nb, struct intel_cht_usb_data, vbus_nb);
+
+	schedule_work(&data->vbus_work);
+
+	return NOTIFY_OK;
+}
+
+static const struct mux_control_ops intel_cht_usb_ops = {
+	.set = intel_cht_usb_set_mux,
+};
+
+static int intel_cht_usb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct intel_cht_usb_data *data;
+	struct mux_chip *mux_chip;
+	struct resource *res;
+	resource_size_t size;
+	int i, ret;
+
+	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*data));
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	mux_chip->ops = &intel_cht_usb_ops;
+	mux_chip->mux[0].idle_state = MUX_USB_DEVICE;
+	/* Keep initial state as is, for e.g. booting from an USB disk */
+	mux_chip->mux[0].init_as_is = true;
+	mux_chip->mux[0].states = MUX_USB_STATES;
+	data = mux_chip_priv(mux_chip);
+	mutex_init(&data->cfg0_lock);
+
+	/*
+	 * Besides controlling the mux we also need to control the vbus_valid
+	 * flag for device/gadget mode to work properly. To do this we monitor
+	 * the extcon interface exported by the PMIC drivers for the PMICs used
+	 * with the Cherry Trail SoC.
+	 *
+	 * We try to get the extcon_dev before registering the mux as this
+	 * may lead to us exiting with -EPROBE_DEFER.
+	 */
+	for (i = 0 ; i < ARRAY_SIZE(vbus_providers); i++) {
+		if (!acpi_dev_present(vbus_providers[i].hid, NULL,
+				      vbus_providers[i].hrv))
+			continue;
+
+		data->vbus_extcon = extcon_get_extcon_dev(
+						vbus_providers[i].extcon);
+		if (data->vbus_extcon == NULL)
+			return -EPROBE_DEFER;
+
+		dev_info(dev, "using extcon '%s' for vbus-valid\n",
+			 vbus_providers[i].extcon);
+		break;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	size = (res->end + 1) - res->start;
+	data->base = devm_ioremap_nocache(dev, res->start, size);
+	if (IS_ERR(data->base)) {
+		ret = PTR_ERR(data->base);
+		dev_err(dev, "can't iomap registers: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	if (data->vbus_extcon) {
+		INIT_WORK(&data->vbus_work, intel_cht_usb_vbus_work);
+		data->vbus_nb.notifier_call = intel_cht_usb_vbus_extcon_evt;
+		ret = devm_extcon_register_notifier_all(dev, data->vbus_extcon,
+							&data->vbus_nb);
+		if (ret) {
+			dev_err(dev, "can't register vbus extcon notifier: %d\n",
+				ret);
+			return ret;
+		}
+
+		/* Sync initial mode */
+		schedule_work(&data->vbus_work);
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id intel_cht_usb_table[] = {
+	{ .name = DRV_NAME },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, intel_cht_usb_table);
+
+static struct platform_driver intel_cht_usb_driver = {
+	.driver = {
+		.name = DRV_NAME,
+	},
+	.id_table = intel_cht_usb_table,
+	.probe = intel_cht_usb_probe,
+};
+
+module_platform_driver(intel_cht_usb_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel Cherrytrail USB mux driver");
+MODULE_LICENSE("GPL");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 09/14] mux: Add Pericom PI3USB30532 Type-C mux driver
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Add a driver for the Pericom PI3USB30532 Type-C cross switch /
mux chip found on some devices with a Type-C port.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Adjust for new MUX_TYPEC_foo state defines
-Add MAINTAINERS entry
-Various code-style fixes

Changes in v3:
-Use new init_as_is mux flag
-Adjust for updated MUX_TYPEC_* defines
---
 MAINTAINERS               |  5 +++
 drivers/mux/Kconfig       | 10 ++++++
 drivers/mux/Makefile      |  2 ++
 drivers/mux/pi3usb30532.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 109 insertions(+)
 create mode 100644 drivers/mux/pi3usb30532.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6cfa0e5f2d2b..5c844fd3a23c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9181,6 +9181,11 @@ M:	Hans de Goede <hdegoede@redhat.com>
 S:	Maintained
 F:	drivers/mux/intel-cht-usb-mux.c
 
+MULTIPLEXER SUBSYSTEM PI3USB30532 DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+S:	Maintained
+F:	drivers/mux/pi3usb30532.c
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index ebc04ae7ff30..f94660229d20 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -58,4 +58,14 @@ config MUX_MMIO
 	  To compile the driver as a module, choose M here: the module will
 	  be called mux-mmio.
 
+config MUX_PI3USB30532
+	tristate "Pericom PI3USB30532 Type-C cross switch driver"
+	depends on I2C
+	help
+	  This driver adds support for the Pericom PI3USB30532 Type-C cross
+	  switch / mux chip found on some devices with a Type-C port.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-pi3usb30532.
+
 endmenu
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 6cf41be2754f..df381c219708 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -7,9 +7,11 @@ mux-adg792a-objs		:= adg792a.o
 mux-gpio-objs			:= gpio.o
 mux-intel-cht-usb-mux-objs	:= intel-cht-usb-mux.o
 mux-mmio-objs			:= mmio.o
+mux-pi3usb30532-objs		:= pi3usb30532.o
 
 obj-$(CONFIG_MULTIPLEXER)		+= mux-core.o
 obj-$(CONFIG_MUX_ADG792A)		+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)			+= mux-gpio.o
 obj-$(CONFIG_MUX_INTEL_CHT_USB_MUX)	+= mux-intel-cht-usb-mux.o
 obj-$(CONFIG_MUX_MMIO)			+= mux-mmio.o
+obj-$(CONFIG_MUX_PI3USB30532)		+= mux-pi3usb30532.o
diff --git a/drivers/mux/pi3usb30532.c b/drivers/mux/pi3usb30532.c
new file mode 100644
index 000000000000..13c7c4ec0047
--- /dev/null
+++ b/drivers/mux/pi3usb30532.c
@@ -0,0 +1,92 @@
+/*
+ * Pericom PI3USB30532 Type-C cross switch / mux driver
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/mux/usb.h>
+
+#define PI3USB30532_CONF			0x00
+
+#define PI3USB30532_CONF_OPEN			0x00
+#define PI3USB30532_CONF_SWAP			0x01
+#define PI3USB30532_CONF_4LANE_DP		0x02
+#define PI3USB30532_CONF_USB3			0x04
+#define PI3USB30532_CONF_USB3_AND_2LANE_DP	0x06
+
+static int pi3usb30532_set_mux(struct mux_control *mux, int state)
+{
+	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+	u8 conf = PI3USB30532_CONF_OPEN;
+
+	if (state == MUX_IDLE_DISCONNECT)
+		return i2c_smbus_write_byte_data(i2c, PI3USB30532_CONF, conf);
+
+	switch (state & ~MUX_TYPEC_POLARITY_INV) {
+	case MUX_TYPEC_USB:
+		conf = PI3USB30532_CONF_USB3;
+		break;
+	case MUX_TYPEC_USB_AND_DP:
+		conf = PI3USB30532_CONF_USB3_AND_2LANE_DP;
+		break;
+	case MUX_TYPEC_DP:
+		conf = PI3USB30532_CONF_4LANE_DP;
+		break;
+	}
+
+	if (state & MUX_TYPEC_POLARITY_INV)
+		conf |= PI3USB30532_CONF_SWAP;
+
+	return i2c_smbus_write_byte_data(i2c, PI3USB30532_CONF, conf);
+}
+
+static const struct mux_control_ops pi3usb30532_ops = {
+	.set = pi3usb30532_set_mux,
+};
+
+static int pi3usb30532_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct mux_chip *mux_chip;
+
+	mux_chip = devm_mux_chip_alloc(dev, 1, 0);
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	mux_chip->ops = &pi3usb30532_ops;
+	mux_chip->mux[0].idle_state = MUX_IDLE_DISCONNECT;
+	/* Keep initial state as is, for e.g. booting from an USB disk */
+	mux_chip->mux[0].init_as_is = true;
+	mux_chip->mux[0].states = MUX_TYPEC_STATES;
+
+	return devm_mux_chip_register(dev, mux_chip);
+}
+
+static const struct i2c_device_id pi3usb30532_table[] = {
+	{ "pi3usb30532" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pi3usb30532_table);
+
+static struct i2c_driver pi3usb30532_driver = {
+	.driver = {
+		.name = "pi3usb30532",
+	},
+	.probe_new = pi3usb30532_probe,
+	.id_table = pi3usb30532_table,
+};
+
+module_i2c_driver(pi3usb30532_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Pericom PI3USB30532 Type-C mux driver");
+MODULE_LICENSE("GPL");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 09/14] mux: Add Pericom PI3USB30532 Type-C mux driver
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

Add a driver for the Pericom PI3USB30532 Type-C cross switch /
mux chip found on some devices with a Type-C port.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Adjust for new MUX_TYPEC_foo state defines
-Add MAINTAINERS entry
-Various code-style fixes

Changes in v3:
-Use new init_as_is mux flag
-Adjust for updated MUX_TYPEC_* defines
---
 MAINTAINERS               |  5 +++
 drivers/mux/Kconfig       | 10 ++++++
 drivers/mux/Makefile      |  2 ++
 drivers/mux/pi3usb30532.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 109 insertions(+)
 create mode 100644 drivers/mux/pi3usb30532.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6cfa0e5f2d2b..5c844fd3a23c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9181,6 +9181,11 @@ M:	Hans de Goede <hdegoede@redhat.com>
 S:	Maintained
 F:	drivers/mux/intel-cht-usb-mux.c
 
+MULTIPLEXER SUBSYSTEM PI3USB30532 DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+S:	Maintained
+F:	drivers/mux/pi3usb30532.c
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index ebc04ae7ff30..f94660229d20 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -58,4 +58,14 @@ config MUX_MMIO
 	  To compile the driver as a module, choose M here: the module will
 	  be called mux-mmio.
 
+config MUX_PI3USB30532
+	tristate "Pericom PI3USB30532 Type-C cross switch driver"
+	depends on I2C
+	help
+	  This driver adds support for the Pericom PI3USB30532 Type-C cross
+	  switch / mux chip found on some devices with a Type-C port.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-pi3usb30532.
+
 endmenu
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 6cf41be2754f..df381c219708 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -7,9 +7,11 @@ mux-adg792a-objs		:= adg792a.o
 mux-gpio-objs			:= gpio.o
 mux-intel-cht-usb-mux-objs	:= intel-cht-usb-mux.o
 mux-mmio-objs			:= mmio.o
+mux-pi3usb30532-objs		:= pi3usb30532.o
 
 obj-$(CONFIG_MULTIPLEXER)		+= mux-core.o
 obj-$(CONFIG_MUX_ADG792A)		+= mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO)			+= mux-gpio.o
 obj-$(CONFIG_MUX_INTEL_CHT_USB_MUX)	+= mux-intel-cht-usb-mux.o
 obj-$(CONFIG_MUX_MMIO)			+= mux-mmio.o
+obj-$(CONFIG_MUX_PI3USB30532)		+= mux-pi3usb30532.o
diff --git a/drivers/mux/pi3usb30532.c b/drivers/mux/pi3usb30532.c
new file mode 100644
index 000000000000..13c7c4ec0047
--- /dev/null
+++ b/drivers/mux/pi3usb30532.c
@@ -0,0 +1,92 @@
+/*
+ * Pericom PI3USB30532 Type-C cross switch / mux driver
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/mux/usb.h>
+
+#define PI3USB30532_CONF			0x00
+
+#define PI3USB30532_CONF_OPEN			0x00
+#define PI3USB30532_CONF_SWAP			0x01
+#define PI3USB30532_CONF_4LANE_DP		0x02
+#define PI3USB30532_CONF_USB3			0x04
+#define PI3USB30532_CONF_USB3_AND_2LANE_DP	0x06
+
+static int pi3usb30532_set_mux(struct mux_control *mux, int state)
+{
+	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+	u8 conf = PI3USB30532_CONF_OPEN;
+
+	if (state == MUX_IDLE_DISCONNECT)
+		return i2c_smbus_write_byte_data(i2c, PI3USB30532_CONF, conf);
+
+	switch (state & ~MUX_TYPEC_POLARITY_INV) {
+	case MUX_TYPEC_USB:
+		conf = PI3USB30532_CONF_USB3;
+		break;
+	case MUX_TYPEC_USB_AND_DP:
+		conf = PI3USB30532_CONF_USB3_AND_2LANE_DP;
+		break;
+	case MUX_TYPEC_DP:
+		conf = PI3USB30532_CONF_4LANE_DP;
+		break;
+	}
+
+	if (state & MUX_TYPEC_POLARITY_INV)
+		conf |= PI3USB30532_CONF_SWAP;
+
+	return i2c_smbus_write_byte_data(i2c, PI3USB30532_CONF, conf);
+}
+
+static const struct mux_control_ops pi3usb30532_ops = {
+	.set = pi3usb30532_set_mux,
+};
+
+static int pi3usb30532_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct mux_chip *mux_chip;
+
+	mux_chip = devm_mux_chip_alloc(dev, 1, 0);
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	mux_chip->ops = &pi3usb30532_ops;
+	mux_chip->mux[0].idle_state = MUX_IDLE_DISCONNECT;
+	/* Keep initial state as is, for e.g. booting from an USB disk */
+	mux_chip->mux[0].init_as_is = true;
+	mux_chip->mux[0].states = MUX_TYPEC_STATES;
+
+	return devm_mux_chip_register(dev, mux_chip);
+}
+
+static const struct i2c_device_id pi3usb30532_table[] = {
+	{ "pi3usb30532" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pi3usb30532_table);
+
+static struct i2c_driver pi3usb30532_driver = {
+	.driver = {
+		.name = "pi3usb30532",
+	},
+	.probe_new = pi3usb30532_probe,
+	.id_table = pi3usb30532_table,
+};
+
+module_i2c_driver(pi3usb30532_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Pericom PI3USB30532 Type-C mux driver");
+MODULE_LICENSE("GPL");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:37   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Cherry Trail SoCs have a built-in USB-role mux for switching between
the host and device controllers, rather then using an external mux
controller by a GPIO.

There is a driver using the mux-subsys to control this mux, this
commit adds support to the intel-int3496 driver to get a mux_controller
handle for the mux and set the mux through the mux-subsys rather then
through a GPIO.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
 compile on !X86
-Minor code style tweaks
---
 drivers/extcon/Kconfig                |  3 +-
 drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index a7bca4207f44..168f9d710ea0 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -44,7 +44,8 @@ config EXTCON_GPIO
 
 config EXTCON_INTEL_INT3496
 	tristate "Intel INT3496 ACPI device extcon driver"
-	depends on GPIOLIB && ACPI && (X86 || COMPILE_TEST)
+	depends on GPIOLIB && ACPI && X86
+	select MULTIPLEXER
 	help
 	  Say Y here to enable extcon support for USB OTG ports controlled by
 	  an Intel INT3496 ACPI device.
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
index 1a45e745717d..3c8e17449c12 100644
--- a/drivers/extcon/extcon-intel-int3496.c
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -23,8 +23,13 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/mux/usb.h>
 #include <linux/platform_device.h>
 
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
 #define INT3496_GPIO_USB_ID	0
 #define INT3496_GPIO_VBUS_EN	1
 #define INT3496_GPIO_USB_MUX	2
@@ -37,6 +42,8 @@ struct int3496_data {
 	struct gpio_desc *gpio_usb_id;
 	struct gpio_desc *gpio_vbus_en;
 	struct gpio_desc *gpio_usb_mux;
+	struct mux_control *usb_mux;
+	bool usb_mux_set;
 	int usb_id_irq;
 };
 
@@ -56,11 +63,32 @@ static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
 	{ },
 };
 
+static struct mux_lookup acpi_int3496_cht_mux_lookup[] = {
+	{
+		.provider = "intel_cht_usb_mux",
+		.dev_id   = "INT3496:00",
+		.mux_name = "usb-role-mux",
+	},
+};
+
+#define ICPU(model)	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+
+static const struct x86_cpu_id cht_cpu_ids[] = {
+	ICPU(INTEL_FAM6_ATOM_AIRMONT),		/* Braswell, Cherry Trail */
+	{}
+};
+
+static bool int3496_soc_has_mux(void)
+{
+	return x86_match_cpu(cht_cpu_ids);
+}
+
 static void int3496_do_usb_id(struct work_struct *work)
 {
 	struct int3496_data *data =
 		container_of(work, struct int3496_data, work.work);
 	int id = gpiod_get_value_cansleep(data->gpio_usb_id);
+	int ret;
 
 	/* id == 1: PERIPHERAL, id == 0: HOST */
 	dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST");
@@ -72,6 +100,22 @@ static void int3496_do_usb_id(struct work_struct *work)
 	if (!IS_ERR(data->gpio_usb_mux))
 		gpiod_direction_output(data->gpio_usb_mux, id);
 
+	if (data->usb_mux) {
+		/*
+		 * The mux framework expects multiple competing users, we must
+		 * release our previous setting before applying the new one.
+		 */
+		if (data->usb_mux_set)
+			mux_control_deselect(data->usb_mux);
+
+		ret = mux_control_select(data->usb_mux,
+					 id ? MUX_USB_DEVICE : MUX_USB_HOST);
+		if (ret)
+			dev_err(data->dev, "Error setting mux: %d\n", ret);
+
+		data->usb_mux_set = ret == 0;
+	}
+
 	if (!IS_ERR(data->gpio_vbus_en))
 		gpiod_direction_output(data->gpio_vbus_en, !id);
 
@@ -107,6 +151,21 @@ static int int3496_probe(struct platform_device *pdev)
 	data->dev = dev;
 	INIT_DELAYED_WORK(&data->work, int3496_do_usb_id);
 
+	if (int3496_soc_has_mux()) {
+		mux_add_table(acpi_int3496_cht_mux_lookup,
+			      ARRAY_SIZE(acpi_int3496_cht_mux_lookup));
+		data->usb_mux = devm_mux_control_get(dev, "usb-role-mux");
+		/* Doing this here keeps our error handling clean. */
+		mux_remove_table(acpi_int3496_cht_mux_lookup,
+				 ARRAY_SIZE(acpi_int3496_cht_mux_lookup));
+		if (IS_ERR(data->usb_mux)) {
+			ret = PTR_ERR(data->usb_mux);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "can't get mux: %d\n", ret);
+			return ret;
+		}
+	}
+
 	data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN);
 	if (IS_ERR(data->gpio_usb_id)) {
 		ret = PTR_ERR(data->gpio_usb_id);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
@ 2017-09-22 18:37   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:37 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Hans de Goede

Cherry Trail SoCs have a built-in USB-role mux for switching between
the host and device controllers, rather then using an external mux
controller by a GPIO.

There is a driver using the mux-subsys to control this mux, this
commit adds support to the intel-int3496 driver to get a mux_controller
handle for the mux and set the mux through the mux-subsys rather then
through a GPIO.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
 compile on !X86
-Minor code style tweaks
---
 drivers/extcon/Kconfig                |  3 +-
 drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index a7bca4207f44..168f9d710ea0 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -44,7 +44,8 @@ config EXTCON_GPIO
 
 config EXTCON_INTEL_INT3496
 	tristate "Intel INT3496 ACPI device extcon driver"
-	depends on GPIOLIB && ACPI && (X86 || COMPILE_TEST)
+	depends on GPIOLIB && ACPI && X86
+	select MULTIPLEXER
 	help
 	  Say Y here to enable extcon support for USB OTG ports controlled by
 	  an Intel INT3496 ACPI device.
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
index 1a45e745717d..3c8e17449c12 100644
--- a/drivers/extcon/extcon-intel-int3496.c
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -23,8 +23,13 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/mux/usb.h>
 #include <linux/platform_device.h>
 
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
 #define INT3496_GPIO_USB_ID	0
 #define INT3496_GPIO_VBUS_EN	1
 #define INT3496_GPIO_USB_MUX	2
@@ -37,6 +42,8 @@ struct int3496_data {
 	struct gpio_desc *gpio_usb_id;
 	struct gpio_desc *gpio_vbus_en;
 	struct gpio_desc *gpio_usb_mux;
+	struct mux_control *usb_mux;
+	bool usb_mux_set;
 	int usb_id_irq;
 };
 
@@ -56,11 +63,32 @@ static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
 	{ },
 };
 
+static struct mux_lookup acpi_int3496_cht_mux_lookup[] = {
+	{
+		.provider = "intel_cht_usb_mux",
+		.dev_id   = "INT3496:00",
+		.mux_name = "usb-role-mux",
+	},
+};
+
+#define ICPU(model)	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+
+static const struct x86_cpu_id cht_cpu_ids[] = {
+	ICPU(INTEL_FAM6_ATOM_AIRMONT),		/* Braswell, Cherry Trail */
+	{}
+};
+
+static bool int3496_soc_has_mux(void)
+{
+	return x86_match_cpu(cht_cpu_ids);
+}
+
 static void int3496_do_usb_id(struct work_struct *work)
 {
 	struct int3496_data *data =
 		container_of(work, struct int3496_data, work.work);
 	int id = gpiod_get_value_cansleep(data->gpio_usb_id);
+	int ret;
 
 	/* id == 1: PERIPHERAL, id == 0: HOST */
 	dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST");
@@ -72,6 +100,22 @@ static void int3496_do_usb_id(struct work_struct *work)
 	if (!IS_ERR(data->gpio_usb_mux))
 		gpiod_direction_output(data->gpio_usb_mux, id);
 
+	if (data->usb_mux) {
+		/*
+		 * The mux framework expects multiple competing users, we must
+		 * release our previous setting before applying the new one.
+		 */
+		if (data->usb_mux_set)
+			mux_control_deselect(data->usb_mux);
+
+		ret = mux_control_select(data->usb_mux,
+					 id ? MUX_USB_DEVICE : MUX_USB_HOST);
+		if (ret)
+			dev_err(data->dev, "Error setting mux: %d\n", ret);
+
+		data->usb_mux_set = ret == 0;
+	}
+
 	if (!IS_ERR(data->gpio_vbus_en))
 		gpiod_direction_output(data->gpio_vbus_en, !id);
 
@@ -107,6 +151,21 @@ static int int3496_probe(struct platform_device *pdev)
 	data->dev = dev;
 	INIT_DELAYED_WORK(&data->work, int3496_do_usb_id);
 
+	if (int3496_soc_has_mux()) {
+		mux_add_table(acpi_int3496_cht_mux_lookup,
+			      ARRAY_SIZE(acpi_int3496_cht_mux_lookup));
+		data->usb_mux = devm_mux_control_get(dev, "usb-role-mux");
+		/* Doing this here keeps our error handling clean. */
+		mux_remove_table(acpi_int3496_cht_mux_lookup,
+				 ARRAY_SIZE(acpi_int3496_cht_mux_lookup));
+		if (IS_ERR(data->usb_mux)) {
+			ret = PTR_ERR(data->usb_mux);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "can't get mux: %d\n", ret);
+			return ret;
+		}
+	}
+
 	data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN);
 	if (IS_ERR(data->gpio_usb_id)) {
 		ret = PTR_ERR(data->gpio_usb_id);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 11/14] staging: typec: tcpm: Set mux to device mode when configured as such
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:38   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Setting the mux to TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT when the
data-role is device is not correct. Plenty of devices support operating
as USB device through a (separate) USB device controller.

So this commit instead splits out TYPEC_MUX_USB into TYPEC_MUX_USB_HOST
and TYPEC_MUX_USB_DEVICE and makes tcpm_set_roles() set the mux
accordingly.

Likewise TCPC_MUX_DP gets renamed to TCPC_MUX_DP_SRC to make clear that
this is for configuring the Type-C port as a Display Port source, not a
sink.

Last this commit makes tcpm_reset_port() call tcpm_mux_set(port,
TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT) so that the mux does _not_
stay in its last mode after a detach.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
---
Changes in v3:
-Improve / reword last paragraph of the commit message
-Add Guenter's Reviewed-by
---
 drivers/usb/typec/tcpm.c |  7 ++++---
 include/linux/usb/tcpm.h | 22 ++++++++++++++--------
 2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
index f557c479fdc2..e104c218cb4a 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm.c
@@ -751,11 +751,11 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
 	int ret;
 
 	if (data == TYPEC_HOST)
-		ret = tcpm_mux_set(port, TYPEC_MUX_USB,
+		ret = tcpm_mux_set(port, TYPEC_MUX_USB_HOST,
 				   TCPC_USB_SWITCH_CONNECT);
 	else
-		ret = tcpm_mux_set(port, TYPEC_MUX_NONE,
-				   TCPC_USB_SWITCH_DISCONNECT);
+		ret = tcpm_mux_set(port, TYPEC_MUX_USB_DEVICE,
+				   TCPC_USB_SWITCH_CONNECT);
 	if (ret < 0)
 		return ret;
 
@@ -1995,6 +1995,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
 	tcpm_init_vconn(port);
 	tcpm_set_current_limit(port, 0, 0);
 	tcpm_set_polarity(port, TYPEC_POLARITY_CC1);
+	tcpm_mux_set(port, TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT);
 	tcpm_set_attached_state(port, false);
 	port->try_src_count = 0;
 	port->try_snk_count = 0;
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index 073197f0d2bb..bc76389ee257 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -103,17 +103,23 @@ enum tcpc_usb_switch {
 };
 
 /* Mux state attributes */
-#define TCPC_MUX_USB_ENABLED		BIT(0)	/* USB enabled */
-#define TCPC_MUX_DP_ENABLED		BIT(1)	/* DP enabled */
-#define TCPC_MUX_POLARITY_INVERTED	BIT(2)	/* Polarity inverted */
+#define TCPC_MUX_USB_DEVICE_ENABLED		BIT(0)	/* USB device enabled */
+#define TCPC_MUX_USB_HOST_ENABLED		BIT(1)	/* USB host enabled */
+#define TCPC_MUX_DP_SRC_ENABLED			BIT(2)	/* DP enabled */
+#define TCPC_MUX_POLARITY_INVERTED		BIT(3)	/* Polarity inverted */
 
 /* Mux modes, decoded to attributes */
 enum tcpc_mux_mode {
-	TYPEC_MUX_NONE	= 0,				/* Open switch */
-	TYPEC_MUX_USB	= TCPC_MUX_USB_ENABLED,		/* USB only */
-	TYPEC_MUX_DP	= TCPC_MUX_DP_ENABLED,		/* DP only */
-	TYPEC_MUX_DOCK	= TCPC_MUX_USB_ENABLED |	/* Both USB and DP */
-			  TCPC_MUX_DP_ENABLED,
+	/* Open switch */
+	TYPEC_MUX_NONE = 0,
+	/* USB device only */
+	TYPEC_MUX_USB_DEVICE = TCPC_MUX_USB_DEVICE_ENABLED,
+	/* USB host only */
+	TYPEC_MUX_USB_HOST = TCPC_MUX_USB_HOST_ENABLED,
+	/* DP source only */
+	TYPEC_MUX_DP = TCPC_MUX_DP_SRC_ENABLED,
+	/* Both USB host and DP source */
+	TYPEC_MUX_DOCK = TCPC_MUX_USB_HOST_ENABLED | TCPC_MUX_DP_SRC_ENABLED,
 };
 
 struct tcpc_mux_dev {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 11/14] staging: typec: tcpm: Set mux to device mode when configured as such
@ 2017-09-22 18:38   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Setting the mux to TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT when the
data-role is device is not correct. Plenty of devices support operating
as USB device through a (separate) USB device controller.

So this commit instead splits out TYPEC_MUX_USB into TYPEC_MUX_USB_HOST
and TYPEC_MUX_USB_DEVICE and makes tcpm_set_roles() set the mux
accordingly.

Likewise TCPC_MUX_DP gets renamed to TCPC_MUX_DP_SRC to make clear that
this is for configuring the Type-C port as a Display Port source, not a
sink.

Last this commit makes tcpm_reset_port() call tcpm_mux_set(port,
TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT) so that the mux does _not_
stay in its last mode after a detach.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
---
Changes in v3:
-Improve / reword last paragraph of the commit message
-Add Guenter's Reviewed-by
---
 drivers/usb/typec/tcpm.c |  7 ++++---
 include/linux/usb/tcpm.h | 22 ++++++++++++++--------
 2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
index f557c479fdc2..e104c218cb4a 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm.c
@@ -751,11 +751,11 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
 	int ret;
 
 	if (data == TYPEC_HOST)
-		ret = tcpm_mux_set(port, TYPEC_MUX_USB,
+		ret = tcpm_mux_set(port, TYPEC_MUX_USB_HOST,
 				   TCPC_USB_SWITCH_CONNECT);
 	else
-		ret = tcpm_mux_set(port, TYPEC_MUX_NONE,
-				   TCPC_USB_SWITCH_DISCONNECT);
+		ret = tcpm_mux_set(port, TYPEC_MUX_USB_DEVICE,
+				   TCPC_USB_SWITCH_CONNECT);
 	if (ret < 0)
 		return ret;
 
@@ -1995,6 +1995,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
 	tcpm_init_vconn(port);
 	tcpm_set_current_limit(port, 0, 0);
 	tcpm_set_polarity(port, TYPEC_POLARITY_CC1);
+	tcpm_mux_set(port, TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT);
 	tcpm_set_attached_state(port, false);
 	port->try_src_count = 0;
 	port->try_snk_count = 0;
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index 073197f0d2bb..bc76389ee257 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -103,17 +103,23 @@ enum tcpc_usb_switch {
 };
 
 /* Mux state attributes */
-#define TCPC_MUX_USB_ENABLED		BIT(0)	/* USB enabled */
-#define TCPC_MUX_DP_ENABLED		BIT(1)	/* DP enabled */
-#define TCPC_MUX_POLARITY_INVERTED	BIT(2)	/* Polarity inverted */
+#define TCPC_MUX_USB_DEVICE_ENABLED		BIT(0)	/* USB device enabled */
+#define TCPC_MUX_USB_HOST_ENABLED		BIT(1)	/* USB host enabled */
+#define TCPC_MUX_DP_SRC_ENABLED			BIT(2)	/* DP enabled */
+#define TCPC_MUX_POLARITY_INVERTED		BIT(3)	/* Polarity inverted */
 
 /* Mux modes, decoded to attributes */
 enum tcpc_mux_mode {
-	TYPEC_MUX_NONE	= 0,				/* Open switch */
-	TYPEC_MUX_USB	= TCPC_MUX_USB_ENABLED,		/* USB only */
-	TYPEC_MUX_DP	= TCPC_MUX_DP_ENABLED,		/* DP only */
-	TYPEC_MUX_DOCK	= TCPC_MUX_USB_ENABLED |	/* Both USB and DP */
-			  TCPC_MUX_DP_ENABLED,
+	/* Open switch */
+	TYPEC_MUX_NONE = 0,
+	/* USB device only */
+	TYPEC_MUX_USB_DEVICE = TCPC_MUX_USB_DEVICE_ENABLED,
+	/* USB host only */
+	TYPEC_MUX_USB_HOST = TCPC_MUX_USB_HOST_ENABLED,
+	/* DP source only */
+	TYPEC_MUX_DP = TCPC_MUX_DP_SRC_ENABLED,
+	/* Both USB host and DP source */
+	TYPEC_MUX_DOCK = TCPC_MUX_USB_HOST_ENABLED | TCPC_MUX_DP_SRC_ENABLED,
 };
 
 struct tcpc_mux_dev {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 12/14] staging: typec: Add Generic TCPC mux driver using the mux subsys
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:38   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

So far the mux functionality of the tcpm code has not been hooked up
in any tcpc drivers. This commit adds a generic TCPC mux driver using
the mux subsys, which tcpc drivers can use to provide mux functionality
in cases where an external my is used.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v3:
-Use new devm_mux_control_get_optional()
-Simplify tcpc_gen_mux_set as we now no longer need to worry about the muxes
 being present
-Adjust for updated MUX_TYPEC_* defines
---
 drivers/usb/typec/Makefile       |   2 +-
 drivers/usb/typec/tcpc_gen_mux.c | 122 +++++++++++++++++++++++++++++++++++++++
 include/linux/usb/tcpm.h         |   2 +
 3 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/typec/tcpc_gen_mux.c

diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index b77688ce1f16..95a7d9c4527b 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_TYPEC)		+= typec.o
-obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o
+obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o tcpc_gen_mux.o
 obj-y				+= fusb302/
 obj-$(CONFIG_TYPEC_WCOVE)	+= typec_wcove.o
 obj-$(CONFIG_TYPEC_UCSI)	+= ucsi/
diff --git a/drivers/usb/typec/tcpc_gen_mux.c b/drivers/usb/typec/tcpc_gen_mux.c
new file mode 100644
index 000000000000..ea40b52ef6a6
--- /dev/null
+++ b/drivers/usb/typec/tcpc_gen_mux.c
@@ -0,0 +1,122 @@
+/*
+ * Generic TCPC mux driver using the mux subsys
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/mux/usb.h>
+#include <linux/usb/tcpm.h>
+
+struct tcpc_gen_mux_data {
+	struct tcpc_mux_dev mux;
+	struct device *dev;
+	struct mux_control *type_c_mode_mux; /* Type-C cross switch / mux */
+	struct mux_control *usb_role_mux;    /* USB Device / Host mode mux */
+	bool muxes_set;
+};
+
+static int tcpc_gen_mux_set(struct tcpc_mux_dev *mux_dev,
+			    enum tcpc_mux_mode mux_mode,
+			    enum tcpc_usb_switch usb_config,
+			    enum typec_cc_polarity polarity)
+{
+	struct tcpc_gen_mux_data *data =
+		container_of(mux_dev, struct tcpc_gen_mux_data, mux);
+	unsigned int typec_state = MUX_TYPEC_USB;
+	unsigned int usb_state = MUX_USB_DEVICE;
+	int ret;
+
+	/* Put the muxes back in their open (idle) state */
+	if (data->muxes_set) {
+		mux_control_deselect(data->type_c_mode_mux);
+		mux_control_deselect(data->usb_role_mux);
+		data->muxes_set = false;
+	}
+
+	switch (mux_mode) {
+	case TYPEC_MUX_NONE:
+		/* Muxes are in their open state, done. */
+		return 0;
+	case TYPEC_MUX_USB_DEVICE:
+		typec_state = MUX_TYPEC_USB;
+		usb_state = MUX_USB_DEVICE;
+		break;
+	case TYPEC_MUX_USB_HOST:
+		typec_state = MUX_TYPEC_USB;
+		usb_state = MUX_USB_HOST;
+		break;
+	case TYPEC_MUX_DP:
+		typec_state = MUX_TYPEC_DP;
+		break;
+	case TYPEC_MUX_DOCK:
+		typec_state = MUX_TYPEC_USB_AND_DP;
+		usb_state = MUX_USB_HOST;
+		break;
+	}
+
+	if (polarity)
+		typec_state |= MUX_TYPEC_POLARITY_INV;
+
+	ret = mux_control_select(data->type_c_mode_mux, typec_state);
+	if (ret) {
+		dev_err(data->dev, "Error setting Type-C mode mux: %d\n", ret);
+		return ret;
+	}
+
+	ret = mux_control_select(data->usb_role_mux, usb_state);
+	if (ret) {
+		dev_err(data->dev, "Error setting USB role mux: %d\n", ret);
+		mux_control_deselect(data->type_c_mode_mux);
+		return ret;
+	}
+
+	data->muxes_set = true;
+	return 0;
+}
+
+struct tcpc_mux_dev *devm_tcpc_gen_mux_create(struct device *dev)
+{
+	struct tcpc_gen_mux_data *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	/* The use of either mux is optional */
+	data->type_c_mode_mux =
+		devm_mux_control_get_optional(dev, "type-c-mode-mux");
+	if (IS_ERR(data->type_c_mode_mux)) {
+		ret = PTR_ERR(data->type_c_mode_mux);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Error getting Type-C mux: %d\n", ret);
+		return ERR_PTR(-ret);
+	}
+
+	data->usb_role_mux = devm_mux_control_get_optional(dev, "usb-role-mux");
+	if (IS_ERR(data->usb_role_mux)) {
+		ret = PTR_ERR(data->usb_role_mux);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Error getting USB role mux: %d\n", ret);
+		return ERR_PTR(-ret);
+	}
+
+	data->dev = dev;
+	data->mux.set = tcpc_gen_mux_set;
+
+	return &data->mux;
+}
+EXPORT_SYMBOL_GPL(devm_tcpc_gen_mux_create);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Generic Type-C mux driver using the mux subsys");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index bc76389ee257..3ad97da5fe16 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -207,4 +207,6 @@ void tcpm_pd_transmit_complete(struct tcpm_port *port,
 void tcpm_pd_hard_reset(struct tcpm_port *port);
 void tcpm_tcpc_reset(struct tcpm_port *port);
 
+struct tcpc_mux_dev *devm_tcpc_gen_mux_create(struct device *dev);
+
 #endif /* __LINUX_USB_TCPM_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 12/14] staging: typec: Add Generic TCPC mux driver using the mux subsys
@ 2017-09-22 18:38   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

So far the mux functionality of the tcpm code has not been hooked up
in any tcpc drivers. This commit adds a generic TCPC mux driver using
the mux subsys, which tcpc drivers can use to provide mux functionality
in cases where an external my is used.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v3:
-Use new devm_mux_control_get_optional()
-Simplify tcpc_gen_mux_set as we now no longer need to worry about the muxes
 being present
-Adjust for updated MUX_TYPEC_* defines
---
 drivers/usb/typec/Makefile       |   2 +-
 drivers/usb/typec/tcpc_gen_mux.c | 122 +++++++++++++++++++++++++++++++++++++++
 include/linux/usb/tcpm.h         |   2 +
 3 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/typec/tcpc_gen_mux.c

diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index b77688ce1f16..95a7d9c4527b 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_TYPEC)		+= typec.o
-obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o
+obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o tcpc_gen_mux.o
 obj-y				+= fusb302/
 obj-$(CONFIG_TYPEC_WCOVE)	+= typec_wcove.o
 obj-$(CONFIG_TYPEC_UCSI)	+= ucsi/
diff --git a/drivers/usb/typec/tcpc_gen_mux.c b/drivers/usb/typec/tcpc_gen_mux.c
new file mode 100644
index 000000000000..ea40b52ef6a6
--- /dev/null
+++ b/drivers/usb/typec/tcpc_gen_mux.c
@@ -0,0 +1,122 @@
+/*
+ * Generic TCPC mux driver using the mux subsys
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option)
+ * any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/mux/usb.h>
+#include <linux/usb/tcpm.h>
+
+struct tcpc_gen_mux_data {
+	struct tcpc_mux_dev mux;
+	struct device *dev;
+	struct mux_control *type_c_mode_mux; /* Type-C cross switch / mux */
+	struct mux_control *usb_role_mux;    /* USB Device / Host mode mux */
+	bool muxes_set;
+};
+
+static int tcpc_gen_mux_set(struct tcpc_mux_dev *mux_dev,
+			    enum tcpc_mux_mode mux_mode,
+			    enum tcpc_usb_switch usb_config,
+			    enum typec_cc_polarity polarity)
+{
+	struct tcpc_gen_mux_data *data =
+		container_of(mux_dev, struct tcpc_gen_mux_data, mux);
+	unsigned int typec_state = MUX_TYPEC_USB;
+	unsigned int usb_state = MUX_USB_DEVICE;
+	int ret;
+
+	/* Put the muxes back in their open (idle) state */
+	if (data->muxes_set) {
+		mux_control_deselect(data->type_c_mode_mux);
+		mux_control_deselect(data->usb_role_mux);
+		data->muxes_set = false;
+	}
+
+	switch (mux_mode) {
+	case TYPEC_MUX_NONE:
+		/* Muxes are in their open state, done. */
+		return 0;
+	case TYPEC_MUX_USB_DEVICE:
+		typec_state = MUX_TYPEC_USB;
+		usb_state = MUX_USB_DEVICE;
+		break;
+	case TYPEC_MUX_USB_HOST:
+		typec_state = MUX_TYPEC_USB;
+		usb_state = MUX_USB_HOST;
+		break;
+	case TYPEC_MUX_DP:
+		typec_state = MUX_TYPEC_DP;
+		break;
+	case TYPEC_MUX_DOCK:
+		typec_state = MUX_TYPEC_USB_AND_DP;
+		usb_state = MUX_USB_HOST;
+		break;
+	}
+
+	if (polarity)
+		typec_state |= MUX_TYPEC_POLARITY_INV;
+
+	ret = mux_control_select(data->type_c_mode_mux, typec_state);
+	if (ret) {
+		dev_err(data->dev, "Error setting Type-C mode mux: %d\n", ret);
+		return ret;
+	}
+
+	ret = mux_control_select(data->usb_role_mux, usb_state);
+	if (ret) {
+		dev_err(data->dev, "Error setting USB role mux: %d\n", ret);
+		mux_control_deselect(data->type_c_mode_mux);
+		return ret;
+	}
+
+	data->muxes_set = true;
+	return 0;
+}
+
+struct tcpc_mux_dev *devm_tcpc_gen_mux_create(struct device *dev)
+{
+	struct tcpc_gen_mux_data *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	/* The use of either mux is optional */
+	data->type_c_mode_mux =
+		devm_mux_control_get_optional(dev, "type-c-mode-mux");
+	if (IS_ERR(data->type_c_mode_mux)) {
+		ret = PTR_ERR(data->type_c_mode_mux);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Error getting Type-C mux: %d\n", ret);
+		return ERR_PTR(-ret);
+	}
+
+	data->usb_role_mux = devm_mux_control_get_optional(dev, "usb-role-mux");
+	if (IS_ERR(data->usb_role_mux)) {
+		ret = PTR_ERR(data->usb_role_mux);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Error getting USB role mux: %d\n", ret);
+		return ERR_PTR(-ret);
+	}
+
+	data->dev = dev;
+	data->mux.set = tcpc_gen_mux_set;
+
+	return &data->mux;
+}
+EXPORT_SYMBOL_GPL(devm_tcpc_gen_mux_create);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Generic Type-C mux driver using the mux subsys");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index bc76389ee257..3ad97da5fe16 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -207,4 +207,6 @@ void tcpm_pd_transmit_complete(struct tcpm_port *port,
 void tcpm_pd_hard_reset(struct tcpm_port *port);
 void tcpm_tcpc_reset(struct tcpm_port *port);
 
+struct tcpc_mux_dev *devm_tcpc_gen_mux_create(struct device *dev);
+
 #endif /* __LINUX_USB_TCPM_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 13/14] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support
@ 2017-09-22 18:38   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb, Rob Herring, Mark Rutland,
	devicetree

Add mux support to the fusb302 driver, call devm_tcpc_gen_mux_create()
to let the generic tcpc_mux_dev code create a tcpc_mux_dev for us.

Also document the mux-names used by the generic tcpc_mux_dev code in
our devicetree bindings.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v3:
-Drop devicetree bindings documentation, since this is only used with
 device-properties set by platform code on X86/ACPI now, we don't need
 bindings yet
---
 drivers/usb/typec/fusb302/fusb302.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c
index e790b67d4953..10415d6b2292 100644
--- a/drivers/usb/typec/fusb302/fusb302.c
+++ b/drivers/usb/typec/fusb302/fusb302.c
@@ -1259,7 +1259,6 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
 	fusb302_tcpc_dev->set_roles = tcpm_set_roles;
 	fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
 	fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
-	fusb302_tcpc_dev->mux = NULL;
 }
 
 static const char * const cc_polarity_name[] = {
@@ -1817,6 +1816,10 @@ static int fusb302_probe(struct i2c_client *client,
 			return -EPROBE_DEFER;
 	}
 
+	chip->tcpc_dev.mux = devm_tcpc_gen_mux_create(dev);
+	if (IS_ERR(chip->tcpc_dev.mux))
+		return PTR_ERR(chip->tcpc_dev.mux);
+
 	cfg.drv_data = chip;
 	chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg);
 	if (IS_ERR(chip->psy)) {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 13/14] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support
@ 2017-09-22 18:38   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	platform-driver-x86-u79uwXL29TY76Z2rM5mHXA,
	devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	Rob Herring, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA

Add mux support to the fusb302 driver, call devm_tcpc_gen_mux_create()
to let the generic tcpc_mux_dev code create a tcpc_mux_dev for us.

Also document the mux-names used by the generic tcpc_mux_dev code in
our devicetree bindings.

Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
Changes in v3:
-Drop devicetree bindings documentation, since this is only used with
 device-properties set by platform code on X86/ACPI now, we don't need
 bindings yet
---
 drivers/usb/typec/fusb302/fusb302.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c
index e790b67d4953..10415d6b2292 100644
--- a/drivers/usb/typec/fusb302/fusb302.c
+++ b/drivers/usb/typec/fusb302/fusb302.c
@@ -1259,7 +1259,6 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
 	fusb302_tcpc_dev->set_roles = tcpm_set_roles;
 	fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
 	fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
-	fusb302_tcpc_dev->mux = NULL;
 }
 
 static const char * const cc_polarity_name[] = {
@@ -1817,6 +1816,10 @@ static int fusb302_probe(struct i2c_client *client,
 			return -EPROBE_DEFER;
 	}
 
+	chip->tcpc_dev.mux = devm_tcpc_gen_mux_create(dev);
+	if (IS_ERR(chip->tcpc_dev.mux))
+		return PTR_ERR(chip->tcpc_dev.mux);
+
 	cfg.drv_data = chip;
 	chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg);
 	if (IS_ERR(chip->psy)) {
-- 
2.14.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 14/14] platform/x86: intel_cht_int33fe: Add mux mappings for the Type-C port
  2017-09-22 18:37 ` Hans de Goede
@ 2017-09-22 18:38   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

We need to add mappings for the mux subsys to be able to find the
muxes for the fusb302 driver to be able to control the PI3USB30532
Type-C mux and the device/host mux integrated in the CHT SoC.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/platform/x86/Kconfig             |  1 +
 drivers/platform/x86/intel_cht_int33fe.c | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 312d2472b8b3..830ff8d0a1eb 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -794,6 +794,7 @@ config ACPI_CMPC
 config INTEL_CHT_INT33FE
 	tristate "Intel Cherry Trail ACPI INT33FE Driver"
 	depends on X86 && ACPI && I2C && REGULATOR
+	select MULTIPLEXER
 	---help---
 	  This driver add support for the INT33FE ACPI device found on
 	  some Intel Cherry Trail devices.
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index b2925d996613..89ba510dac78 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mux/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
@@ -35,6 +36,19 @@ struct cht_int33fe_data {
 	struct i2c_client *pi3usb30532;
 };
 
+static struct mux_lookup cht_int33fe_mux_lookup[] = {
+	{
+		.provider = "i2c-pi3usb30532",
+		.dev_id   = "i2c-fusb302",
+		.mux_name = "type-c-mode-mux",
+	},
+	{
+		.provider = "intel_cht_usb_mux",
+		.dev_id   = "i2c-fusb302",
+		.mux_name = "usb-role-mux",
+	},
+};
+
 /*
  * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
  * the max17047 both through the INT33FE ACPI device (it is right there
@@ -177,6 +191,9 @@ static int cht_int33fe_probe(struct i2c_client *client)
 	board_info.properties = fusb302_props;
 	board_info.irq = fusb302_irq;
 
+	mux_add_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
 	if (!data->fusb302)
 		goto out_unregister_max17047;
@@ -200,6 +217,9 @@ static int cht_int33fe_probe(struct i2c_client *client)
 	if (data->max17047)
 		i2c_unregister_device(data->max17047);
 
+	mux_remove_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
 }
 
@@ -212,6 +232,9 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
 	if (data->max17047)
 		i2c_unregister_device(data->max17047);
 
+	mux_remove_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	return 0;
 }
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v3 14/14] platform/x86: intel_cht_int33fe: Add mux mappings for the Type-C port
@ 2017-09-22 18:38   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-09-22 18:38 UTC (permalink / raw)
  To: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: Hans de Goede, linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

We need to add mappings for the mux subsys to be able to find the
muxes for the fusb302 driver to be able to control the PI3USB30532
Type-C mux and the device/host mux integrated in the CHT SoC.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/platform/x86/Kconfig             |  1 +
 drivers/platform/x86/intel_cht_int33fe.c | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 312d2472b8b3..830ff8d0a1eb 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -794,6 +794,7 @@ config ACPI_CMPC
 config INTEL_CHT_INT33FE
 	tristate "Intel Cherry Trail ACPI INT33FE Driver"
 	depends on X86 && ACPI && I2C && REGULATOR
+	select MULTIPLEXER
 	---help---
 	  This driver add support for the INT33FE ACPI device found on
 	  some Intel Cherry Trail devices.
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index b2925d996613..89ba510dac78 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mux/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
@@ -35,6 +36,19 @@ struct cht_int33fe_data {
 	struct i2c_client *pi3usb30532;
 };
 
+static struct mux_lookup cht_int33fe_mux_lookup[] = {
+	{
+		.provider = "i2c-pi3usb30532",
+		.dev_id   = "i2c-fusb302",
+		.mux_name = "type-c-mode-mux",
+	},
+	{
+		.provider = "intel_cht_usb_mux",
+		.dev_id   = "i2c-fusb302",
+		.mux_name = "usb-role-mux",
+	},
+};
+
 /*
  * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates
  * the max17047 both through the INT33FE ACPI device (it is right there
@@ -177,6 +191,9 @@ static int cht_int33fe_probe(struct i2c_client *client)
 	board_info.properties = fusb302_props;
 	board_info.irq = fusb302_irq;
 
+	mux_add_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
 	if (!data->fusb302)
 		goto out_unregister_max17047;
@@ -200,6 +217,9 @@ static int cht_int33fe_probe(struct i2c_client *client)
 	if (data->max17047)
 		i2c_unregister_device(data->max17047);
 
+	mux_remove_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
 }
 
@@ -212,6 +232,9 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
 	if (data->max17047)
 		i2c_unregister_device(data->max17047);
 
+	mux_remove_table(cht_int33fe_mux_lookup,
+		      ARRAY_SIZE(cht_int33fe_mux_lookup));
+
 	return 0;
 }
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 05/14] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
  2017-09-22 18:37   ` Hans de Goede
@ 2017-09-26  7:45     ` Heikki Krogerus
  -1 siblings, 0 replies; 38+ messages in thread
From: Heikki Krogerus @ 2017-09-26  7:45 UTC (permalink / raw)
  To: Hans de Goede
  Cc: MyungJoo Ham, Chanwoo Choi, Guenter Roeck, Darren Hart,
	Andy Shevchenko, Peter Rosin, Mathias Nyman, linux-kernel,
	platform-driver-x86, devel, Kuppuswamy Sathyanarayanan,
	Sathyanarayanan Kuppuswamy Natarajan, Greg Kroah-Hartman,
	linux-usb

Hi Hans,

Sorry about the late response.

On Fri, Sep 22, 2017 at 08:37:54PM +0200, Hans de Goede wrote:
> Add MUX_USB_* and MUX_TYPEC_* state constant defines, which can be used by
> USB device/host, resp. Type-C polarity/role/altmode mux drivers and
> consumers to ensure that they agree on the meaning of the
> mux_control_select() state argument.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Start numbering of defines at 0 not 1
> -Use a new usb.h header, rather then adding these to consumer.h
> -Add separate MUX_USB_* and MUX_TYPEC_* defines
> 
> Changes in v3:
> -Simplify MUX_TYPEC_* states, drop having separate USB HOST / DEVICE states
> ---
>  include/linux/mux/usb.h | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
>  create mode 100644 include/linux/mux/usb.h
> 
> diff --git a/include/linux/mux/usb.h b/include/linux/mux/usb.h
> new file mode 100644
> index 000000000000..2fec06846e14
> --- /dev/null
> +++ b/include/linux/mux/usb.h
> @@ -0,0 +1,31 @@
> +/*
> + * mux/usb.h - definitions for USB multiplexers
> + *
> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef _LINUX_MUX_USB_H
> +#define _LINUX_MUX_USB_H
> +
> +/* Mux state values for USB device/host role muxes */
> +#define MUX_USB_DEVICE		(0) /* USB device mode */
> +#define MUX_USB_HOST		(1) /* USB host mode */
> +#define MUX_USB_STATES		(2)
> +
> +/*
> + * Mux state values for Type-C polarity/role/altmode muxes.
> + *
> + * MUX_TYPEC_POLARITY_INV may be or-ed together with any other mux-state as
> + * inverted-polarity (Type-C plugged in upside down) can happen with any
> + * other mux-state.
> + */
> +#define MUX_TYPEC_POLARITY_INV		BIT(0)   /* Polarity inverted bit */
> +#define MUX_TYPEC_USB			(0 << 1) /* USB only mode */

Predefined values for the usb role are probable OK (maybe), but..

> +#define MUX_TYPEC_USB_AND_DP		(1 << 1) /* USB host + 2 lanes DP */
> +#define MUX_TYPEC_DP			(2 << 1) /* 4 lanes Display Port */
> +#define MUX_TYPEC_STATES		(3 << 1)

..for alternate modes, no way. We don't need to try to keep a list of
all the possible states in one place. The pin configurations need to be
defined per alternate mode (per SVID), and we should not mix the
whole mux subsystem into that.

You are also only considering muxing. We need to deliver the
negotiated pin configurations to other components as well. For
example, in case of DisplayPort, the DP controller will need to know
at least the lane count, but also most likely the plug orientation.

And also, I think this is clear to everybody, but just in case it
isn't: Let's not mix TCPM or TCPC into the alternate mode specific pin
configuration handling at all. The alternate mode specific drivers can
take care of that. I think I need to prepare RFC out of my "alternate
mode bus" idea to give you guys an idea how that should work. Give me
a day or two.

But in any case, drop all alternate mode stuff from this series.
Let's move one step at the time.


Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 05/14] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
@ 2017-09-26  7:45     ` Heikki Krogerus
  0 siblings, 0 replies; 38+ messages in thread
From: Heikki Krogerus @ 2017-09-26  7:45 UTC (permalink / raw)
  To: Hans de Goede
  Cc: devel, Kuppuswamy Sathyanarayanan, Mathias Nyman,
	Greg Kroah-Hartman, linux-usb, linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan, Chanwoo Choi, MyungJoo Ham,
	Guenter Roeck, Darren Hart, Peter Rosin, Andy Shevchenko

Hi Hans,

Sorry about the late response.

On Fri, Sep 22, 2017 at 08:37:54PM +0200, Hans de Goede wrote:
> Add MUX_USB_* and MUX_TYPEC_* state constant defines, which can be used by
> USB device/host, resp. Type-C polarity/role/altmode mux drivers and
> consumers to ensure that they agree on the meaning of the
> mux_control_select() state argument.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Start numbering of defines at 0 not 1
> -Use a new usb.h header, rather then adding these to consumer.h
> -Add separate MUX_USB_* and MUX_TYPEC_* defines
> 
> Changes in v3:
> -Simplify MUX_TYPEC_* states, drop having separate USB HOST / DEVICE states
> ---
>  include/linux/mux/usb.h | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
>  create mode 100644 include/linux/mux/usb.h
> 
> diff --git a/include/linux/mux/usb.h b/include/linux/mux/usb.h
> new file mode 100644
> index 000000000000..2fec06846e14
> --- /dev/null
> +++ b/include/linux/mux/usb.h
> @@ -0,0 +1,31 @@
> +/*
> + * mux/usb.h - definitions for USB multiplexers
> + *
> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef _LINUX_MUX_USB_H
> +#define _LINUX_MUX_USB_H
> +
> +/* Mux state values for USB device/host role muxes */
> +#define MUX_USB_DEVICE		(0) /* USB device mode */
> +#define MUX_USB_HOST		(1) /* USB host mode */
> +#define MUX_USB_STATES		(2)
> +
> +/*
> + * Mux state values for Type-C polarity/role/altmode muxes.
> + *
> + * MUX_TYPEC_POLARITY_INV may be or-ed together with any other mux-state as
> + * inverted-polarity (Type-C plugged in upside down) can happen with any
> + * other mux-state.
> + */
> +#define MUX_TYPEC_POLARITY_INV		BIT(0)   /* Polarity inverted bit */
> +#define MUX_TYPEC_USB			(0 << 1) /* USB only mode */

Predefined values for the usb role are probable OK (maybe), but..

> +#define MUX_TYPEC_USB_AND_DP		(1 << 1) /* USB host + 2 lanes DP */
> +#define MUX_TYPEC_DP			(2 << 1) /* 4 lanes Display Port */
> +#define MUX_TYPEC_STATES		(3 << 1)

..for alternate modes, no way. We don't need to try to keep a list of
all the possible states in one place. The pin configurations need to be
defined per alternate mode (per SVID), and we should not mix the
whole mux subsystem into that.

You are also only considering muxing. We need to deliver the
negotiated pin configurations to other components as well. For
example, in case of DisplayPort, the DP controller will need to know
at least the lane count, but also most likely the plug orientation.

And also, I think this is clear to everybody, but just in case it
isn't: Let's not mix TCPM or TCPC into the alternate mode specific pin
configuration handling at all. The alternate mode specific drivers can
take care of that. I think I need to prepare RFC out of my "alternate
mode bus" idea to give you guys an idea how that should work. Give me
a day or two.

But in any case, drop all alternate mode stuff from this series.
Let's move one step at the time.


Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 07/14] xhci: Add Intel cherrytrail extended cap / otg phy mux handling
  2017-09-22 18:37   ` Hans de Goede
@ 2017-10-05 11:13     ` Mathias Nyman
  -1 siblings, 0 replies; 38+ messages in thread
From: Mathias Nyman @ 2017-10-05 11:13 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Chanwoo Choi, Guenter Roeck,
	Heikki Krogerus, Darren Hart, Andy Shevchenko, Peter Rosin
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

On 22.09.2017 21:37, Hans de Goede wrote:
> The Intel cherrytrail xhci controller has an extended cap mmio-range
> which contains registers to control the muxing to the xhci (host mode)
> or the dwc3 (device mode) and vbus-detection for the otg usb-phy.
>
> Having a mux driver included in the xhci code (or under drivers/usb/host)
> is not desirable. So this commit adds a simple handler for this extended
> capability, which creates a platform device with the caps mmio region as
> resource, this allows us to write a separate platform mux driver for the
> mux.
>
> Note this commit adds a call to the new xhci_ext_cap_init() function
> to xhci_pci_probe(), it is added here because xhci_ext_cap_init() must
> be called only once. If in the future we also want to handle ext-caps
> on non pci XHCI HCDs from xhci_ext_cap_init() a call to it should also
> be added to other bus probe paths.
>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Check xHCI controller PCI device-id instead of only checking for the
>   Intel Extended capability ID, as the Extended capability ID is used on
>   other model Intel xHCI controllers too
>
> Changes in v3:
> -Add a new generic xhci_ext_cap_init() function and handle the new
>   XHCI_INTEL_CHT_USB_MUX quirk there.
> ---

Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 07/14] xhci: Add Intel cherrytrail extended cap / otg phy mux handling
@ 2017-10-05 11:13     ` Mathias Nyman
  0 siblings, 0 replies; 38+ messages in thread
From: Mathias Nyman @ 2017-10-05 11:13 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Chanwoo Choi, Guenter Roeck,
	Heikki Krogerus, Darren Hart, Andy Shevchenko, Peter Rosin
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

On 22.09.2017 21:37, Hans de Goede wrote:
> The Intel cherrytrail xhci controller has an extended cap mmio-range
> which contains registers to control the muxing to the xhci (host mode)
> or the dwc3 (device mode) and vbus-detection for the otg usb-phy.
>
> Having a mux driver included in the xhci code (or under drivers/usb/host)
> is not desirable. So this commit adds a simple handler for this extended
> capability, which creates a platform device with the caps mmio region as
> resource, this allows us to write a separate platform mux driver for the
> mux.
>
> Note this commit adds a call to the new xhci_ext_cap_init() function
> to xhci_pci_probe(), it is added here because xhci_ext_cap_init() must
> be called only once. If in the future we also want to handle ext-caps
> on non pci XHCI HCDs from xhci_ext_cap_init() a call to it should also
> be added to other bus probe paths.
>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Check xHCI controller PCI device-id instead of only checking for the
>   Intel Extended capability ID, as the Extended capability ID is used on
>   other model Intel xHCI controllers too
>
> Changes in v3:
> -Add a new generic xhci_ext_cap_init() function and handle the new
>   XHCI_INTEL_CHT_USB_MUX quirk there.
> ---

Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
  2017-09-22 18:37   ` Hans de Goede
@ 2017-10-18  2:33     ` Chanwoo Choi
  -1 siblings, 0 replies; 38+ messages in thread
From: Chanwoo Choi @ 2017-10-18  2:33 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Hi Hans,

On 2017년 09월 23일 03:37, Hans de Goede wrote:
> Cherry Trail SoCs have a built-in USB-role mux for switching between
> the host and device controllers, rather then using an external mux
> controller by a GPIO.
> 
> There is a driver using the mux-subsys to control this mux, this
> commit adds support to the intel-int3496 driver to get a mux_controller
> handle for the mux and set the mux through the mux-subsys rather then
> through a GPIO.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>  compile on !X86
> -Minor code style tweaks
> ---
>  drivers/extcon/Kconfig                |  3 +-
>  drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>  2 files changed, 61 insertions(+), 1 deletion(-)

Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

[snip]

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
@ 2017-10-18  2:33     ` Chanwoo Choi
  0 siblings, 0 replies; 38+ messages in thread
From: Chanwoo Choi @ 2017-10-18  2:33 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Hi Hans,

On 2017년 09월 23일 03:37, Hans de Goede wrote:
> Cherry Trail SoCs have a built-in USB-role mux for switching between
> the host and device controllers, rather then using an external mux
> controller by a GPIO.
> 
> There is a driver using the mux-subsys to control this mux, this
> commit adds support to the intel-int3496 driver to get a mux_controller
> handle for the mux and set the mux through the mux-subsys rather then
> through a GPIO.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>  compile on !X86
> -Minor code style tweaks
> ---
>  drivers/extcon/Kconfig                |  3 +-
>  drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>  2 files changed, 61 insertions(+), 1 deletion(-)

Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

[snip]

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
  2017-10-18  2:33     ` Chanwoo Choi
@ 2017-10-18  9:14       ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-10-18  9:14 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

Hi,

On 18-10-17 04:33, Chanwoo Choi wrote:
> Hi Hans,
> 
> On 2017년 09월 23일 03:37, Hans de Goede wrote:
>> Cherry Trail SoCs have a built-in USB-role mux for switching between
>> the host and device controllers, rather then using an external mux
>> controller by a GPIO.
>>
>> There is a driver using the mux-subsys to control this mux, this
>> commit adds support to the intel-int3496 driver to get a mux_controller
>> handle for the mux and set the mux through the mux-subsys rather then
>> through a GPIO.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> Changes in v2:
>> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>>   compile on !X86
>> -Minor code style tweaks
>> ---
>>   drivers/extcon/Kconfig                |  3 +-
>>   drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>>   2 files changed, 61 insertions(+), 1 deletion(-)
> 
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

Note that there have been some comments on this series, and it
is not sure yet how we are going to end up handling this. So
please do not merge this yet, as we may end up with another
solution.

Regards,

Hans

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
@ 2017-10-18  9:14       ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2017-10-18  9:14 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: devel, Kuppuswamy Sathyanarayanan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, platform-driver-x86,
	Sathyanarayanan Kuppuswamy Natarajan

Hi,

On 18-10-17 04:33, Chanwoo Choi wrote:
> Hi Hans,
> 
> On 2017년 09월 23일 03:37, Hans de Goede wrote:
>> Cherry Trail SoCs have a built-in USB-role mux for switching between
>> the host and device controllers, rather then using an external mux
>> controller by a GPIO.
>>
>> There is a driver using the mux-subsys to control this mux, this
>> commit adds support to the intel-int3496 driver to get a mux_controller
>> handle for the mux and set the mux through the mux-subsys rather then
>> through a GPIO.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> Changes in v2:
>> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>>   compile on !X86
>> -Minor code style tweaks
>> ---
>>   drivers/extcon/Kconfig                |  3 +-
>>   drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>>   2 files changed, 61 insertions(+), 1 deletion(-)
> 
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

Note that there have been some comments on this series, and it
is not sure yet how we are going to end up handling this. So
please do not merge this yet, as we may end up with another
solution.

Regards,

Hans
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
  2017-10-18  9:14       ` Hans de Goede
@ 2017-10-18  9:40         ` Chanwoo Choi
  -1 siblings, 0 replies; 38+ messages in thread
From: Chanwoo Choi @ 2017-10-18  9:40 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

On 2017년 10월 18일 18:14, Hans de Goede wrote:
> Hi,
> 
> On 18-10-17 04:33, Chanwoo Choi wrote:
>> Hi Hans,
>>
>> On 2017년 09월 23일 03:37, Hans de Goede wrote:
>>> Cherry Trail SoCs have a built-in USB-role mux for switching between
>>> the host and device controllers, rather then using an external mux
>>> controller by a GPIO.
>>>
>>> There is a driver using the mux-subsys to control this mux, this
>>> commit adds support to the intel-int3496 driver to get a mux_controller
>>> handle for the mux and set the mux through the mux-subsys rather then
>>> through a GPIO.
>>>
>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>> ---
>>> Changes in v2:
>>> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>>>   compile on !X86
>>> -Minor code style tweaks
>>> ---
>>>   drivers/extcon/Kconfig                |  3 +-
>>>   drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>>>   2 files changed, 61 insertions(+), 1 deletion(-)
>>
>> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> 
> Note that there have been some comments on this series, and it
> is not sure yet how we are going to end up handling this. So
> please do not merge this yet, as we may end up with another
> solution.

Sure. I don't merge only this patch. After finishing the review
of this patchset, one maintainer apply all patches and then
send immutable pull request.

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux
@ 2017-10-18  9:40         ` Chanwoo Choi
  0 siblings, 0 replies; 38+ messages in thread
From: Chanwoo Choi @ 2017-10-18  9:40 UTC (permalink / raw)
  To: Hans de Goede, MyungJoo Ham, Guenter Roeck, Heikki Krogerus,
	Darren Hart, Andy Shevchenko, Peter Rosin, Mathias Nyman
  Cc: linux-kernel, platform-driver-x86, devel,
	Kuppuswamy Sathyanarayanan, Sathyanarayanan Kuppuswamy Natarajan,
	Greg Kroah-Hartman, linux-usb

On 2017년 10월 18일 18:14, Hans de Goede wrote:
> Hi,
> 
> On 18-10-17 04:33, Chanwoo Choi wrote:
>> Hi Hans,
>>
>> On 2017년 09월 23일 03:37, Hans de Goede wrote:
>>> Cherry Trail SoCs have a built-in USB-role mux for switching between
>>> the host and device controllers, rather then using an external mux
>>> controller by a GPIO.
>>>
>>> There is a driver using the mux-subsys to control this mux, this
>>> commit adds support to the intel-int3496 driver to get a mux_controller
>>> handle for the mux and set the mux through the mux-subsys rather then
>>> through a GPIO.
>>>
>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>> ---
>>> Changes in v2:
>>> -Drop || COMPILE_TEST from Kconfig depends on, as we will now fail to
>>>   compile on !X86
>>> -Minor code style tweaks
>>> ---
>>>   drivers/extcon/Kconfig                |  3 +-
>>>   drivers/extcon/extcon-intel-int3496.c | 59 +++++++++++++++++++++++++++++++++++
>>>   2 files changed, 61 insertions(+), 1 deletion(-)
>>
>> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> 
> Note that there have been some comments on this series, and it
> is not sure yet how we are going to end up handling this. So
> please do not merge this yet, as we may end up with another
> solution.

Sure. I don't merge only this patch. After finishing the review
of this patchset, one maintainer apply all patches and then
send immutable pull request.

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2017-10-18  9:40 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-22 18:37 [PATCH v3 01/14] mux: core: Add mux_control_get_optional() API Hans de Goede
2017-09-22 18:37 ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 02/14] mux: core: Add explicit hook to leave the mux as-is on init/registration Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 03/14] mux: core: Add of_mux_control_get helper function Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 04/14] mux: core: Add support for getting a mux controller on a non DT platform Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 05/14] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-26  7:45   ` Heikki Krogerus
2017-09-26  7:45     ` Heikki Krogerus
2017-09-22 18:37 ` [PATCH v3 06/14] xhci: Add option to get next extended capability in list by passing id = 0 Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 07/14] xhci: Add Intel cherrytrail extended cap / otg phy mux handling Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-10-05 11:13   ` Mathias Nyman
2017-10-05 11:13     ` Mathias Nyman
2017-09-22 18:37 ` [PATCH v3 08/14] mux: Add Intel Cherrytrail USB mux driver Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 09/14] mux: Add Pericom PI3USB30532 Type-C " Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-09-22 18:37 ` [PATCH v3 10/14] extcon: intel-int3496: Add support for controlling the USB-role mux Hans de Goede
2017-09-22 18:37   ` Hans de Goede
2017-10-18  2:33   ` Chanwoo Choi
2017-10-18  2:33     ` Chanwoo Choi
2017-10-18  9:14     ` Hans de Goede
2017-10-18  9:14       ` Hans de Goede
2017-10-18  9:40       ` Chanwoo Choi
2017-10-18  9:40         ` Chanwoo Choi
2017-09-22 18:38 ` [PATCH v3 11/14] staging: typec: tcpm: Set mux to device mode when configured as such Hans de Goede
2017-09-22 18:38   ` Hans de Goede
2017-09-22 18:38 ` [PATCH v3 12/14] staging: typec: Add Generic TCPC mux driver using the mux subsys Hans de Goede
2017-09-22 18:38   ` Hans de Goede
2017-09-22 18:38 ` [PATCH v3 13/14] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support Hans de Goede
2017-09-22 18:38   ` Hans de Goede
2017-09-22 18:38 ` [PATCH v3 14/14] platform/x86: intel_cht_int33fe: Add mux mappings for the Type-C port Hans de Goede
2017-09-22 18:38   ` Hans de Goede

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.