Skip to contentSkip to conversation

usb: add support for Intel dual role port mux

PATCH Superseded Lu Baolu 4 participants 30 messages Mar 3, 2016 – Mar 4, 2016

Subsystems (4)

v1 of 10 Superseded Latest is v10 →

lore
Share & tools
lore

Lu Baolu

author
#0 lore raw

cover usb: add support for Intel dual role port mux

Intel SOC chips are featured with USB dual role. The host role is provided by Intel xHCI IP, and the gadget role is provided by IP from designware. Tablet platform designs always share a single port for both host and gadget controllers. There is a mux to switch the port to the right controller according to the cable type. OS needs to provide the callback to control the mux when a plug-in event raises. The method to control the mux is platform dependent. At least three types of implementation can be found across current devices. 1) GPIO pins; 2) a unit which can be controlled by memory mapped registers; 3) ACPI ASL code.

This patch series adds supports for Intel dual role port mux. It includes:
(1) A helper layer on top of extcon for individual mux driver. It listens to the USB-HOST extcon cable and call the switch call-back when the cable state changes.
(2) Drivers for GPIO controlled port mux which could be found on Baytrail devices. A mfd driver is used to split the GPIOs into USB gpio extcon device and a USB mux device. Driver for USB gpio extcon device is already in upstream Linux. This patch series includes a driver for GPIO USB mux.
(3) Drivers for USB port mux controlled through memory mapped registers and the logic to create the mux device. This type of dual role port mux could be found in Cherry Trail and Broxton devices.

Lu Baolu (7):
extcon: usb-gpio: add device binding for platform device
extcon: usb-gpio: add support for ACPI gpio interface
usb: misc: add common code for Intel dual role port mux
usb: misc: add driver for Intel gpio controlled port mux
usb: misc: add driver for Intel drcfg controlled port mux
usb: pci-quirks: add Intel USB drcfg mux device
mfd: intel_vuport: Add Intel virtual USB port MFD Driver

 MAINTAINERS                        |  10 +++
 drivers/extcon/extcon-usb-gpio.c   |  10 ++-
 drivers/mfd/Kconfig                |   7 ++
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/intel-vuport.c         |  79 +++++++++++++++++
 drivers/usb/host/pci-quirks.c      |  47 +++++++++-
 drivers/usb/host/xhci-ext-caps.h   |   2 +
 drivers/usb/misc/Kconfig           |  20 +++++
 drivers/usb/misc/Makefile          |   4 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 drivers/usb/misc/intel-mux-gpio.c  | 126 +++++++++++++++++++++++++++
 drivers/usb/misc/mux.c             | 172 ++++++++++++++++++++++++++++++++++++
 include/linux/usb/mux.h            |  71 +++++++++++++++
 13 files changed, 720 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mfd/intel-vuport.c
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
 create mode 100644 drivers/usb/misc/intel-mux-gpio.c
 create mode 100644 drivers/usb/misc/mux.c
 create mode 100644 include/linux/usb/mux.h
Signature · 1 line
2.1.4
author
#1 lore raw

PATCH 1/7 extcon: usb-gpio: add device binding for platform device

This is needed to handle the GPIO connected USB ID pin found on Intel Baytrail devices.

---
 drivers/extcon/extcon-usb-gpio.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/extcon/extcon-usb-gpio.c +7 -0
index 2b2fecf..af9c8b0 100644
@@ -206,6 +206,12 @@ static const struct of_device_id usb_extcon_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
 
+static const struct platform_device_id usb_extcon_platform_ids[] = {
+	{ .name = "extcon-usb-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids);
+
 static struct platform_driver usb_extcon_driver = {
 	.probe		= usb_extcon_probe,
 	.remove		= usb_extcon_remove,
@@ -214,6 +220,7 @@ static struct platform_driver usb_extcon_driver = {
 		.pm	= &usb_extcon_pm_ops,
 		.of_match_table = usb_extcon_dt_match,
 	},
+	.id_table = usb_extcon_platform_ids,
 };
 
 module_platform_driver(usb_extcon_driver);
Signature · 1 line
2.1.4
maintainer Acked-by on v1 1/7
#2 lore raw

Re: [PATCH 1/7] extcon: usb-gpio: add device binding for platform device

Hell Lu,

Quoted 28 lines · Lu Baolu

This is needed to handle the GPIO connected USB ID pin found on Intel Baytrail devices.

---
 drivers/extcon/extcon-usb-gpio.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/extcon/extcon-usb-gpio.c +6 -0
index 2b2fecf..af9c8b0 100644
@@ -206,6 +206,12 @@ static const struct of_device_id usb_extcon_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
 
+static const struct platform_device_id usb_extcon_platform_ids[] = {
+	{ .name = "extcon-usb-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids);
+
 static struct platform_driver usb_extcon_driver = {
 	.probe		= usb_extcon_probe,
 	.remove		= usb_extcon_remove,

drivers/extcon/extcon-usb-gpio.c static struct platform_driver usb_extcon_driver = { · line 226

Quoted 7 lines
drivers/extcon/extcon-usb-gpio.c +1 -0
@@ -214,6 +220,7 @@ static struct platform_driver usb_extcon_driver = {
 		.pm	= &usb_extcon_pm_ops,
 		.of_match_table = usb_extcon_dt_match,
 	},
+	.id_table = usb_extcon_platform_ids,
 };
 
 module_platform_driver(usb_extcon_driver);

Looks good to me.

Best Regards,
Chanwoo Choi

author
#3 lore raw

Re: [PATCH 1/7] extcon: usb-gpio: add device binding for platform device

Quoted 36 lines · Chanwoo Choi

Hell Lu,

Quoted 33 lines · Lu Baolu

This is needed to handle the GPIO connected USB ID pin found on Intel Baytrail devices.

---
 drivers/extcon/extcon-usb-gpio.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/extcon/extcon-usb-gpio.c +7 -0
index 2b2fecf..af9c8b0 100644
@@ -206,6 +206,12 @@ static const struct of_device_id usb_extcon_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, usb_extcon_dt_match);
 
+static const struct platform_device_id usb_extcon_platform_ids[] = {
+	{ .name = "extcon-usb-gpio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids);
+
 static struct platform_driver usb_extcon_driver = {
 	.probe		= usb_extcon_probe,
 	.remove		= usb_extcon_remove,
@@ -214,6 +220,7 @@ static struct platform_driver usb_extcon_driver = {
 		.pm	= &usb_extcon_pm_ops,
 		.of_match_table = usb_extcon_dt_match,
 	},
+	.id_table = usb_extcon_platform_ids,
 };
 
Quoted 5 lines

drivers/extcon/extcon-usb-gpio.c static struct platform_driver usb_extcon_driver = { · line 226

Quoted 2 lines
drivers/extcon/extcon-usb-gpio.c +0 -0
 module_platform_driver(usb_extcon_driver);

Looks good to me.

Thank you!

Quoted 5 lines

Best Regards,
Chanwoo Choi

author
#4 lore raw

PATCH 2/7 extcon: usb-gpio: add support for ACPI gpio interface

In reply to Lu Baolu

GPIO resource could be retrieved through APCI as well.

---
 drivers/extcon/extcon-usb-gpio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/extcon/extcon-usb-gpio.c +2 -1
index af9c8b0..472c431 100644
@@ -26,6 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/acpi.h>
 
 #define USB_GPIO_DEBOUNCE_MS	20	/* ms */
 
@@ -91,7 +92,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
 	struct usb_extcon_info *info;
 	int ret;
 
-	if (!np)
+	if (!np && !ACPI_HANDLE(dev))
 		return -EINVAL;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
Signature · 1 line
2.1.4
maintainer Acked-by on v1 2/7
#5 lore raw

Re: [PATCH 2/7] extcon: usb-gpio: add support for ACPI gpio interface

Hi Lu,

Quoted 22 lines · Lu Baolu

GPIO resource could be retrieved through APCI as well.

---
 drivers/extcon/extcon-usb-gpio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/extcon/extcon-usb-gpio.c +1 -0
index af9c8b0..472c431 100644
@@ -26,6 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/acpi.h>
 
 #define USB_GPIO_DEBOUNCE_MS	20	/* ms */
 

drivers/extcon/extcon-usb-gpio.c static int usb_extcon_probe(struct platform_device *pdev) · line 98

Quoted 8 lines
drivers/extcon/extcon-usb-gpio.c +1 -1
@@ -91,7 +92,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
 	struct usb_extcon_info *info;
 	int ret;
 
-	if (!np)
+	if (!np && !ACPI_HANDLE(dev))
 		return -EINVAL;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);

Looks good to me.

Best Regards,
Chanwoo Choi

author
#6 lore raw

Re: [PATCH 2/7] extcon: usb-gpio: add support for ACPI gpio interface

Quoted 31 lines · Chanwoo Choi

Hi Lu,

Quoted 28 lines · Lu Baolu

GPIO resource could be retrieved through APCI as well.

---
 drivers/extcon/extcon-usb-gpio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/extcon/extcon-usb-gpio.c +2 -1
index af9c8b0..472c431 100644
@@ -26,6 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/acpi.h>
 
 #define USB_GPIO_DEBOUNCE_MS	20	/* ms */
 
@@ -91,7 +92,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
 	struct usb_extcon_info *info;
 	int ret;
 
-	if (!np)
+	if (!np && !ACPI_HANDLE(dev))
 		return -EINVAL;
 
Quoted 5 lines

drivers/extcon/extcon-usb-gpio.c static int usb_extcon_probe(struct platform_device *pdev) · line 98

Quoted 2 lines
drivers/extcon/extcon-usb-gpio.c +0 -0
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);

Looks good to me.

Thank you!

Quoted 4 lines

Best Regards,
Chanwoo Choi

author
#7 lore raw

PATCH 3/7 usb: misc: add common code for Intel dual role port mux

In reply to Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller.

A usb port mux could be abstracted as the following elements:
1) mux state: HOST or PERIPHERAL;
2) an extcon cable which triggers the change of mux state between HOST and PERIPHERAL;
3) The required action to do the real port switch.

This patch adds the common code to handle usb port mux. With this common code, the individual mux driver, which always is platform dependent, could focus on the real operation of mux switch.

---
 MAINTAINERS               |   7 ++
 drivers/usb/misc/Kconfig  |   4 ++
 drivers/usb/misc/Makefile |   2 +
 drivers/usb/misc/mux.c    | 172 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/mux.h   |  71 +++++++++++++++++++
 5 files changed, 256 insertions(+)
 create mode 100644 drivers/usb/misc/mux.c
 create mode 100644 include/linux/usb/mux.h
MAINTAINERS +7 -0
index d894ee2..45f1e1e 100644
@@ -11389,6 +11389,13 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:	Maintained
 F:	drivers/usb/phy/
 
+USB PORT MUX DRIVER
+M:	Lu Baolu <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/usb/misc/mux.c
+F:	include/linux/usb/mux.h
+
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
 L:	[email protected]
drivers/usb/misc/Kconfig +4 -0
index f7a7fc2..6496d17 100644
@@ -3,6 +3,10 @@
 #
 comment "USB Miscellaneous drivers"
 
+config USB_MUX
+	select EXTCON
+	def_bool n
+
 config USB_EMI62
 	tristate "EMI 6|2m USB Audio interface support"
 	---help---
drivers/usb/misc/Makefile +2 -0
index 45fd4ac..fd79dd5 100644
@@ -29,3 +29,5 @@ obj-$(CONFIG_USB_CHAOSKEY)		+= chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
+
+obj-$(CONFIG_USB_MUX)			+= mux.o
drivers/usb/misc/mux.c new file +172 -0

172 lines not on this page · raw message

include/linux/usb/mux.h new file +71 -0

71 lines not on this page · raw message

Signature · 1 line
2.1.4
#8 lore raw

Re: [PATCH 3/7] usb: misc: add common code for Intel dual role port mux

Quoted 64 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller.

A usb port mux could be abstracted as the following elements:
1) mux state: HOST or PERIPHERAL;
2) an extcon cable which triggers the change of mux state between HOST and PERIPHERAL;
3) The required action to do the real port switch.

This patch adds the common code to handle usb port mux. With this common code, the individual mux driver, which always is platform dependent, could focus on the real operation of mux switch.

---
 MAINTAINERS               |   7 ++
 drivers/usb/misc/Kconfig  |   4 ++
 drivers/usb/misc/Makefile |   2 +
 drivers/usb/misc/mux.c    | 172 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/mux.h   |  71 +++++++++++++++++++
 5 files changed, 256 insertions(+)
 create mode 100644 drivers/usb/misc/mux.c
 create mode 100644 include/linux/usb/mux.h
MAINTAINERS +7 -0
index d894ee2..45f1e1e 100644
@@ -11389,6 +11389,13 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:	Maintained
 F:	drivers/usb/phy/
 
+USB PORT MUX DRIVER
+M:	Lu Baolu <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/usb/misc/mux.c
+F:	include/linux/usb/mux.h
+
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
 L:	[email protected]
drivers/usb/misc/Kconfig +4 -0
index f7a7fc2..6496d17 100644
@@ -3,6 +3,10 @@
 #
 comment "USB Miscellaneous drivers"
 
+config USB_MUX
+	select EXTCON
+	def_bool n
+
 config USB_EMI62
 	tristate "EMI 6|2m USB Audio interface support"
 	---help---
drivers/usb/misc/Makefile +0 -0
index 45fd4ac..fd79dd5 100644

drivers/usb/misc/Makefile obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o · line 33

Quoted 5 lines
drivers/usb/misc/Makefile +2 -0
@@ -29,3 +29,5 @@ obj-$(CONFIG_USB_CHAOSKEY)		+= chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
+
+obj-$(CONFIG_USB_MUX)			+= mux.o

"mux.ko" is a _VERY_ generic name of a kernel module. Please make this much more specific to your chip as this will not work for any other platform that has this type of functionality.

Same goes for all of your exported symbols.

Quoted 132 lines
drivers/usb/misc/mux.c new file +126 -0
new file mode 100644
index 0000000..e353fff
@@ -0,0 +1,172 @@
+/**
+ * mux.c - USB Port Mux support
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/notifier.h>
+#include <linux/usb/mux.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+
+static int usb_mux_change_state(struct usb_mux *mux, int state)
+{
+	int ret;
+	struct usb_mux_dev *umdev = mux->umdev;
+
+	dev_WARN_ONCE(umdev->dev, !mutex_is_locked(&mux->mux_mutex),
+			"mutex is unlocked\n");
+
+	mux->mux_state = state;
+
+	if (mux->mux_state)
+		ret = umdev->cable_set_cb(umdev);
+	else
+		ret = umdev->cable_unset_cb(umdev);
+
+	return ret;
+}
+
+static int usb_mux_notifier(struct notifier_block *nb,
+		unsigned long event, void *ptr)
+{
+	struct usb_mux *mux;
+	int state;
+	int ret = NOTIFY_DONE;
+
+	mux = container_of(nb, struct usb_mux, nb);
+
+	state = extcon_get_cable_state(mux->obj.edev,
+			mux->umdev->cable_name);
+
+	if (mux->mux_state == -1 || mux->mux_state != state) {
+		mutex_lock(&mux->mux_mutex);
+		ret = usb_mux_change_state(mux, state);
+		mutex_unlock(&mux->mux_mutex);
+	}
+
+	return ret;
+}
+
+static ssize_t mux_debug_read(struct file *file, char __user *user_buf,
+		size_t len, loff_t *offset)
+{
+	struct usb_mux *mux = file->private_data;
+	char output_buf[16];
+
+	memset(output_buf, 0, sizeof(output_buf));
+	if (mux->mux_state)
+		strcpy(output_buf, "host\n");
+	else
+		strcpy(output_buf, "peripheral\n");
+
+	return simple_read_from_buffer(user_buf, len, offset,
+			output_buf, strlen(output_buf));
+}
+
+static ssize_t mux_debug_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *offset)
+{
+	struct usb_mux *mux = file->private_data;
+	char input_buf[16];
+	int size, state;
+
+	size = min(count, sizeof(input_buf) - 1);
+	memset(input_buf, 0, sizeof(input_buf));
+	if (strncpy_from_user(input_buf, user_buf, size) < 0)
+		return -EFAULT;
+
+	if (!strncmp(input_buf, "host", 4))
+		state = 1;
+	else if (!strncmp(input_buf, "peripheral", 10))
+		state = 0;
+	else
+		state = -1;
+
+	if (state != -1) {
+		mutex_lock(&mux->mux_mutex);
+		usb_mux_change_state(mux, state);
+		mutex_unlock(&mux->mux_mutex);
+	}
+
+	return count;
+}
+
+static const struct file_operations mux_debug_fops = {
+	.read =		mux_debug_read,
+	.write =	mux_debug_write,
+	.open =		simple_open,
+	.llseek =	default_llseek,
+};
+
+int usb_mux_register(struct usb_mux_dev *umdev)
+{
+	int ret;
+	struct device *dev = umdev->dev;
+	struct usb_mux *mux;
+
+	if (!umdev->cable_name)
+		return -ENODEV;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	mux->umdev = umdev;
+	mux->nb.notifier_call = usb_mux_notifier;
+	mutex_init(&mux->mux_mutex);
+	mux->mux_state = -1;
+	dev_set_drvdata(dev, mux);
+
+	ret = extcon_register_interest(&mux->obj, umdev->extcon_name,

drivers/usb/misc/mux.c line 136

Quoted 10 lines
drivers/usb/misc/mux.c new file +10 -0
+			umdev->cable_name, &mux->nb);
+	if (ret) {
+		dev_err(dev, "failed to register extcon notifier\n");
+		return -ENODEV;
+	}
+
+	usb_mux_notifier(&mux->nb, 0, NULL);
+
+	mux->debug_file = debugfs_create_file("usb_mux", 0600,
+			usb_debug_root, mux, &mux_debug_fops);

So you control this through debugfs? That's not a good idea, what if you have multiple ones of these? What if debugfs is not enabled? Who is in charge of controlling this from userspace?

Quoted 75 lines
drivers/usb/misc/mux.c new file +36 -0
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_mux_register);
+
+int usb_mux_unregister(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	debugfs_remove(mux->debug_file);
+	extcon_unregister_interest(&mux->obj);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_mux_unregister);
+
+struct usb_mux_dev *usb_mux_get_dev(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	if (mux)
+		return mux->umdev;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_mux_get_dev);
+
+#ifdef CONFIG_PM_SLEEP
+void usb_mux_complete(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	usb_mux_notifier(&mux->nb, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_mux_complete);
+#endif
include/linux/usb/mux.h new file +33 -0
new file mode 100644
index 0000000..5dada48
@@ -0,0 +1,71 @@
+/**
+ * mux.h - USB Port Mux defines
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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_USB_MUX_H
+#define __LINUX_USB_MUX_H
+
+#include <linux/extcon.h>
+#include <linux/usb.h>
+
+struct usb_mux_dev {
+	struct device	*dev;
+	char		*extcon_name;
+	char		*cable_name;
+	int		(*cable_set_cb)(struct usb_mux_dev *mux);
+	int		(*cable_unset_cb)(struct usb_mux_dev *mux);
+};
+
+struct usb_mux {
+	struct usb_mux_dev		*umdev;
+	struct notifier_block		nb;
+	struct extcon_specific_cable_nb	obj;
+
+	/*
+	 * The state of the mux.

include/linux/usb/mux.h line 43

Quoted 10 lines
include/linux/usb/mux.h new file +10 -0
+	 * 0, 1 - mux switch state
+	 * -1   - uninitialized state
+	 *
+	 * mux_mutex is lock to protect mux_state
+	 */
+	int				mux_state;
+	struct mutex			mux_mutex;
+
+	struct dentry			*debug_file;
+};

Why is this a public structure?

And why isn't it properly reference counted if it is a public structure?

Quoted 18 lines
include/linux/usb/mux.h new file +18 -0
+
+#if IS_ENABLED(CONFIG_USB_MUX)
+extern int usb_mux_register(struct usb_mux_dev *mux);
+extern int usb_mux_unregister(struct device *dev);
+extern struct usb_mux_dev *usb_mux_get_dev(struct device *dev);
+
+#ifdef CONFIG_PM_SLEEP
+extern void usb_mux_complete(struct device *dev);
+#endif
+
+#else /* CONFIG_USB_MUX */
+static inline int usb_mux_register(struct usb_mux_dev *mux)
+{
+	return -ENODEV;
+}
+
+static inline int usb_mux_unregister(struct device *dev)
+{

include/linux/usb/mux.h line 71

Quoted 10 lines
include/linux/usb/mux.h new file +10 -0
+	return 0;
+}
+
+static inline struct usb_mux_dev *usb_mux_get_dev(struct device *dev)
+{
+	return NULL;
+}
+#endif /* CONFIG_USB_MUX */
+
+#endif /* __LINUX_USB_MUX_H */

Why do you need this .h file at all?

thanks,

greg k-h

author
#9 lore raw

Re: [PATCH 3/7] usb: misc: add common code for Intel dual role port mux

Quoted 74 lines · Greg Kroah-Hartman
Quoted 64 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller.

A usb port mux could be abstracted as the following elements:
1) mux state: HOST or PERIPHERAL;
2) an extcon cable which triggers the change of mux state between HOST and PERIPHERAL;
3) The required action to do the real port switch.

This patch adds the common code to handle usb port mux. With this common code, the individual mux driver, which always is platform dependent, could focus on the real operation of mux switch.

---
 MAINTAINERS               |   7 ++
 drivers/usb/misc/Kconfig  |   4 ++
 drivers/usb/misc/Makefile |   2 +
 drivers/usb/misc/mux.c    | 172 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/mux.h   |  71 +++++++++++++++++++
 5 files changed, 256 insertions(+)
 create mode 100644 drivers/usb/misc/mux.c
 create mode 100644 include/linux/usb/mux.h
MAINTAINERS +7 -0
index d894ee2..45f1e1e 100644
@@ -11389,6 +11389,13 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:	Maintained
 F:	drivers/usb/phy/
 
+USB PORT MUX DRIVER
+M:	Lu Baolu <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/usb/misc/mux.c
+F:	include/linux/usb/mux.h
+
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
 L:	[email protected]
drivers/usb/misc/Kconfig +4 -0
index f7a7fc2..6496d17 100644
@@ -3,6 +3,10 @@
 #
 comment "USB Miscellaneous drivers"
 
+config USB_MUX
+	select EXTCON
+	def_bool n
+
 config USB_EMI62
 	tristate "EMI 6|2m USB Audio interface support"
 	---help---
drivers/usb/misc/Makefile +0 -0
index 45fd4ac..fd79dd5 100644

drivers/usb/misc/Makefile obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o · line 33

Quoted 5 lines
drivers/usb/misc/Makefile +2 -0
@@ -29,3 +29,5 @@ obj-$(CONFIG_USB_CHAOSKEY)		+= chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
+
+obj-$(CONFIG_USB_MUX)			+= mux.o

"mux.ko" is a _VERY_ generic name of a kernel module. Please make this much more specific to your chip as this will not work for any other platform that has this type of functionality.

Quoted 1 line

Same goes for all of your exported symbols.

Sure. I will change the module name to "intel-mux", and change the exported symbols to "intel_usb_mux_*".

Quoted 138 lines
Quoted 138 lines
drivers/usb/misc/mux.c new file +130 -0
new file mode 100644
index 0000000..e353fff
@@ -0,0 +1,172 @@
+/**
+ * mux.c - USB Port Mux support
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/notifier.h>
+#include <linux/usb/mux.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+
+static int usb_mux_change_state(struct usb_mux *mux, int state)
+{
+	int ret;
+	struct usb_mux_dev *umdev = mux->umdev;
+
+	dev_WARN_ONCE(umdev->dev, !mutex_is_locked(&mux->mux_mutex),
+			"mutex is unlocked\n");
+
+	mux->mux_state = state;
+
+	if (mux->mux_state)
+		ret = umdev->cable_set_cb(umdev);
+	else
+		ret = umdev->cable_unset_cb(umdev);
+
+	return ret;
+}
+
+static int usb_mux_notifier(struct notifier_block *nb,
+		unsigned long event, void *ptr)
+{
+	struct usb_mux *mux;
+	int state;
+	int ret = NOTIFY_DONE;
+
+	mux = container_of(nb, struct usb_mux, nb);
+
+	state = extcon_get_cable_state(mux->obj.edev,
+			mux->umdev->cable_name);
+
+	if (mux->mux_state == -1 || mux->mux_state != state) {
+		mutex_lock(&mux->mux_mutex);
+		ret = usb_mux_change_state(mux, state);
+		mutex_unlock(&mux->mux_mutex);
+	}
+
+	return ret;
+}
+
+static ssize_t mux_debug_read(struct file *file, char __user *user_buf,
+		size_t len, loff_t *offset)
+{
+	struct usb_mux *mux = file->private_data;
+	char output_buf[16];
+
+	memset(output_buf, 0, sizeof(output_buf));
+	if (mux->mux_state)
+		strcpy(output_buf, "host\n");
+	else
+		strcpy(output_buf, "peripheral\n");
+
+	return simple_read_from_buffer(user_buf, len, offset,
+			output_buf, strlen(output_buf));
+}
+
+static ssize_t mux_debug_write(struct file *file, const char __user *user_buf,
+		size_t count, loff_t *offset)
+{
+	struct usb_mux *mux = file->private_data;
+	char input_buf[16];
+	int size, state;
+
+	size = min(count, sizeof(input_buf) - 1);
+	memset(input_buf, 0, sizeof(input_buf));
+	if (strncpy_from_user(input_buf, user_buf, size) < 0)
+		return -EFAULT;
+
+	if (!strncmp(input_buf, "host", 4))
+		state = 1;
+	else if (!strncmp(input_buf, "peripheral", 10))
+		state = 0;
+	else
+		state = -1;
+
+	if (state != -1) {
+		mutex_lock(&mux->mux_mutex);
+		usb_mux_change_state(mux, state);
+		mutex_unlock(&mux->mux_mutex);
+	}
+
+	return count;
+}
+
+static const struct file_operations mux_debug_fops = {
+	.read =		mux_debug_read,
+	.write =	mux_debug_write,
+	.open =		simple_open,
+	.llseek =	default_llseek,
+};
+
+int usb_mux_register(struct usb_mux_dev *umdev)
+{
+	int ret;
+	struct device *dev = umdev->dev;
+	struct usb_mux *mux;
+
+	if (!umdev->cable_name)
+		return -ENODEV;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	mux->umdev = umdev;
+	mux->nb.notifier_call = usb_mux_notifier;
+	mutex_init(&mux->mux_mutex);
+	mux->mux_state = -1;
+	dev_set_drvdata(dev, mux);
+
+	ret = extcon_register_interest(&mux->obj, umdev->extcon_name,
+			umdev->cable_name, &mux->nb);
+	if (ret) {
+		dev_err(dev, "failed to register extcon notifier\n");
+		return -ENODEV;
Quoted 8 lines

drivers/usb/misc/mux.c line 136

Quoted 6 lines
drivers/usb/misc/mux.c new file +6 -0
+	}
+
+	usb_mux_notifier(&mux->nb, 0, NULL);
+
+	mux->debug_file = debugfs_create_file("usb_mux", 0600,
+			usb_debug_root, mux, &mux_debug_fops);

So you control this through debugfs? That's not a good idea, what if you have multiple ones of these? What if debugfs is not enabled?

Agree. It's really a problem if we have multiple ones (although currently we have only single one).

I will make it with sysfs instead.

Quoted 2 lines

Who
is in charge of controlling this from userspace?

Port mux is only handled in kernel. There is no requirement to control it from user space. This is added for debugging and information only.

Quoted 89 lines
Quoted 76 lines
drivers/usb/misc/mux.c new file +36 -0
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_mux_register);
+
+int usb_mux_unregister(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	debugfs_remove(mux->debug_file);
+	extcon_unregister_interest(&mux->obj);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_mux_unregister);
+
+struct usb_mux_dev *usb_mux_get_dev(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	if (mux)
+		return mux->umdev;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_mux_get_dev);
+
+#ifdef CONFIG_PM_SLEEP
+void usb_mux_complete(struct device *dev)
+{
+	struct usb_mux *mux = dev_get_drvdata(dev);
+
+	usb_mux_notifier(&mux->nb, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_mux_complete);
+#endif
include/linux/usb/mux.h new file +33 -0
new file mode 100644
index 0000000..5dada48
@@ -0,0 +1,71 @@
+/**
+ * mux.h - USB Port Mux defines
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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_USB_MUX_H
+#define __LINUX_USB_MUX_H
+
+#include <linux/extcon.h>
+#include <linux/usb.h>
+
+struct usb_mux_dev {
+	struct device	*dev;
+	char		*extcon_name;
+	char		*cable_name;
+	int		(*cable_set_cb)(struct usb_mux_dev *mux);
+	int		(*cable_unset_cb)(struct usb_mux_dev *mux);
+};
+
+struct usb_mux {
+	struct usb_mux_dev		*umdev;
+	struct notifier_block		nb;
+	struct extcon_specific_cable_nb	obj;
+
+	/*
+	 * The state of the mux.

include/linux/usb/mux.h line 43

Quoted 10 lines
include/linux/usb/mux.h new file +10 -0
+	 * 0, 1 - mux switch state
+	 * -1   - uninitialized state
+	 *
+	 * mux_mutex is lock to protect mux_state
+	 */
+	int				mux_state;
+	struct mutex			mux_mutex;
+
+	struct dentry			*debug_file;
+};

Why is this a public structure?

Quoted 1 line

And why isn't it properly reference counted if it is a public structure?

Agree. I will move it to .c file and make it private one.

Quoted 24 lines
Quoted 24 lines
include/linux/usb/mux.h new file +22 -0
+
+#if IS_ENABLED(CONFIG_USB_MUX)
+extern int usb_mux_register(struct usb_mux_dev *mux);
+extern int usb_mux_unregister(struct device *dev);
+extern struct usb_mux_dev *usb_mux_get_dev(struct device *dev);
+
+#ifdef CONFIG_PM_SLEEP
+extern void usb_mux_complete(struct device *dev);
+#endif
+
+#else /* CONFIG_USB_MUX */
+static inline int usb_mux_register(struct usb_mux_dev *mux)
+{
+	return -ENODEV;
+}
+
+static inline int usb_mux_unregister(struct device *dev)
+{
+	return 0;
+}
+
+static inline struct usb_mux_dev *usb_mux_get_dev(struct device *dev)
Quoted 8 lines

include/linux/usb/mux.h line 71

Quoted 6 lines
include/linux/usb/mux.h new file +6 -0
+{
+	return NULL;
+}
+#endif /* CONFIG_USB_MUX */
+
+#endif /* __LINUX_USB_MUX_H */

Why do you need this .h file at all?

File mux.c is a common file for all port mux drivers. The individual port mux driver needs this .h file for structure and function interface definition.

Quoted 5 lines

thanks,

greg k-h

Thank you for your time.

Best Regards,
-Baolu

#10 lore raw

Re: [PATCH 3/7] usb: misc: add common code for Intel dual role port mux

In reply to Lu Baolu

include/linux/usb/mux.h line 48

Quoted 4 lines · Lu Baolu
include/linux/usb/mux.h new file +4 -0
+#if IS_ENABLED(CONFIG_USB_MUX)
+extern int usb_mux_register(struct usb_mux_dev *mux);
+extern int usb_mux_unregister(struct device *dev);
+extern struct usb_mux_dev *usb_mux_get_dev(struct device *dev);

This api needs a lot of work, for such a "tiny" api, it's obviously pretty incorrect. Please fix it up to be sane...

author
#11 lore raw

Re: [PATCH 3/7] usb: misc: add common code for Intel dual role port mux

Quoted 7 lines · Greg Kroah-Hartman

include/linux/usb/mux.h line 48

Quoted 4 lines · Lu Baolu
include/linux/usb/mux.h new file +4 -0
+#if IS_ENABLED(CONFIG_USB_MUX)
+extern int usb_mux_register(struct usb_mux_dev *mux);
+extern int usb_mux_unregister(struct device *dev);
+extern struct usb_mux_dev *usb_mux_get_dev(struct device *dev);

This api needs a lot of work, for such a "tiny" api, it's obviously pretty incorrect. Please fix it up to be sane...

Sure.

Quoted 3 lines
author
#12 lore raw

PATCH 4/7 usb: misc: add driver for Intel gpio controlled port mux

In reply to Lu Baolu

In some Intel platforms, a single usb port is shared between USB host and device controller. The shared port is under control of GPIO pins.

This patch adds the support for USB GPIO controlled port mux.

---
 MAINTAINERS                       |   1 +
 drivers/usb/misc/Kconfig          |   9 +++
 drivers/usb/misc/Makefile         |   1 +
 drivers/usb/misc/intel-mux-gpio.c | 126 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-gpio.c
MAINTAINERS +1 -0
index 45f1e1e..0f321e4 100644
@@ -11395,6 +11395,7 @@ L:	[email protected]
 S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
+F:	drivers/usb/misc/intel-mux-gpio.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +9 -0
index 6496d17..33e6386 100644
@@ -272,3 +272,12 @@ config USB_CHAOSKEY
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called chaoskey.
+
+config INTEL_MUX_GPIO
+	tristate "Intel dual role port mux controlled by GPIOs"
+	depends on GPIOLIB
+	depends on ACPI
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by GPIOs.
drivers/usb/misc/Makefile +1 -0
index fd79dd5..da4fb4e 100644
@@ -31,3 +31,4 @@ obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
+obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
drivers/usb/misc/intel-mux-gpio.c new file +126 -0

126 lines not on this page · raw message

Signature · 1 line
2.1.4
#13 lore raw

Re: [PATCH 4/7] usb: misc: add driver for Intel gpio controlled port mux

coccinelle warnings: (new ones prefixed by >>)

Hi Lu,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing

coccinelle warnings: (new ones prefixed by >>)

>> drivers/usb/misc/intel-mux-gpio.c:111:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#14 lore raw

[PATCH] usb: misc: fix platform_no_drv_owner.cocci warnings

In reply to Lu Baolu
drivers/usb/misc/intel-mux-gpio.c:111:3-8: No need to set .owner here. The core will do it.

drivers/usb/misc/intel-mux-gpio.c:111:3-8: No need to set .owner here. The core will do it.

Remove .owner field if calls are used which set it automatically

Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci

---

 intel-mux-gpio.c |    1 -
 1 file changed, 1 deletion(-)
drivers/usb/misc/intel-mux-gpio.c +0 -1
@@ -108,7 +108,6 @@ MODULE_DEVICE_TABLE(platform, vuport_pla
 static struct platform_driver vuport_driver = {
 	.driver = {
 		.name = "intel-mux-gpio",
-		.owner = THIS_MODULE,
 #ifdef CONFIG_PM_SLEEP
 		.pm = &vuport_pm_ops,
 #endif
author
#15 lore raw

PATCH 5/7 usb: misc: add driver for Intel drcfg controlled port mux

In reply to Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
MAINTAINERS +1 -0
index 0f321e4..20eb873 100644
@@ -11396,6 +11396,7 @@ S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
+F:	drivers/usb/misc/intel-mux-drcfg.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +7 -0
index 33e6386..befd910 100644
@@ -281,3 +281,10 @@ config INTEL_MUX_GPIO
 	help
 	  Say Y here to enable support for Intel dual role port mux
 	  controlled by GPIOs.
+
+config INTEL_MUX_DRCFG
+	tristate "Intel dual role port mux controlled by register"
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by the Dual Role Configuration Registers.
drivers/usb/misc/Makefile +1 -0
index da4fb4e..c4d19a0 100644
@@ -32,3 +32,4 @@ obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
 obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
+obj-$(CONFIG_INTEL_MUX_DRCFG)		+= intel-mux-drcfg.o
drivers/usb/misc/intel-mux-drcfg.c new file +174 -0

174 lines not on this page · raw message

Signature · 1 line
2.1.4
#16 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree…

Hi Lu,

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: arm64-allyesconfig (attached as .config)

reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64

All error/warnings (new ones prefixed by >>):

drivers/usb/misc/intel-mux-drcfg.c: In function 'intel_mux_drcfg_switch':

>> drivers/usb/misc/intel-mux-drcfg.c:42:2: error: implicit declaration of function 'readl' [-Werror=implicit-function-declaration]
     data = readl(mux->regs + INTEL_MUX_CFG0);
     ^
>> drivers/usb/misc/intel-mux-drcfg.c:45:3: error: implicit declaration of function 'writel' [-Werror=implicit-function-declaration]
      writel(data, mux->regs + INTEL_MUX_CFG0);
      ^
   drivers/usb/misc/intel-mux-drcfg.c: In function 'intel_mux_drcfg_probe':
>> drivers/usb/misc/intel-mux-drcfg.c:108:2: error: implicit declaration of function 'devm_ioremap_nocache' [-Werror=implicit-function-declaration]
     mux->regs = devm_ioremap_nocache(dev, start, size);
     ^
>> drivers/usb/misc/intel-mux-drcfg.c:108:12: warning: assignment makes pointer from integer without a cast
     mux->regs = devm_ioremap_nocache(dev, start, size);
               ^

cc1: some warnings being treated as errors

vim +/readl +42 drivers/usb/misc/intel-mux-drcfg.c

    36		unsigned long timeout;
    37		u32 data;
    38	
    39		mux = container_of(umdev, struct intel_usb_mux, umdev);
    40	
    41		/* Check and set mux to SW controlled mode */
  > 42		data = readl(mux->regs + INTEL_MUX_CFG0);
    43		if (!(data & CFG0_SW_IDPIN_EN)) {
    44			data |= CFG0_SW_IDPIN_EN;
  > 45			writel(data, mux->regs + INTEL_MUX_CFG0);
    46		}
    47	
    48		/*
    49		 * Configure CFG0 to switch the mux and VBUS_VALID bit is
    50		 * required for device mode.
    51		 */
    52		data = readl(mux->regs + INTEL_MUX_CFG0);
    53		if (host)
    54			data &= ~(CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
    55		else
    56			data |= (CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
    57		writel(data, mux->regs + INTEL_MUX_CFG0);
    58	
    59		/*
    60		 * Polling CFG1 for safety, most case it takes about 600ms
    61		 * to finish mode switching, set TIMEOUT long enough.
    62		 */
    63		timeout = jiffies + msecs_to_jiffies(CFG1_POLL_TIMEOUT);
    64	
    65		/* Polling on CFG1 register to confirm mode switch. */
    66		while (!time_after(jiffies, timeout)) {
    67			data = readl(mux->regs + INTEL_MUX_CFG1);
    68			if (!(host ^ (data & CFG1_SW_MODE)))
    69				return 0;
    70			/* interval for polling is set to about 5ms */
    71			usleep_range(5000, 5100);
    72		}
    73	
    74		return -ETIMEDOUT;
    75	}
    76	
    77	static int intel_mux_drcfg_cable_set(struct usb_mux_dev *umdev)
    78	{
    79		dev_dbg(umdev->dev, "drcfg mux switch to HOST\n");
    80	
    81		return intel_mux_drcfg_switch(umdev, true);
    82	}
    83	
    84	static int intel_mux_drcfg_cable_unset(struct usb_mux_dev *umdev)
    85	{
    86		dev_dbg(umdev->dev, "drcfg mux switch to DEVICE\n");
    87	
    88		return intel_mux_drcfg_switch(umdev, false);
    89	}
    90	
    91	static int intel_mux_drcfg_probe(struct platform_device *pdev)
    92	{
    93		struct intel_usb_mux *mux;
    94		struct usb_mux_dev *umdev;
    95		struct device *dev = &pdev->dev;
    96		u64 start, size;
    97		int ret;
    98	
    99		mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
   100		if (!mux)
   101			return -ENOMEM;
   102	
   103		ret = device_property_read_u64(dev, "reg-start", &start);
   104		ret |= device_property_read_u64(dev, "reg-size", &size);
   105		if (ret)
   106			return -ENODEV;
   107	
 > 108		mux->regs = devm_ioremap_nocache(dev, start, size);

109 if (!mux->regs)
110 return -ENOMEM;
111

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#17 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

In reply to Lu Baolu
Quoted 8 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

Quoted 5 lines
---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++

If you are going to start having a bunch of these, please make a new directory, drivers/usb/mux/ ?

author
#18 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

Quoted 14 lines · Greg Kroah-Hartman
Quoted 8 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

Quoted 5 lines
---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
Quoted 2 lines

If you are going to start having a bunch of these, please make a new directory, drivers/usb/mux/ ?

Sure. I can put them in drivers/usb/mux.

#19 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

In reply to Lu Baolu
Quoted 154 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
MAINTAINERS +1 -0
index 0f321e4..20eb873 100644
@@ -11396,6 +11396,7 @@ S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
+F:	drivers/usb/misc/intel-mux-drcfg.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +7 -0
index 33e6386..befd910 100644
@@ -281,3 +281,10 @@ config INTEL_MUX_GPIO
 	help
 	  Say Y here to enable support for Intel dual role port mux
 	  controlled by GPIOs.
+
+config INTEL_MUX_DRCFG
+	tristate "Intel dual role port mux controlled by register"
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by the Dual Role Configuration Registers.
drivers/usb/misc/Makefile +1 -0
index da4fb4e..c4d19a0 100644
@@ -32,3 +32,4 @@ obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
 obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
+obj-$(CONFIG_INTEL_MUX_DRCFG)		+= intel-mux-drcfg.o
drivers/usb/misc/intel-mux-drcfg.c new file +96 -0
new file mode 100644
index 0000000..29081c5
@@ -0,0 +1,174 @@
+/**
+ * intel-mux-drcfg.c - Driver for Intel USB mux via register
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Heikki Krogerus <[email protected]>
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/usb/mux.h>
+#include <linux/platform_device.h>
+
+#define INTEL_MUX_CFG0		0x00
+#define INTEL_MUX_CFG1		0x04
+#define CFG0_SW_IDPIN		BIT(20)
+#define CFG0_SW_IDPIN_EN	BIT(21)
+#define CFG0_SW_VBUS_VALID	BIT(24)
+#define CFG1_SW_MODE		BIT(29)
+#define CFG1_POLL_TIMEOUT	1000
+
+struct intel_usb_mux {
+	struct usb_mux_dev umdev;
+	void __iomem *regs;
+	u32 cfg0_ctx;
+};
+
+static inline int intel_mux_drcfg_switch(struct usb_mux_dev *umdev, bool host)
+{
+	struct intel_usb_mux *mux;
+	unsigned long timeout;
+	u32 data;
+
+	mux = container_of(umdev, struct intel_usb_mux, umdev);
+
+	/* Check and set mux to SW controlled mode */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (!(data & CFG0_SW_IDPIN_EN)) {
+		data |= CFG0_SW_IDPIN_EN;
+		writel(data, mux->regs + INTEL_MUX_CFG0);
+	}
+
+	/*
+	 * Configure CFG0 to switch the mux and VBUS_VALID bit is
+	 * required for device mode.
+	 */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (host)
+		data &= ~(CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	else
+		data |= (CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	writel(data, mux->regs + INTEL_MUX_CFG0);
+
+	/*
+	 * Polling CFG1 for safety, most case it takes about 600ms
+	 * to finish mode switching, set TIMEOUT long enough.
+	 */
+	timeout = jiffies + msecs_to_jiffies(CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch. */
+	while (!time_after(jiffies, timeout)) {
+		data = readl(mux->regs + INTEL_MUX_CFG1);
+		if (!(host ^ (data & CFG1_SW_MODE)))
+			return 0;
+		/* interval for polling is set to about 5ms */
+		usleep_range(5000, 5100);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_mux_drcfg_cable_set(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to HOST\n");
+
+	return intel_mux_drcfg_switch(umdev, true);
+}
+
+static int intel_mux_drcfg_cable_unset(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to DEVICE\n");
+
+	return intel_mux_drcfg_switch(umdev, false);
+}
+
+static int intel_mux_drcfg_probe(struct platform_device *pdev)
+{
+	struct intel_usb_mux *mux;
+	struct usb_mux_dev *umdev;
+	struct device *dev = &pdev->dev;
+	u64 start, size;

drivers/usb/misc/intel-mux-drcfg.c line 106

Quoted 10 lines
drivers/usb/misc/intel-mux-drcfg.c new file +10 -0
+	int ret;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return -ENOMEM;
+
+	ret = device_property_read_u64(dev, "reg-start", &start);
+	ret |= device_property_read_u64(dev, "reg-size", &size);
+	if (ret)
+		return -ENODEV;

And you leaked memory :(

drivers/usb/misc/intel-mux-drcfg.c line 110

Quoted 4 lines
drivers/usb/misc/intel-mux-drcfg.c new file +4 -0
+
+	mux->regs = devm_ioremap_nocache(dev, start, size);
+	if (!mux->regs)
+		return -ENOMEM;

Memory gone :(

drivers/usb/misc/intel-mux-drcfg.c line 122

Quoted 12 lines
drivers/usb/misc/intel-mux-drcfg.c new file +12 -0
+
+	mux->cfg0_ctx = readl(mux->regs + INTEL_MUX_CFG0);
+
+	umdev = &mux->umdev;
+	umdev->dev = dev;
+	umdev->cable_name = "USB-HOST";
+	umdev->cable_set_cb = intel_mux_drcfg_cable_set;
+	umdev->cable_unset_cb = intel_mux_drcfg_cable_unset;
+
+	ret = usb_mux_register(umdev);
+	if (ret)
+		writel(mux->cfg0_ctx, mux->regs + INTEL_MUX_CFG0);

So if an error happens you just keep going?

author
#20 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

Quoted 158 lines · Greg Kroah-Hartman
Quoted 157 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
MAINTAINERS +1 -0
index 0f321e4..20eb873 100644
@@ -11396,6 +11396,7 @@ S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
+F:	drivers/usb/misc/intel-mux-drcfg.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +7 -0
index 33e6386..befd910 100644
@@ -281,3 +281,10 @@ config INTEL_MUX_GPIO
 	help
 	  Say Y here to enable support for Intel dual role port mux
 	  controlled by GPIOs.
+
+config INTEL_MUX_DRCFG
+	tristate "Intel dual role port mux controlled by register"
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by the Dual Role Configuration Registers.
drivers/usb/misc/Makefile +1 -0
index da4fb4e..c4d19a0 100644
@@ -32,3 +32,4 @@ obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
 obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
+obj-$(CONFIG_INTEL_MUX_DRCFG)		+= intel-mux-drcfg.o
drivers/usb/misc/intel-mux-drcfg.c new file +99 -0
new file mode 100644
index 0000000..29081c5
@@ -0,0 +1,174 @@
+/**
+ * intel-mux-drcfg.c - Driver for Intel USB mux via register
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Heikki Krogerus <[email protected]>
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/usb/mux.h>
+#include <linux/platform_device.h>
+
+#define INTEL_MUX_CFG0		0x00
+#define INTEL_MUX_CFG1		0x04
+#define CFG0_SW_IDPIN		BIT(20)
+#define CFG0_SW_IDPIN_EN	BIT(21)
+#define CFG0_SW_VBUS_VALID	BIT(24)
+#define CFG1_SW_MODE		BIT(29)
+#define CFG1_POLL_TIMEOUT	1000
+
+struct intel_usb_mux {
+	struct usb_mux_dev umdev;
+	void __iomem *regs;
+	u32 cfg0_ctx;
+};
+
+static inline int intel_mux_drcfg_switch(struct usb_mux_dev *umdev, bool host)
+{
+	struct intel_usb_mux *mux;
+	unsigned long timeout;
+	u32 data;
+
+	mux = container_of(umdev, struct intel_usb_mux, umdev);
+
+	/* Check and set mux to SW controlled mode */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (!(data & CFG0_SW_IDPIN_EN)) {
+		data |= CFG0_SW_IDPIN_EN;
+		writel(data, mux->regs + INTEL_MUX_CFG0);
+	}
+
+	/*
+	 * Configure CFG0 to switch the mux and VBUS_VALID bit is
+	 * required for device mode.
+	 */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (host)
+		data &= ~(CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	else
+		data |= (CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	writel(data, mux->regs + INTEL_MUX_CFG0);
+
+	/*
+	 * Polling CFG1 for safety, most case it takes about 600ms
+	 * to finish mode switching, set TIMEOUT long enough.
+	 */
+	timeout = jiffies + msecs_to_jiffies(CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch. */
+	while (!time_after(jiffies, timeout)) {
+		data = readl(mux->regs + INTEL_MUX_CFG1);
+		if (!(host ^ (data & CFG1_SW_MODE)))
+			return 0;
+		/* interval for polling is set to about 5ms */
+		usleep_range(5000, 5100);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_mux_drcfg_cable_set(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to HOST\n");
+
+	return intel_mux_drcfg_switch(umdev, true);
+}
+
+static int intel_mux_drcfg_cable_unset(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to DEVICE\n");
+
+	return intel_mux_drcfg_switch(umdev, false);
+}
+
+static int intel_mux_drcfg_probe(struct platform_device *pdev)
+{
+	struct intel_usb_mux *mux;
+	struct usb_mux_dev *umdev;
+	struct device *dev = &pdev->dev;
+	u64 start, size;
+	int ret;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
Quoted 8 lines

drivers/usb/misc/intel-mux-drcfg.c line 106

Quoted 7 lines
drivers/usb/misc/intel-mux-drcfg.c new file +7 -0
+	if (!mux)
+		return -ENOMEM;
+
+	ret = device_property_read_u64(dev, "reg-start", &start);
+	ret |= device_property_read_u64(dev, "reg-size", &size);
+	if (ret)
+		return -ENODEV;

And you leaked memory :(

Did you mean device_property_read_*() allocated memory and I need to release it before return error?

Quoted 6 lines

drivers/usb/misc/intel-mux-drcfg.c line 110

Quoted 5 lines
drivers/usb/misc/intel-mux-drcfg.c new file +4 -0
+
+	mux->regs = devm_ioremap_nocache(dev, start, size);
+	if (!mux->regs)
+		return -ENOMEM;

Memory gone :(

devm interface will manage the resources by itself, or not?

Quoted 14 lines

drivers/usb/misc/intel-mux-drcfg.c line 122

Quoted 13 lines
drivers/usb/misc/intel-mux-drcfg.c new file +12 -0
+
+	mux->cfg0_ctx = readl(mux->regs + INTEL_MUX_CFG0);
+
+	umdev = &mux->umdev;
+	umdev->dev = dev;
+	umdev->cable_name = "USB-HOST";
+	umdev->cable_set_cb = intel_mux_drcfg_cable_set;
+	umdev->cable_unset_cb = intel_mux_drcfg_cable_unset;
+
+	ret = usb_mux_register(umdev);
+	if (ret)
+		writel(mux->cfg0_ctx, mux->regs + INTEL_MUX_CFG0);

So if an error happens you just keep going?

No. If error happens, I will restore the register and return error.

Thanks,
-Baolu

#21 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

Quoted 174 lines · Lu Baolu
Quoted 158 lines · Greg Kroah-Hartman
Quoted 157 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
MAINTAINERS +1 -0
index 0f321e4..20eb873 100644
@@ -11396,6 +11396,7 @@ S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
+F:	drivers/usb/misc/intel-mux-drcfg.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +7 -0
index 33e6386..befd910 100644
@@ -281,3 +281,10 @@ config INTEL_MUX_GPIO
 	help
 	  Say Y here to enable support for Intel dual role port mux
 	  controlled by GPIOs.
+
+config INTEL_MUX_DRCFG
+	tristate "Intel dual role port mux controlled by register"
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by the Dual Role Configuration Registers.
drivers/usb/misc/Makefile +1 -0
index da4fb4e..c4d19a0 100644
@@ -32,3 +32,4 @@ obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
 obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
+obj-$(CONFIG_INTEL_MUX_DRCFG)		+= intel-mux-drcfg.o
drivers/usb/misc/intel-mux-drcfg.c new file +99 -0
new file mode 100644
index 0000000..29081c5
@@ -0,0 +1,174 @@
+/**
+ * intel-mux-drcfg.c - Driver for Intel USB mux via register
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Heikki Krogerus <[email protected]>
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/usb/mux.h>
+#include <linux/platform_device.h>
+
+#define INTEL_MUX_CFG0		0x00
+#define INTEL_MUX_CFG1		0x04
+#define CFG0_SW_IDPIN		BIT(20)
+#define CFG0_SW_IDPIN_EN	BIT(21)
+#define CFG0_SW_VBUS_VALID	BIT(24)
+#define CFG1_SW_MODE		BIT(29)
+#define CFG1_POLL_TIMEOUT	1000
+
+struct intel_usb_mux {
+	struct usb_mux_dev umdev;
+	void __iomem *regs;
+	u32 cfg0_ctx;
+};
+
+static inline int intel_mux_drcfg_switch(struct usb_mux_dev *umdev, bool host)
+{
+	struct intel_usb_mux *mux;
+	unsigned long timeout;
+	u32 data;
+
+	mux = container_of(umdev, struct intel_usb_mux, umdev);
+
+	/* Check and set mux to SW controlled mode */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (!(data & CFG0_SW_IDPIN_EN)) {
+		data |= CFG0_SW_IDPIN_EN;
+		writel(data, mux->regs + INTEL_MUX_CFG0);
+	}
+
+	/*
+	 * Configure CFG0 to switch the mux and VBUS_VALID bit is
+	 * required for device mode.
+	 */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (host)
+		data &= ~(CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	else
+		data |= (CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	writel(data, mux->regs + INTEL_MUX_CFG0);
+
+	/*
+	 * Polling CFG1 for safety, most case it takes about 600ms
+	 * to finish mode switching, set TIMEOUT long enough.
+	 */
+	timeout = jiffies + msecs_to_jiffies(CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch. */
+	while (!time_after(jiffies, timeout)) {
+		data = readl(mux->regs + INTEL_MUX_CFG1);
+		if (!(host ^ (data & CFG1_SW_MODE)))
+			return 0;
+		/* interval for polling is set to about 5ms */
+		usleep_range(5000, 5100);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_mux_drcfg_cable_set(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to HOST\n");
+
+	return intel_mux_drcfg_switch(umdev, true);
+}
+
+static int intel_mux_drcfg_cable_unset(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to DEVICE\n");
+
+	return intel_mux_drcfg_switch(umdev, false);
+}
+
+static int intel_mux_drcfg_probe(struct platform_device *pdev)
+{
+	struct intel_usb_mux *mux;
+	struct usb_mux_dev *umdev;
+	struct device *dev = &pdev->dev;
+	u64 start, size;
+	int ret;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
Quoted 8 lines

drivers/usb/misc/intel-mux-drcfg.c line 106

Quoted 7 lines
drivers/usb/misc/intel-mux-drcfg.c new file +7 -0
+	if (!mux)
+		return -ENOMEM;
+
+	ret = device_property_read_u64(dev, "reg-start", &start);
+	ret |= device_property_read_u64(dev, "reg-size", &size);
+	if (ret)
+		return -ENODEV;

And you leaked memory :(

Did you mean device_property_read_*() allocated memory and I need to release it before return error?

Quoted 1 line
Quoted 7 lines
Quoted 5 lines

drivers/usb/misc/intel-mux-drcfg.c line 110

Quoted 4 lines
drivers/usb/misc/intel-mux-drcfg.c new file +4 -0
+
+	mux->regs = devm_ioremap_nocache(dev, start, size);
+	if (!mux->regs)
+		return -ENOMEM;

Memory gone :(

devm interface will manage the resources by itself, or not?

Ugh, you are right, nevermind, these both are fine, sorry for the noise.

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/usb/misc/intel-mux-drcfg.c new file +4 -0
+	mux->cfg0_ctx = readl(mux->regs + INTEL_MUX_CFG0);
+
+	umdev = &mux->umdev;
+	umdev->dev = dev;
Quoted 8 lines

drivers/usb/misc/intel-mux-drcfg.c line 122

Quoted 7 lines
drivers/usb/misc/intel-mux-drcfg.c new file +7 -0
+	umdev->cable_name = "USB-HOST";
+	umdev->cable_set_cb = intel_mux_drcfg_cable_set;
+	umdev->cable_unset_cb = intel_mux_drcfg_cable_unset;
+
+	ret = usb_mux_register(umdev);
+	if (ret)
+		writel(mux->cfg0_ctx, mux->regs + INTEL_MUX_CFG0);

So if an error happens you just keep going?

Quoted 1 line

No. If error happens, I will restore the register and return error.

That seems a bit "odd", and will change when you fix up the api...

thanks,

greg k-h

author
#22 lore raw

Re: [PATCH 5/7] usb: misc: add driver for Intel drcfg controlled port mux

Quoted 192 lines · Greg Kroah-Hartman
Quoted 171 lines · Lu Baolu
Quoted 158 lines · Greg Kroah-Hartman
Quoted 157 lines · Lu Baolu

Several Intel PCHs and SOCs have an internal mux that is used to share one USB port between device controller and host controller. The mux is handled through the Dual Role Configuration Register.

---
 MAINTAINERS                        |   1 +
 drivers/usb/misc/Kconfig           |   7 ++
 drivers/usb/misc/Makefile          |   1 +
 drivers/usb/misc/intel-mux-drcfg.c | 174 +++++++++++++++++++++++++++++++++++++
 4 files changed, 183 insertions(+)
 create mode 100644 drivers/usb/misc/intel-mux-drcfg.c
MAINTAINERS +1 -0
index 0f321e4..20eb873 100644
@@ -11396,6 +11396,7 @@ S:	Supported
 F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
+F:	drivers/usb/misc/intel-mux-drcfg.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/usb/misc/Kconfig +7 -0
index 33e6386..befd910 100644
@@ -281,3 +281,10 @@ config INTEL_MUX_GPIO
 	help
 	  Say Y here to enable support for Intel dual role port mux
 	  controlled by GPIOs.
+
+config INTEL_MUX_DRCFG
+	tristate "Intel dual role port mux controlled by register"
+	select USB_MUX
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by the Dual Role Configuration Registers.
drivers/usb/misc/Makefile +1 -0
index da4fb4e..c4d19a0 100644
@@ -32,3 +32,4 @@ obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
 
 obj-$(CONFIG_USB_MUX)			+= mux.o
 obj-$(CONFIG_INTEL_MUX_GPIO)		+= intel-mux-gpio.o
+obj-$(CONFIG_INTEL_MUX_DRCFG)		+= intel-mux-drcfg.o
drivers/usb/misc/intel-mux-drcfg.c new file +99 -0
new file mode 100644
index 0000000..29081c5
@@ -0,0 +1,174 @@
+/**
+ * intel-mux-drcfg.c - Driver for Intel USB mux via register
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Heikki Krogerus <[email protected]>
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/usb/mux.h>
+#include <linux/platform_device.h>
+
+#define INTEL_MUX_CFG0		0x00
+#define INTEL_MUX_CFG1		0x04
+#define CFG0_SW_IDPIN		BIT(20)
+#define CFG0_SW_IDPIN_EN	BIT(21)
+#define CFG0_SW_VBUS_VALID	BIT(24)
+#define CFG1_SW_MODE		BIT(29)
+#define CFG1_POLL_TIMEOUT	1000
+
+struct intel_usb_mux {
+	struct usb_mux_dev umdev;
+	void __iomem *regs;
+	u32 cfg0_ctx;
+};
+
+static inline int intel_mux_drcfg_switch(struct usb_mux_dev *umdev, bool host)
+{
+	struct intel_usb_mux *mux;
+	unsigned long timeout;
+	u32 data;
+
+	mux = container_of(umdev, struct intel_usb_mux, umdev);
+
+	/* Check and set mux to SW controlled mode */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (!(data & CFG0_SW_IDPIN_EN)) {
+		data |= CFG0_SW_IDPIN_EN;
+		writel(data, mux->regs + INTEL_MUX_CFG0);
+	}
+
+	/*
+	 * Configure CFG0 to switch the mux and VBUS_VALID bit is
+	 * required for device mode.
+	 */
+	data = readl(mux->regs + INTEL_MUX_CFG0);
+	if (host)
+		data &= ~(CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	else
+		data |= (CFG0_SW_IDPIN | CFG0_SW_VBUS_VALID);
+	writel(data, mux->regs + INTEL_MUX_CFG0);
+
+	/*
+	 * Polling CFG1 for safety, most case it takes about 600ms
+	 * to finish mode switching, set TIMEOUT long enough.
+	 */
+	timeout = jiffies + msecs_to_jiffies(CFG1_POLL_TIMEOUT);
+
+	/* Polling on CFG1 register to confirm mode switch. */
+	while (!time_after(jiffies, timeout)) {
+		data = readl(mux->regs + INTEL_MUX_CFG1);
+		if (!(host ^ (data & CFG1_SW_MODE)))
+			return 0;
+		/* interval for polling is set to about 5ms */
+		usleep_range(5000, 5100);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int intel_mux_drcfg_cable_set(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to HOST\n");
+
+	return intel_mux_drcfg_switch(umdev, true);
+}
+
+static int intel_mux_drcfg_cable_unset(struct usb_mux_dev *umdev)
+{
+	dev_dbg(umdev->dev, "drcfg mux switch to DEVICE\n");
+
+	return intel_mux_drcfg_switch(umdev, false);
+}
+
+static int intel_mux_drcfg_probe(struct platform_device *pdev)
+{
+	struct intel_usb_mux *mux;
+	struct usb_mux_dev *umdev;
+	struct device *dev = &pdev->dev;
+	u64 start, size;
+	int ret;
+
+	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
Quoted 8 lines

drivers/usb/misc/intel-mux-drcfg.c line 106

Quoted 7 lines
drivers/usb/misc/intel-mux-drcfg.c new file +7 -0
+	if (!mux)
+		return -ENOMEM;
+
+	ret = device_property_read_u64(dev, "reg-start", &start);
+	ret |= device_property_read_u64(dev, "reg-size", &size);
+	if (ret)
+		return -ENODEV;

And you leaked memory :(

Did you mean device_property_read_*() allocated memory and I need to release it before return error?

Quoted 6 lines
Quoted 5 lines

drivers/usb/misc/intel-mux-drcfg.c line 110

Quoted 4 lines
drivers/usb/misc/intel-mux-drcfg.c new file +4 -0
+
+	mux->regs = devm_ioremap_nocache(dev, start, size);
+	if (!mux->regs)
+		return -ENOMEM;

Memory gone :(

devm interface will manage the resources by itself, or not?

Ugh, you are right, nevermind, these both are fine, sorry for the noise.

Quoted 12 lines
Quoted 12 lines

drivers/usb/misc/intel-mux-drcfg.c line 122

Quoted 11 lines
drivers/usb/misc/intel-mux-drcfg.c new file +11 -0
+	mux->cfg0_ctx = readl(mux->regs + INTEL_MUX_CFG0);
+
+	umdev = &mux->umdev;
+	umdev->dev = dev;
+	umdev->cable_name = "USB-HOST";
+	umdev->cable_set_cb = intel_mux_drcfg_cable_set;
+	umdev->cable_unset_cb = intel_mux_drcfg_cable_unset;
+
+	ret = usb_mux_register(umdev);
+	if (ret)
+		writel(mux->cfg0_ctx, mux->regs + INTEL_MUX_CFG0);

So if an error happens you just keep going?

Quoted 2 lines
Quoted 1 line

No. If error happens, I will restore the register and return error.

That seems a bit "odd", and will change when you fix up the api...

Sure.

Quoted 5 lines

thanks,

greg k-h

Thank you for your time.

Best Regards,
baolu

author
#23 lore raw

PATCH 6/7 usb: pci-quirks: add Intel USB drcfg mux device

In reply to Lu Baolu

In some Intel platforms, a single usb port is shared between USB host and device controllers. The shared port is under control of a switch which is defined in the Intel vendor defined extended capability for xHCI.

This patch adds the support to detect and create the platform device for the port mux switch.

---
 drivers/usb/host/pci-quirks.c    | 47 ++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/xhci-ext-caps.h |  2 ++
 2 files changed, 47 insertions(+), 2 deletions(-)
drivers/usb/host/pci-quirks.c +45 -2
index 35af362..6a737cf 100644
@@ -16,10 +16,11 @@
 #include <linux/export.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
+#include <linux/platform_device.h>
+
 #include "pci-quirks.h"
 #include "xhci-ext-caps.h"
 
-
 #define UHCI_USBLEGSUP		0xc0		/* legacy support */
 #define UHCI_USBCMD		0		/* command register */
 #define UHCI_USBINTR		4		/* interrupt register */
@@ -78,6 +79,9 @@
 #define USB_INTEL_USB3_PSSEN   0xD8
 #define USB_INTEL_USB3PRM      0xDC
 
+#define DEVICE_ID_INTEL_CHERRYVIEW_XHCI		0x22b5
+#define DEVICE_ID_INTEL_BROXTON_M_XHCI		0x0aa8
+
 /*
  * amd_chipset_gen values represent AMD different chipset generations
  */
@@ -956,6 +960,41 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
 }
 EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
 
+static void create_intel_usb_mux_device(struct pci_dev *xhci_pdev,
+			void __iomem *base)
+{
+	struct platform_device *plat_dev;
+	struct property_set pset;
+	int ret;
+
+	struct property_entry pentry[] = {
+		PROPERTY_ENTRY_U64("reg-start",
+				pci_resource_start(xhci_pdev, 0) + 0x80d8),
+		PROPERTY_ENTRY_U64("reg-size", 8),
+		{ },
+	};
+
+	if (!xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_USB_MUX))
+		return;
+
+	plat_dev = platform_device_alloc("intel-mux-drcfg",
+					PLATFORM_DEVID_AUTO);
+	if (!plat_dev)
+		return;
+
+	plat_dev->dev.parent = &xhci_pdev->dev;
+	pset.properties = pentry;
+	platform_device_add_properties(plat_dev, &pset);
+
+	ret = platform_device_add(plat_dev);
+	if (ret) {
+		dev_warn(&xhci_pdev->dev,
+				"failed to create mux device with error %d",
+				ret);
+		platform_device_put(plat_dev);
+	}
+}
+
 /**
  * PCI Quirks for xHCI.
  *
@@ -1022,8 +1061,12 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
 	writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
 hc_init:
-	if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		usb_enable_intel_xhci_ports(pdev);
+		if (pdev->device == DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+				pdev->device == DEVICE_ID_INTEL_BROXTON_M_XHCI)
+			create_intel_usb_mux_device(pdev, base);
+	}
 
 	op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
drivers/usb/host/xhci-ext-caps.h +2 -0
index e0244fb..e368ccb 100644
@@ -51,6 +51,8 @@
 #define XHCI_EXT_CAPS_ROUTE	5
 /* IDs 6-9 reserved */
 #define XHCI_EXT_CAPS_DEBUG	10
+/* Vendor defined 192-255 */
+#define XHCI_EXT_CAPS_INTEL_USB_MUX	192
 /* USB Legacy Support Capability - section 7.1.1 */
 #define XHCI_HC_BIOS_OWNED	(1 << 16)
 #define XHCI_HC_OS_OWNED	(1 << 24)
Signature · 1 line
2.1.4
author
#24 lore raw

PATCH 7/7 mfd: intel_vuport: Add Intel virtual USB port MFD Driver

In reply to Lu Baolu

Some Intel platforms have an USB port mux controlled by GPIOs. There's a single ACPI platform device that provides both USB ID extcon device and a USB port mux device. This MFD driver will split the 2 devices for their respective drivers.

---
 MAINTAINERS                |  1 +
 drivers/mfd/Kconfig        |  7 ++++
 drivers/mfd/Makefile       |  1 +
 drivers/mfd/intel-vuport.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+)
 create mode 100644 drivers/mfd/intel-vuport.c
MAINTAINERS +1 -0
index 20eb873..6e0bb12 100644
@@ -11397,6 +11397,7 @@ F:	drivers/usb/misc/mux.c
 F:	include/linux/usb/mux.h
 F:	drivers/usb/misc/intel-mux-gpio.c
 F:	drivers/usb/misc/intel-mux-drcfg.c
+F:	drivers/mfd/intel-vuport.c
 
 USB PRINTER DRIVER (usblp)
 M:	Pete Zaitcev <[email protected]>
drivers/mfd/Kconfig +7 -0
index 9ca66de..0913494 100644
@@ -1534,5 +1534,12 @@ config MFD_VEXPRESS_SYSREG
 	  System Registers are the platform configuration block
 	  on the ARM Ltd. Versatile Express board.
 
+config MFD_INTEL_VUPORT
+	tristate "Intel virtual USB port controller"
+	select MFD_CORE
+	help
+	  Say Y here to enable support for Intel dual role port mux
+	  controlled by 3 GPIOs.
+
 endmenu
 endif
drivers/mfd/Makefile +1 -0
index 0f230a6..0ccd107 100644
@@ -198,3 +198,4 @@ intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
+obj-$(CONFIG_MFD_INTEL_VUPORT)	+= intel-vuport.o
drivers/mfd/intel-vuport.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.1.4
#25 lore raw

Re: [PATCH 7/7] mfd: intel_vuport: Add Intel virtual USB port MFD Driver

coccinelle warnings: (new ones prefixed by >>)

Hi Lu,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing

coccinelle warnings: (new ones prefixed by >>)

>> drivers/mfd/intel-vuport.c:68:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#26 lore raw

[PATCH] mfd: intel_vuport: fix platform_no_drv_owner.cocci warnings

In reply to Lu Baolu
drivers/mfd/intel-vuport.c:68:3-8: No need to set .owner here. The core will do it.

drivers/mfd/intel-vuport.c:68:3-8: No need to set .owner here. The core will do it.

Remove .owner field if calls are used which set it automatically

Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci

---

 intel-vuport.c |    1 -
 1 file changed, 1 deletion(-)
drivers/mfd/intel-vuport.c +0 -1
@@ -65,7 +65,6 @@ MODULE_DEVICE_TABLE(acpi, vuport_acpi_ma
 static struct platform_driver vuport_driver = {
 	.driver = {
 		.name = "intel-vuport",
-		.owner = THIS_MODULE,
 		.acpi_match_table = ACPI_PTR(vuport_acpi_match),
 	},
 	.probe = vuport_probe,
#27 lore raw

Re: [PATCH 7/7] mfd: intel_vuport: Add Intel virtual USB port MFD Driver

In reply to Lu Baolu
reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree…

Hi Lu,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: openrisc-allyesconfig (attached as .config)

reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=openrisc

All warnings (new ones prefixed by >>):

drivers/mfd/intel-vuport.c: In function 'vuport_probe':

>> drivers/mfd/intel-vuport.c:39:17: warning: unused variable 'dev'

drivers/mfd/intel-vuport.c: At top level:
drivers/mfd/intel-vuport.c:59:30: warning: 'vuport_acpi_match' defined but not used

vim +/dev +39 drivers/mfd/intel-vuport.c

    23		{ "vbus_en-gpios", &vbus_gpio, 1 },
    24		{ "usb_mux-gpios", &mux_gpio, 1 },
    25		{ },
    26	};
    27	
    28	static const struct mfd_cell intel_vuport_mfd_cells[] = {
    29		{
    30			.name = "extcon-usb-gpio",
    31		},
    32		{
    33			.name = "intel-mux-gpio",
    34		},
    35	};
    36	
    37	static int vuport_probe(struct platform_device *pdev)
    38	{
  > 39		struct device *dev = &pdev->dev;
    40		int ret;
    41	
    42		ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_usb_gpios);
    43		if (ret)
    44			return ret;
    45	
    46		return mfd_add_devices(&pdev->dev, 0, intel_vuport_mfd_cells,
    47				ARRAY_SIZE(intel_vuport_mfd_cells), NULL, 0,

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#28 lore raw

Re: [PATCH 7/7] mfd: intel_vuport: Add Intel virtual USB port MFD Driver

In reply to Lu Baolu
reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree…

Hi Lu,

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: parisc-allyesconfig (attached as .config)

reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=parisc

All warnings (new ones prefixed by >>):

drivers/mfd/intel-vuport.c: In function 'vuport_probe':
drivers/mfd/intel-vuport.c:39:17: warning: unused variable 'dev' [-Wunused-variable]

     struct device *dev = &pdev->dev;
                    ^
   drivers/mfd/intel-vuport.c: At top level:
   drivers/mfd/intel-vuport.c:63:1: warning: data definition has no type or storage class
    MODULE_DEVICE_TABLE(acpi, vuport_acpi_match);
    ^
   drivers/mfd/intel-vuport.c:63:1: error: type defaults to 'int' in declaration of 'MODULE_DEVICE_TABLE' [-Werror=implicit-int]
   drivers/mfd/intel-vuport.c:63:1: warning: parameter names (without types) in function declaration
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/device.h:1337:1: warning: data definition has no type or storage class
    module_init(__driver##_init); \
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   include/linux/device.h:1337:1: error: type defaults to 'int' in declaration of 'module_init' [-Werror=implicit-int]
    module_init(__driver##_init); \
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   In file included from include/linux/linkage.h:6:0,
                    from include/linux/kernel.h:6,
                    from include/linux/list.h:8,
                    from include/linux/resource_ext.h:17,
                    from include/linux/acpi.h:26,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/export.h:36:30: warning: parameter names (without types) in function declaration
    #define THIS_MODULE ((struct module *)0)
                                 ^
   include/linux/platform_device.h:198:34: note: in expansion of macro 'THIS_MODULE'
     __platform_driver_register(drv, THIS_MODULE)
                                     ^
   include/linux/device.h:1335:9: note: in expansion of macro 'platform_driver_register'
     return __register(&(__driver) , ##__VA_ARGS__); \
            ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/device.h:1342:1: warning: data definition has no type or storage class
    module_exit(__driver##_exit);
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   include/linux/device.h:1342:1: error: type defaults to 'int' in declaration of 'module_exit' [-Werror=implicit-int]
    module_exit(__driver##_exit);
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   In file included from include/linux/linkage.h:6:0,
                    from include/linux/kernel.h:6,
                    from include/linux/list.h:8,
                    from include/linux/resource_ext.h:17,
                    from include/linux/acpi.h:26,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/export.h:36:30: warning: parameter names (without types) in function declaration
    #define THIS_MODULE ((struct module *)0)
                                 ^
   include/linux/platform_device.h:198:34: note: in expansion of macro 'THIS_MODULE'
     __platform_driver_register(drv, THIS_MODULE)
                                     ^
   include/linux/device.h:1335:9: note: in expansion of macro 'platform_driver_register'
     return __register(&(__driver) , ##__VA_ARGS__); \
            ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   drivers/mfd/intel-vuport.c:77:15: error: expected declaration specifiers or '...' before string constant
    MODULE_AUTHOR("Lu Baolu <[email protected]>");
                  ^
   drivers/mfd/intel-vuport.c:78:20: error: expected declaration specifiers or '...' before string constant
    MODULE_DESCRIPTION("Intel virtual USB port");
                       ^
   drivers/mfd/intel-vuport.c:79:16: error: expected declaration specifiers or '...' before string constant
    MODULE_LICENSE("GPL v2");
                   ^
   drivers/mfd/intel-vuport.c:59:30: warning: 'vuport_acpi_match' defined but not used [-Wunused-variable]
    static struct acpi_device_id vuport_acpi_match[] = {
                                 ^
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   drivers/mfd/intel-vuport.c:75:24: warning: 'vuport_driver_init' defined but not used [-Wunused-function]
    module_platform_driver(vuport_driver);
                           ^
   include/linux/device.h:1333:19: note: in definition of macro 'module_driver'
    static int __init __driver##_init(void) \
                      ^
>> drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^

cc1: some warnings being treated as errors

vim +/module_platform_driver +75 drivers/mfd/intel-vuport.c

    57	}
    58	
    59	static struct acpi_device_id vuport_acpi_match[] = {
    60		{ "INT3496" },
    61		{ }
    62	};
  > 63	MODULE_DEVICE_TABLE(acpi, vuport_acpi_match);
    64	
    65	static struct platform_driver vuport_driver = {
    66		.driver = {
    67			.name = "intel-vuport",
    68			.owner = THIS_MODULE,
    69			.acpi_match_table = ACPI_PTR(vuport_acpi_match),
    70		},
    71		.probe = vuport_probe,
    72		.remove = vuport_remove,
    73	};
    74	
  > 75	module_platform_driver(vuport_driver);
    76	
    77	MODULE_AUTHOR("Lu Baolu <[email protected]>");
    78	MODULE_DESCRIPTION("Intel virtual USB port");

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#29 lore raw

Re: [PATCH 7/7] mfd: intel_vuport: Add Intel virtual USB port MFD Driver

In reply to Lu Baolu
reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree…

Hi Lu,

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on v4.5-rc6 next-20160303]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Lu-Baolu/usb-add-support-for-Intel-dual-role-port-mux/20160303-144241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: mn10300-allmodconfig (attached as .config)

reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=mn10300

All error/warnings (new ones prefixed by >>):

drivers/mfd/intel-vuport.c: In function 'vuport_probe':
drivers/mfd/intel-vuport.c:39:17: warning: unused variable 'dev' [-Wunused-variable]

     struct device *dev = &pdev->dev;
                    ^
   drivers/mfd/intel-vuport.c: At top level:
>> drivers/mfd/intel-vuport.c:63:1: warning: data definition has no type or storage class
    MODULE_DEVICE_TABLE(acpi, vuport_acpi_match);
    ^
>> drivers/mfd/intel-vuport.c:63:1: error: type defaults to 'int' in declaration of 'MODULE_DEVICE_TABLE' [-Werror=implicit-int]
>> drivers/mfd/intel-vuport.c:63:1: warning: parameter names (without types) in function declaration
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/device.h:1337:1: warning: data definition has no type or storage class
    module_init(__driver##_init); \
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   include/linux/device.h:1337:1: error: type defaults to 'int' in declaration of 'module_init' [-Werror=implicit-int]
    module_init(__driver##_init); \
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   drivers/mfd/intel-vuport.c:75:1: warning: parameter names (without types) in function declaration
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   include/linux/device.h:1342:1: warning: data definition has no type or storage class
    module_exit(__driver##_exit);
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   include/linux/device.h:1342:1: error: type defaults to 'int' in declaration of 'module_exit' [-Werror=implicit-int]
    module_exit(__driver##_exit);
    ^
   include/linux/platform_device.h:228:2: note: in expansion of macro 'module_driver'
     module_driver(__platform_driver, platform_driver_register, \
     ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   drivers/mfd/intel-vuport.c:75:1: warning: parameter names (without types) in function declaration
>> drivers/mfd/intel-vuport.c:77:15: error: expected declaration specifiers or '...' before string constant
    MODULE_AUTHOR("Lu Baolu <[email protected]>");
                  ^
   drivers/mfd/intel-vuport.c:78:20: error: expected declaration specifiers or '...' before string constant
    MODULE_DESCRIPTION("Intel virtual USB port");
                       ^
   drivers/mfd/intel-vuport.c:79:16: error: expected declaration specifiers or '...' before string constant
    MODULE_LICENSE("GPL v2");
                   ^
   drivers/mfd/intel-vuport.c:59:30: warning: 'vuport_acpi_match' defined but not used [-Wunused-variable]
    static struct acpi_device_id vuport_acpi_match[] = {
                                 ^
   In file included from include/linux/acpi.h:27:0,
                    from drivers/mfd/intel-vuport.c:12:
   drivers/mfd/intel-vuport.c:75:24: warning: 'vuport_driver_init' defined but not used [-Wunused-function]
    module_platform_driver(vuport_driver);
                           ^
   include/linux/device.h:1333:19: note: in definition of macro 'module_driver'
    static int __init __driver##_init(void) \
                      ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^
   drivers/mfd/intel-vuport.c:75:24: warning: 'vuport_driver_exit' defined but not used [-Wunused-function]
    module_platform_driver(vuport_driver);
                           ^
   include/linux/device.h:1338:20: note: in definition of macro 'module_driver'
    static void __exit __driver##_exit(void) \
                       ^
   drivers/mfd/intel-vuport.c:75:1: note: in expansion of macro 'module_platform_driver'
    module_platform_driver(vuport_driver);
    ^

cc1: some warnings being treated as errors

vim +63 drivers/mfd/intel-vuport.c

    33			.name = "intel-mux-gpio",
    34		},
    35	};
    36	
    37	static int vuport_probe(struct platform_device *pdev)
    38	{
  > 39		struct device *dev = &pdev->dev;
    40		int ret;
    41	
    42		ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_usb_gpios);
    43		if (ret)
    44			return ret;
    45	
    46		return mfd_add_devices(&pdev->dev, 0, intel_vuport_mfd_cells,
    47				ARRAY_SIZE(intel_vuport_mfd_cells), NULL, 0,
    48				NULL);
    49	}
    50	
    51	static int vuport_remove(struct platform_device *pdev)
    52	{
    53		mfd_remove_devices(&pdev->dev);
    54		acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
    55	
    56		return 0;
    57	}
    58	
    59	static struct acpi_device_id vuport_acpi_match[] = {
    60		{ "INT3496" },
    61		{ }
    62	};
  > 63	MODULE_DEVICE_TABLE(acpi, vuport_acpi_match);
    64	
    65	static struct platform_driver vuport_driver = {
    66		.driver = {
    67			.name = "intel-vuport",
    68			.owner = THIS_MODULE,
    69			.acpi_match_table = ACPI_PTR(vuport_acpi_match),
    70		},
    71		.probe = vuport_probe,
    72		.remove = vuport_remove,
    73	};
    74	
  > 75	module_platform_driver(vuport_driver);
    76	
  > 77	MODULE_AUTHOR("Lu Baolu <[email protected]>");
    78	MODULE_DESCRIPTION("Intel virtual USB port");
    79	MODULE_LICENSE("GPL v2");

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation