Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1726854 > unrolled thread

[PATCH v2 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems

Started byHans de Goede <hdegoede@redhat.com>
First post2017-09-05 18:50 +0200
Last post2017-09-05 18:50 +0200
Articles 11 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v2 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
    [PATCH v2 05/11] mux: Add Intel Cherrytrail USB mux driver Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
    [PATCH v2 10/11] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
    [PATCH v2 06/11] mux: Add Pericom PI3USB30532 Type-C mux driver Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
    [PATCH v2 09/11] staging: typec: Add Generic TCPC mux driver using the mux subsys Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
    [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
      Re: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap /  otg phy mux handling Mathias Nyman <mathias.nyman@linux.intel.com> - 2017-09-07 15:20 +0200
        Re: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap /  otg phy mux handling Hans de Goede <hdegoede@redhat.com> - 2017-09-07 17:50 +0200
    [PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200
      Re: [PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and  and MUX_TYPEC_* state constants Hans de Goede <hdegoede@redhat.com> - 2017-09-08 19:10 +0200
    [PATCH v2 08/11] staging: typec: tcpm: Set mux to device mode when configured as such Hans de Goede <hdegoede@redhat.com> - 2017-09-05 18:50 +0200

#1726854 — [PATCH v2 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems
Message-ID<umpcZ-5fU-5@gated-at.bofh.it>
Hi All,

Here is v2 of my USB / Type-C mux series, addressing various comments
from the reviews of v1. See the per patch changelogs for details.

For reference here the cover letter of v1:

This series consists of 4 parts:

1) Core mux changes to add support for getting mux-controllers on
   non DT platforms and to add some standardised state values for USB

2) Add Intel CHT USB mux and Pericom-PI3USB30532 Type-C mux drivers

3) Hookup the Intel CHT USB mux driver for CHT devices without Type-C

4) Hookup both the Intel CHT USB mux and Pericom-PI3USB30532 Type-C mux
   drivers to the fusb302 Type-C port controller found on some CHT x86 devs

Please review, or in the case of the drivers/mux changes (which are a dep
for some of the other patches) merge if the patches are ready.

Regards,

Hans

[toc] | [next] | [standalone]


#1726856 — [PATCH v2 05/11] mux: Add Intel Cherrytrail USB mux driver

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 05/11] mux: Add Intel Cherrytrail USB mux driver
Message-ID<umpcZ-5fU-17@gated-at.bofh.it>
In reply to#1726854
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
---
 MAINTAINERS                     |   5 +
 drivers/mux/Kconfig             |  11 ++
 drivers/mux/Makefile            |  10 +-
 drivers/mux/intel-cht-usb-mux.c | 257 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 279 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mux/intel-cht-usb-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 14a2fd905217..dfaed958db85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8991,6 +8991,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/mix/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..947cfd7af02a 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..9cd1a1f5027f
--- /dev/null
+++ b/drivers/mux/intel-cht-usb-mux.c
@@ -0,0 +1,257 @@
+/*
+ * Intel Cherrytrail USB OTG MUX driver
+ *
+ * Copyright (c) 2016 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 const unsigned int vbus_cable_ids[] = {
+	EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP,
+	EXTCON_CHG_USB_ACA, EXTCON_CHG_USB_FAST,
+};
+
+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.*/
+	while (1) {
+		val = readl(data->base + DUAL_ROLE_CFG1);
+		if (!!(val & HOST_MODE) == host_mode)
+			break;
+
+		/* Interval for polling is set to about 5 - 10 ms */
+		usleep_range(5000, 10000);
+
+		if (time_after(jiffies, timeout)) {
+			dev_warn(&mux->chip->dev,
+				 "Timeout waiting for mux to switch\n");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+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);
+	bool vbus_present = false;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vbus_cable_ids); i++) {
+		if (extcon_get_state(data->vbus_extcon, vbus_cable_ids[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].cached_state = MUX_USB_DEVICE;
+	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.13.5

[toc] | [prev] | [next] | [standalone]


#1726857 — [PATCH v2 10/11] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 10/11] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support
Message-ID<umpd0-5fU-21@gated-at.bofh.it>
In reply to#1726854
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>
---
 Documentation/devicetree/bindings/usb/fcs,fusb302.txt |  3 +++
 drivers/staging/typec/fusb302/fusb302.c               | 11 ++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt
index 472facfa5a71..63d639eadacd 100644
--- a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt
+++ b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt
@@ -6,6 +6,9 @@ Required properties :
 - interrupts             : Interrupt specifier
 
 Optional properties :
+- mux-controls           : List of mux-ctrl-specifiers containing 1 or 2 muxes
+- mux-names              : "type-c-mode-mux" when using 1 mux, or
+                           "type-c-mode-mux", "usb-role-mux" when using 2 muxes
 - fcs,max-sink-microvolt : Maximum voltage to negotiate when configured as sink
 - fcs,max-sink-microamp  : Maximum current to negotiate when configured as sink
 - fcs,max-sink-microwatt : Maximum power to negotiate when configured as sink
diff --git a/drivers/staging/typec/fusb302/fusb302.c b/drivers/staging/typec/fusb302/fusb302.c
index cf6355f59cd9..00d045d0246b 100644
--- a/drivers/staging/typec/fusb302/fusb302.c
+++ b/drivers/staging/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,16 @@ 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)) {
+		ret = PTR_ERR(chip->tcpc_dev.mux);
+		/* Use of a mux is optional (for now?), ignore -ENODEV errors */
+		if (ret == -ENODEV)
+			chip->tcpc_dev.mux = NULL;
+		else
+			return ret;
+	}
+
 	cfg.drv_data = chip;
 	chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg);
 	if (IS_ERR(chip->psy)) {
-- 
2.13.5

[toc] | [prev] | [next] | [standalone]


#1726859 — [PATCH v2 06/11] mux: Add Pericom PI3USB30532 Type-C mux driver

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 06/11] mux: Add Pericom PI3USB30532 Type-C mux driver
Message-ID<umpd0-5fU-25@gated-at.bofh.it>
In reply to#1726854
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
---
 MAINTAINERS               |  5 +++
 drivers/mux/Kconfig       | 10 +++++
 drivers/mux/Makefile      |  2 +
 drivers/mux/pi3usb30532.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+)
 create mode 100644 drivers/mux/pi3usb30532.c

diff --git a/MAINTAINERS b/MAINTAINERS
index dfaed958db85..5527b0efcef3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8996,6 +8996,11 @@ M:	Hans de Goede <hdegoede@redhat.com>
 S:	Maintained
 F:	drivers/mix/intel-cht-usb-mux.c
 
+MULTIPLEXER SUBSYSTEM PI3USB30532 DRIVER
+M:	Hans de Goede <hdegoede@redhat.com>
+S:	Maintained
+F:	drivers/mix/pi3usb30532.c
+
 MULTISOUND SOUND DRIVER
 M:	Andrew Veliath <andrewtv@usa.net>
 S:	Maintained
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 947cfd7af02a..1f6f017ee920 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..3d959e3ee8c6
--- /dev/null
+++ b/drivers/mux/pi3usb30532.c
@@ -0,0 +1,93 @@
+/*
+ * 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_DEVICE:
+	case MUX_TYPEC_HOST:
+		conf = PI3USB30532_CONF_USB3;
+		break;
+	case MUX_TYPEC_HOST_AND_DP_SRC:
+		conf = PI3USB30532_CONF_USB3_AND_2LANE_DP;
+		break;
+	case MUX_TYPEC_DP_SRC:
+		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].cached_state = MUX_IDLE_DISCONNECT;
+	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.13.5

[toc] | [prev] | [next] | [standalone]


#1726861 — [PATCH v2 09/11] staging: typec: Add Generic TCPC mux driver using the mux subsys

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 09/11] staging: typec: Add Generic TCPC mux driver using the mux subsys
Message-ID<umpd2-5fU-37@gated-at.bofh.it>
In reply to#1726854
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>
---
 drivers/staging/typec/Makefile       |   2 +-
 drivers/staging/typec/tcpc_gen_mux.c | 131 +++++++++++++++++++++++++++++++++++
 drivers/staging/typec/tcpm.h         |   2 +
 3 files changed, 134 insertions(+), 1 deletion(-)
 create mode 100644 drivers/staging/typec/tcpc_gen_mux.c

diff --git a/drivers/staging/typec/Makefile b/drivers/staging/typec/Makefile
index 30a7e29cbc9e..623d78114ee3 100644
--- a/drivers/staging/typec/Makefile
+++ b/drivers/staging/typec/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o
+obj-$(CONFIG_TYPEC_TCPM)	+= tcpm.o tcpc_gen_mux.o
 obj-$(CONFIG_TYPEC_TCPCI)	+= tcpci.o
 obj-y				+= fusb302/
diff --git a/drivers/staging/typec/tcpc_gen_mux.c b/drivers/staging/typec/tcpc_gen_mux.c
new file mode 100644
index 000000000000..d40f9eaaddf5
--- /dev/null
+++ b/drivers/staging/typec/tcpc_gen_mux.c
@@ -0,0 +1,131 @@
+/*
+ * 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 "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_DEVICE;
+	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);
+		if (data->usb_role_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_DEVICE;
+		usb_state = MUX_USB_DEVICE;
+		break;
+	case TYPEC_MUX_USB_HOST:
+		typec_state = MUX_TYPEC_HOST;
+		usb_state = MUX_USB_HOST;
+		break;
+	case TYPEC_MUX_DP:
+		typec_state = MUX_TYPEC_DP_SRC;
+		break;
+	case TYPEC_MUX_DOCK:
+		typec_state = MUX_TYPEC_HOST_AND_DP_SRC;
+		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;
+	}
+
+	if (!data->usb_role_mux)
+		goto out;
+
+	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;
+	}
+
+out:
+	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);
+
+	data->type_c_mode_mux = devm_mux_control_get(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(dev, "usb-role-mux");
+	if (IS_ERR(data->usb_role_mux)) {
+		ret = PTR_ERR(data->usb_role_mux);
+		/* The USB role mux is optional */
+		if (ret == -ENODEV) {
+			data->usb_role_mux = NULL;
+		} else {
+			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/drivers/staging/typec/tcpm.h b/drivers/staging/typec/tcpm.h
index f662eed48c86..36789005a2b0 100644
--- a/drivers/staging/typec/tcpm.h
+++ b/drivers/staging/typec/tcpm.h
@@ -164,4 +164,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.13.5

[toc] | [prev] | [next] | [standalone]


#1726862 — [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling
Message-ID<umpd2-5fU-39@gated-at.bofh.it>
In reply to#1726854
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.

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
---
 drivers/usb/host/Makefile            |  2 +-
 drivers/usb/host/xhci-intel-quirks.c | 85 ++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-pci.c          |  4 ++
 drivers/usb/host/xhci.h              |  2 +
 4 files changed, 92 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/xhci-intel-quirks.c

diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index cf2691fffcc0..441edf82eb1c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -63,7 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_DAVINCI)	+= ohci-da8xx.o
 obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
 obj-$(CONFIG_USB_FHCI_HCD)	+= fhci.o
 obj-$(CONFIG_USB_XHCI_HCD)	+= xhci-hcd.o
-obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o
+obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o xhci-intel-quirks.o
 obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
 obj-$(CONFIG_USB_XHCI_MTK)	+= xhci-mtk.o
 obj-$(CONFIG_USB_XHCI_TEGRA)	+= xhci-tegra.o
diff --git a/drivers/usb/host/xhci-intel-quirks.c b/drivers/usb/host/xhci-intel-quirks.c
new file mode 100644
index 000000000000..819f5f9da9ee
--- /dev/null
+++ b/drivers/usb/host/xhci-intel-quirks.c
@@ -0,0 +1,85 @@
+/*
+ * Intel Vendor Defined XHCI extended capability handling
+ *
+ * Copyright (c) 2016) 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;
+ */
+
+#include <linux/platform_device.h>
+#include "xhci.h"
+
+/* Extended capability IDs for Intel Vendor Defined */
+#define XHCI_EXT_CAPS_INTEL_HOST_CAP	192
+
+static void xhci_intel_unregister_pdev(void *arg)
+{
+	platform_device_unregister(arg);
+}
+
+int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci)
+{
+	struct usb_hcd *hcd = xhci_to_hcd(xhci);
+	struct device *dev = hcd->self.controller;
+	struct platform_device *pdev;
+	struct resource	res = { 0, };
+	int ret, ext_offset;
+
+	ext_offset = xhci_find_next_ext_cap(&xhci->cap_regs->hc_capbase, 0,
+					    XHCI_EXT_CAPS_INTEL_HOST_CAP);
+	if (!ext_offset) {
+		xhci_err(xhci, "couldn't find Intel ext caps\n");
+		return -ENODEV;
+	}
+
+	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 + ext_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;
+}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 8071c8fdd15e..b55c1e96abf0 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 ||
@@ -328,6 +329,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
 		xhci_pme_acpi_rtd3_enable(dev);
 
+	if (xhci->quirks & XHCI_INTEL_CHT_USB_MUX)
+		xhci_create_intel_cht_mux_pdev(xhci);
+
 	/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
 	pm_runtime_put_noidle(&dev->dev);
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e3e935291ed6..f722ee31e50d 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1821,6 +1821,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;
@@ -2005,6 +2006,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_create_intel_cht_mux_pdev(struct xhci_hcd *xhci);
 
 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
-- 
2.13.5

[toc] | [prev] | [next] | [standalone]


#1728215 — Re: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling

FromMathias Nyman <mathias.nyman@linux.intel.com>
Date2017-09-07 15:20 +0200
SubjectRe: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling
Message-ID<un4SR-ny-1@gated-at.bofh.it>
In reply to#1726862
On 05.09.2017 19:42, 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.
>
> 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
> ---
>   drivers/usb/host/Makefile            |  2 +-
>   drivers/usb/host/xhci-intel-quirks.c | 85 ++++++++++++++++++++++++++++++++++++
>   drivers/usb/host/xhci-pci.c          |  4 ++
>   drivers/usb/host/xhci.h              |  2 +
>   4 files changed, 92 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/usb/host/xhci-intel-quirks.c
>
> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
> index cf2691fffcc0..441edf82eb1c 100644
> --- a/drivers/usb/host/Makefile
> +++ b/drivers/usb/host/Makefile
> @@ -63,7 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_DAVINCI)	+= ohci-da8xx.o
>   obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
>   obj-$(CONFIG_USB_FHCI_HCD)	+= fhci.o
>   obj-$(CONFIG_USB_XHCI_HCD)	+= xhci-hcd.o
> -obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o
> +obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o xhci-intel-quirks.o
>   obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
>   obj-$(CONFIG_USB_XHCI_MTK)	+= xhci-mtk.o
>   obj-$(CONFIG_USB_XHCI_TEGRA)	+= xhci-tegra.o
> diff --git a/drivers/usb/host/xhci-intel-quirks.c b/drivers/usb/host/xhci-intel-quirks.c
> new file mode 100644

I think it would be better to have one place where we add handlers for
vendor specific extended capabilities.

Something like xhci-vendor-ext-caps.c, or just xhci-ext-caps.c as
there's a xhci-ext-caps.h header already

We could walk through the capability list once and add the needed handlers.
Something like:

+int xhci_ext_cap_init(void __iomem *base)
+{
+        u32 val;
+       u32 cap_offset;
+
+        cap_offset = xhci_next_ext_cap(base, 0);
+
+        while (cap_offset) {
+                val = readl(base + cap_offset);
+
+                switch (XHCI_EXT_CAPS_ID(val)) {
+                case XHCI_EXT_CAPS_VENDOR_INTEL:
+                        /* check hw/id/something, and call what's needed */
+                        break;
+                case XHCI_EXT_CAPS_VENDOR_XYZ:
+                        /* do something */
+                        break;
+                default:
+                        break;
+                }
+
+               printk(KERN_ERR "MATTU EXT_CAP id %d\n", XHCI_EXT_CAPS_ID(val));
+
+               cap_offset = xhci_next_ext_cap(base, cap_offset);
+        }
+
+        return 0;
+}

xhci_next_ext_cap() doesn't exist anywhere else than my local sandbox branch yet.

> +
> +/* Extended capability IDs for Intel Vendor Defined */
> +#define XHCI_EXT_CAPS_INTEL_HOST_CAP	192

XHCI_EXT_CAPS_VENDOR_INTEL
and should be in xhci-ext-caps.h

> +
> +static void xhci_intel_unregister_pdev(void *arg)
> +{
> +	platform_device_unregister(arg);
> +}
> +
> +int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci)
> +{
> +	struct usb_hcd *hcd = xhci_to_hcd(xhci);
> +	struct device *dev = hcd->self.controller;
> +	struct platform_device *pdev;
> +	struct resource	res = { 0, };
> +	int ret, ext_offset;
> +
> +	ext_offset = xhci_find_next_ext_cap(&xhci->cap_regs->hc_capbase, 0,
> +					    XHCI_EXT_CAPS_INTEL_HOST_CAP);
> +	if (!ext_offset) {
> +		xhci_err(xhci, "couldn't find Intel ext caps\n");
> +		return -ENODEV;
> +	}
> +
> +	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 + ext_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;
> +}
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 8071c8fdd15e..b55c1e96abf0 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 ||
> @@ -328,6 +329,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
>   	if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
>   		xhci_pme_acpi_rtd3_enable(dev);
>
> +	if (xhci->quirks & XHCI_INTEL_CHT_USB_MUX)
> +		xhci_create_intel_cht_mux_pdev(xhci);
> +
>   	/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
>   	pm_runtime_put_noidle(&dev->dev);
>
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index e3e935291ed6..f722ee31e50d 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1821,6 +1821,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)

Everything you said about the quirk flags in v1 is true, and I hate to
make the bulk of xhci even more PCI dependent, but I'm running out of flag bits and
would like a better solution than the current quirk flags we have.

This isn't really your concern, this patch is just doing it the same way it has
always been done, but if you have a better idea I'm all ears.

-Mathias

[toc] | [prev] | [next] | [standalone]


#1728280 — Re: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-07 17:50 +0200
SubjectRe: [PATCH v2 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling
Message-ID<un7e1-1Zv-1@gated-at.bofh.it>
In reply to#1728215
Hi,

On 07-09-17 15:14, Mathias Nyman wrote:
> On 05.09.2017 19:42, 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.
>>
>> 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
>> ---
>>   drivers/usb/host/Makefile            |  2 +-
>>   drivers/usb/host/xhci-intel-quirks.c | 85 ++++++++++++++++++++++++++++++++++++
>>   drivers/usb/host/xhci-pci.c          |  4 ++
>>   drivers/usb/host/xhci.h              |  2 +
>>   4 files changed, 92 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/usb/host/xhci-intel-quirks.c
>>
>> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
>> index cf2691fffcc0..441edf82eb1c 100644
>> --- a/drivers/usb/host/Makefile
>> +++ b/drivers/usb/host/Makefile
>> @@ -63,7 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_DAVINCI)    += ohci-da8xx.o
>>   obj-$(CONFIG_USB_UHCI_HCD)    += uhci-hcd.o
>>   obj-$(CONFIG_USB_FHCI_HCD)    += fhci.o
>>   obj-$(CONFIG_USB_XHCI_HCD)    += xhci-hcd.o
>> -obj-$(CONFIG_USB_XHCI_PCI)    += xhci-pci.o
>> +obj-$(CONFIG_USB_XHCI_PCI)    += xhci-pci.o xhci-intel-quirks.o
>>   obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
>>   obj-$(CONFIG_USB_XHCI_MTK)    += xhci-mtk.o
>>   obj-$(CONFIG_USB_XHCI_TEGRA)    += xhci-tegra.o
>> diff --git a/drivers/usb/host/xhci-intel-quirks.c b/drivers/usb/host/xhci-intel-quirks.c
>> new file mode 100644
> 
> I think it would be better to have one place where we add handlers for
> vendor specific extended capabilities.
> 
> Something like xhci-vendor-ext-caps.c, or just xhci-ext-caps.c as
> there's a xhci-ext-caps.h header already
> 
> We could walk through the capability list once and add the needed handlers.
> Something like:
> 
> +int xhci_ext_cap_init(void __iomem *base)

This will need to take a struct xhci_hcd *xhci param instead
as some of the ext_cap handling (including the cht mux code)
will need access to this.

> +{
> +        u32 val;
> +       u32 cap_offset;
> +
> +        cap_offset = xhci_next_ext_cap(base, 0);
> +
> +        while (cap_offset) {
> +                val = readl(base + cap_offset);
> +
> +                switch (XHCI_EXT_CAPS_ID(val)) {
> +                case XHCI_EXT_CAPS_VENDOR_INTEL:
> +                        /* check hw/id/something, and call what's needed */

So I see 2 options here (without making this function PCI specific)
1) Add an u32 product_id field to struct xhci_hcd; or
2) Use a quirk flag as my current code is doing.

I'm fine with doing this either way, please let me know your preference.

> +                        break;
> +                case XHCI_EXT_CAPS_VENDOR_XYZ:
> +                        /* do something */
> +                        break;
> +                default:
> +                        break;
> +                }
> +
> +               printk(KERN_ERR "MATTU EXT_CAP id %d\n", XHCI_EXT_CAPS_ID(val));
> +
> +               cap_offset = xhci_next_ext_cap(base, cap_offset);
> +        }
> +
> +        return 0;
> +}
> 
> xhci_next_ext_cap() doesn't exist anywhere else than my local sandbox branch yet.

Can you do a "git format-patch" of that and send it to me? If you
can give me that + your preference for how to check if we're
dealing with a cht xhci hcd in xhci_ext_cap_init I can do a v3
with your suggestions applied.

> 
>> +
>> +/* Extended capability IDs for Intel Vendor Defined */
>> +#define XHCI_EXT_CAPS_INTEL_HOST_CAP    192
> 
> XHCI_EXT_CAPS_VENDOR_INTEL
> and should be in xhci-ext-caps.h

Ok.

Regards,

Hans


> 
>> +
>> +static void xhci_intel_unregister_pdev(void *arg)
>> +{
>> +    platform_device_unregister(arg);
>> +}
>> +
>> +int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci)
>> +{
>> +    struct usb_hcd *hcd = xhci_to_hcd(xhci);
>> +    struct device *dev = hcd->self.controller;
>> +    struct platform_device *pdev;
>> +    struct resource    res = { 0, };
>> +    int ret, ext_offset;
>> +
>> +    ext_offset = xhci_find_next_ext_cap(&xhci->cap_regs->hc_capbase, 0,
>> +                        XHCI_EXT_CAPS_INTEL_HOST_CAP);
>> +    if (!ext_offset) {
>> +        xhci_err(xhci, "couldn't find Intel ext caps\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    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 + ext_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;
>> +}
>> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
>> index 8071c8fdd15e..b55c1e96abf0 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 ||
>> @@ -328,6 +329,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
>>       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
>>           xhci_pme_acpi_rtd3_enable(dev);
>>
>> +    if (xhci->quirks & XHCI_INTEL_CHT_USB_MUX)
>> +        xhci_create_intel_cht_mux_pdev(xhci);
>> +
>>       /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
>>       pm_runtime_put_noidle(&dev->dev);
>>
>> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
>> index e3e935291ed6..f722ee31e50d 100644
>> --- a/drivers/usb/host/xhci.h
>> +++ b/drivers/usb/host/xhci.h
>> @@ -1821,6 +1821,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)
> 
> Everything you said about the quirk flags in v1 is true, and I hate to
> make the bulk of xhci even more PCI dependent, but I'm running out of flag bits and
> would like a better solution than the current quirk flags we have.
> 
> This isn't really your concern, this patch is just doing it the same way it has
> always been done, but if you have a better idea I'm all ears.
> 
> -Mathias

[toc] | [prev] | [next] | [standalone]


#1726865 — [PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
Message-ID<umpd2-5fU-45@gated-at.bofh.it>
In reply to#1726854
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
---
 include/linux/mux/usb.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 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..44df5eca5256
--- /dev/null
+++ b/include/linux/mux/usb.h
@@ -0,0 +1,32 @@
+/*
+ * 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_DEVICE		(0 << 1) /* USB device mode */
+#define MUX_TYPEC_HOST			(1 << 1) /* USB host mode */
+#define MUX_TYPEC_HOST_AND_DP_SRC	(2 << 1) /* USB host + 2 lanes DP src */
+#define MUX_TYPEC_DP_SRC		(3 << 1) /* 4 lanes Display Port src */
+#define MUX_TYPEC_STATES		(4 << 1)
+
+#endif /* _LINUX_MUX_TYPEC_H */
-- 
2.13.5

[toc] | [prev] | [next] | [standalone]


#1729091 — Re: [PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-08 19:10 +0200
SubjectRe: [PATCH v2 03/11] mux: core: Add usb.h header with MUX_USB_* and and MUX_TYPEC_* state constants
Message-ID<unuWZ-1th-1@gated-at.bofh.it>
In reply to#1726865
Hi,

On 08-09-17 17:47, Peter Rosin wrote:
> On 2017-09-05 18:42, 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
>> ---
>>   include/linux/mux/usb.h | 32 ++++++++++++++++++++++++++++++++
>>   1 file changed, 32 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..44df5eca5256
>> --- /dev/null
>> +++ b/include/linux/mux/usb.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + * 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_DEVICE		(0 << 1) /* USB device mode */
>> +#define MUX_TYPEC_HOST			(1 << 1) /* USB host mode */
>> +#define MUX_TYPEC_HOST_AND_DP_SRC	(2 << 1) /* USB host + 2 lanes DP src */
>> +#define MUX_TYPEC_DP_SRC		(3 << 1) /* 4 lanes Display Port src */
>> +#define MUX_TYPEC_STATES		(4 << 1)
> 
> But USB Type-C muxes need not support just these states If I read it right?
> USB Type-C seems to be usable for a variety of protocols and the above list
> seems pretty much like a special case for this mux (and perhaps a set of
> other similar muxes). But when someone with a USB Type-C mux for different
> protocols shows up, that person will probably be frustrated by these
> defines, no? Or is there something I don't see that limits USB-C to DP?

In general almost all hardware is limited to the above (+ analog audio over
the 2 Sideband use pins, but I expect that to have a separate mux).

You're right, theoretically there might be other cases, e.g. there is a spec
for HDMI over Type-C (wishful thinking from the HDMI group, no one uses this),
but:

1) I expect most muxes to implement the above set, that is what all
hardware out there supports (well that or less).

2) We can always add extra defines here, that means that a Type-C mux may
not implement all states and return -EINVAL when asked for something it
does not implement, which I understand is a bit weird from a mux subsys
pov. But that can be the case anyways because even though the mux supports
these options, the board it is used on does no necessarily have to support
these options, e.g. there may be only 2 lanes of DP hooked up to the mux
(or no DP at all, but then I would them to expect a different mux).

So the Type-C Port Manager already needs to be passed some platform
data describing which features the board has and keep that in mind
when negotiation with the dongle attached to the Type-C port, so if
we do get boards which do HDMI and no DP, then the TCPM would simply
never use the MUX_TYPEC_HOST_AND_DP_SRC and MUX_TYPEC_DP_SRC states.

Regards,

Hans

[toc] | [prev] | [next] | [standalone]


#1726866 — [PATCH v2 08/11] staging: typec: tcpm: Set mux to device mode when configured as such

FromHans de Goede <hdegoede@redhat.com>
Date2017-09-05 18:50 +0200
Subject[PATCH v2 08/11] staging: typec: tcpm: Set mux to device mode when configured as such
Message-ID<umpd2-5fU-47@gated-at.bofh.it>
In reply to#1726854
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() to set the mux to
TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT so that it does not and up
staying in host (and with this commit also device) mode after a detach.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/staging/typec/tcpm.c |  7 ++++---
 drivers/staging/typec/tcpm.h | 22 ++++++++++++++--------
 2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c
index 8af62e74d54c..ffe7e26d4ed3 100644
--- a/drivers/staging/typec/tcpm.c
+++ b/drivers/staging/typec/tcpm.c
@@ -752,11 +752,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;
 
@@ -2025,6 +2025,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/drivers/staging/typec/tcpm.h b/drivers/staging/typec/tcpm.h
index 7e9a6b7b5cd6..f662eed48c86 100644
--- a/drivers/staging/typec/tcpm.h
+++ b/drivers/staging/typec/tcpm.h
@@ -83,17 +83,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.13.5

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web