linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [v3 PATCH 0/6] add USB Type-B GPIO connector driver
@ 2019-04-03  2:09 Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 1/6] dt-bindings: connector: add optional properties for Type-B Chunfeng Yun
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Because the USB Connector is introduced and the requirement of
usb-connector.txt binding, the old way using extcon to support
USB Dual-Role switch is now deprecated, meanwhile there is no
available common driver when use Type-B connector, typically
using an input GPIO to detect USB ID pin.
This patch series introduce a Type-B GPIO connector driver and try
to replace the function provided by extcon-usb-gpio driver.

v3 changes:
  1. add GPIO direction, and use fixed-regulator for GPIO controlled
    VBUS regulator suggested by Rob;
  2. rebuild fwnode_usb_role_switch_get() suggested by Andy and Heikki
  3. treat the type-B connector as a virtual device;
  4. change file name of driver again
  5. select USB_ROLE_SWITCH in mtu3/Kconfig suggested by Heikki
  6. rename ssusb_mode_manual_switch() to ssusb_mode_switch()

v2 changes:
 1. make binding clear, and add a extra compatible suggested by Hans

Chunfeng Yun (6):
  dt-bindings: connector: add optional properties for Type-B
  dt-bindings: usb: add binding for Type-B GPIO connector driver
  dt-bindings: usb: mtu3: add properties about USB Role Switch
  usb: roles: add API to get usb_role_switch by node
  usb: roles: add USB Type-B GPIO connector driver
  usb: mtu3: register a USB Role Switch for dual role mode

 .../bindings/connector/usb-connector.txt      |  14 +
 .../devicetree/bindings/usb/mediatek,mtu3.txt |  10 +-
 .../bindings/usb/typeb-conn-gpio.txt          |  49 +++
 drivers/usb/mtu3/Kconfig                      |   1 +
 drivers/usb/mtu3/mtu3.h                       |   5 +
 drivers/usb/mtu3/mtu3_debugfs.c               |   4 +-
 drivers/usb/mtu3/mtu3_dr.c                    |  47 ++-
 drivers/usb/mtu3/mtu3_dr.h                    |   6 +-
 drivers/usb/mtu3/mtu3_plat.c                  |   3 +-
 drivers/usb/roles/Kconfig                     |  11 +
 drivers/usb/roles/Makefile                    |   1 +
 drivers/usb/roles/class.c                     |  31 ++
 drivers/usb/roles/typeb-conn-gpio.c           | 301 ++++++++++++++++++
 include/linux/usb/role.h                      |   2 +
 14 files changed, 476 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/typeb-conn-gpio.txt
 create mode 100644 drivers/usb/roles/typeb-conn-gpio.c

-- 
2.20.1


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

* [v3 PATCH 1/6] dt-bindings: connector: add optional properties for Type-B
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 2/6] dt-bindings: usb: add binding for Type-B GPIO connector driver Chunfeng Yun
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Add id-gpios, vbus-gpios, vbus-supply and pinctrl properties for
usb-b-connector

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3 changes:
 1. add GPIO direction, and use fixed-regulator for GPIO controlled
    VBUS regulator suggested by Rob;

v2 changes:
  1. describe more clear for vbus-gpios and vbus-supply suggested by Hans
---
 .../bindings/connector/usb-connector.txt           | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt
index a9a2f2fc44f2..e8f9e854fd11 100644
--- a/Documentation/devicetree/bindings/connector/usb-connector.txt
+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt
@@ -17,6 +17,20 @@ Optional properties:
 - self-powered: Set this property if the usb device that has its own power
   source.
 
+Optional properties for usb-b-connector:
+- id-gpios: an input gpio for USB ID pin.
+- vbus-gpios: an input gpio for USB VBUS pin, used to detect presence of
+  VBUS 5V.
+  see gpio/gpio.txt.
+- vbus-supply: a phandle to the regulator for USB VBUS if needed when host
+  mode or dual role mode is supported.
+  Particularly, if use an output GPIO to control a VBUS regulator, should
+  model it as a regulator.
+  see regulator/fixed-regulator.yaml
+- pinctrl-names : a pinctrl state named "default" is optional
+- pinctrl-0 : pin control group
+  see pinctrl/pinctrl-bindings.txt
+
 Optional properties for usb-c-connector:
 - power-role: should be one of "source", "sink" or "dual"(DRP) if typec
   connector has power support.
-- 
2.20.1


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

* [v3 PATCH 2/6] dt-bindings: usb: add binding for Type-B GPIO connector driver
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 1/6] dt-bindings: connector: add optional properties for Type-B Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 3/6] dt-bindings: usb: mtu3: add properties about USB Role Switch Chunfeng Yun
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

It's used to support dual role switch via GPIO when use Type-B
receptacle, typically the USB ID pin is connected to an input
GPIO pin

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3 changes:
 1. treat type-B connector as a virtual device, but not child device of
    USB controller's

v2 changes:
  1. new patch to make binding clear suggested by Hans
---
 .../bindings/usb/typeb-conn-gpio.txt          | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/typeb-conn-gpio.txt

diff --git a/Documentation/devicetree/bindings/usb/typeb-conn-gpio.txt b/Documentation/devicetree/bindings/usb/typeb-conn-gpio.txt
new file mode 100644
index 000000000000..d2e1c4e01b6d
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/typeb-conn-gpio.txt
@@ -0,0 +1,49 @@
+USB Type-B GPIO Connector
+
+This is a virtual device used to switch dual role mode from the USB ID pin
+connected to an input GPIO pin.
+
+Required properties:
+- compatible : Should be "linux,typeb-conn-gpio"
+
+Sub-nodes:
+- connector : should be present.
+	- compatible : should be "usb-b-connector".
+	- id-gpios, vbus-gpios : either one of them must be present,
+		and both can be present as well.
+	- vbus-supply : can be present if needed when supports dual role mode.
+	see connector/usb-connector.txt
+
+- port : should be present.
+	see graph.txt
+
+Example:
+
+rsw_iddig: role_sw_iddig {
+	compatible = "linux,typeb-conn-gpio";
+	status = "okay";
+
+	connector {
+		compatible = "usb-b-connector";
+		label = "micro-USB";
+		type = "micro";
+		id-gpios = <&pio 12 GPIO_ACTIVE_HIGH>;
+		vbus-supply = <&usb_p0_vbus>;
+	};
+
+	port {
+		bconn_ep: endpoint@0 {
+			remote-endpoint = <&usb_role_sw>;
+		};
+	};
+};
+
+&mtu3 {
+	status = "okay";
+
+	port {
+		usb_role_sw: endpoint@0 {
+			remote-endpoint = <&bconn_ep>;
+		};
+	};
+};
-- 
2.20.1


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

* [v3 PATCH 3/6] dt-bindings: usb: mtu3: add properties about USB Role Switch
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 1/6] dt-bindings: connector: add optional properties for Type-B Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 2/6] dt-bindings: usb: add binding for Type-B GPIO connector driver Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node Chunfeng Yun
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Now the USB Role Switch is supported, so add properties about it

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3: no changes

v2 changes:
  1. fix typo
  2. refer new binding about connector property
---
 .../devicetree/bindings/usb/mediatek,mtu3.txt          | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
index 3382b5cb471d..6e004c4a89af 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
@@ -27,7 +27,9 @@ Optional properties:
  - ranges : allows valid 1:1 translation between child's address space and
 	parent's address space
  - extcon : external connector for vbus and idpin changes detection, needed
-	when supports dual-role mode.
+	when supports dual-role mode; it's consiedered valid for compatibility
+	reasons, and not allowed for new bindings, use the property
+	usb-role-switch instead.
  - vbus-supply : reference to the VBUS regulator, needed when supports
 	dual-role mode.
  - pinctrl-names : a pinctrl state named "default" is optional, and need be
@@ -36,7 +38,8 @@ Optional properties:
 	is not set.
  - pinctrl-0 : pin control group
 	See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
-
+ - usb-role-switch : use USB Role Switch to support dual-role switch, but
+	not extcon
  - maximum-speed : valid arguments are "super-speed", "high-speed" and
 	"full-speed"; refer to usb/generic.txt
  - enable-manual-drd : supports manual dual-role switch via debugfs; usually
@@ -61,6 +64,9 @@ The xhci should be added as subnode to mtu3 as shown in the following example
 if host mode is enabled. The DT binding details of xhci can be found in:
 Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
 
+The port would be added as subnode if use usb-role-switch property
+	see graph.txt
+
 Example:
 ssusb: usb@11271000 {
 	compatible = "mediatek,mt8173-mtu3";
-- 
2.20.1


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

* [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
                   ` (2 preceding siblings ...)
  2019-04-03  2:09 ` [v3 PATCH 3/6] dt-bindings: usb: mtu3: add properties about USB Role Switch Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-10 10:22   ` Heikki Krogerus
  2019-04-03  2:09 ` [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver Chunfeng Yun
  2019-04-03  2:09 ` [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode Chunfeng Yun
  5 siblings, 1 reply; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Add fwnode_usb_role_switch_get() to make easier to get
usb_role_switch by fwnode which register it.
It's useful when there is not device_connection registered
between two drivers and only knows the fwnode which register
usb_role_switch.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3 changes:
  1. use fwnodes instead of node suggested by Andy
  2. rebuild the API suggested by Heikki

v2 no changes
---
 drivers/usb/roles/class.c | 31 +++++++++++++++++++++++++++++++
 include/linux/usb/role.h  |  2 ++
 2 files changed, 33 insertions(+)

diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index f45d8df5cfb8..5ecb57f8960b 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -12,6 +12,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 
 static struct class *role_class;
@@ -135,6 +136,36 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_get);
 
+static int __switch_match_fwnode(struct device *dev, const void *fwnode)
+{
+	return dev_fwnode(dev->parent) == (const struct fwnode_handle *)fwnode;
+}
+
+/**
+ * fwnode_usb_role_switch_get - Find USB role switch by it's parent fwnode
+ * @fwnode: The fwnode that register USB role switch
+ *
+ * Finds and returns role switch registered by @fwnode. The reference count
+ * for the found switch is incremented.
+ */
+struct usb_role_switch *
+fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
+{
+	struct usb_role_switch *sw;
+	struct device *dev;
+
+	dev = class_find_device(role_class, NULL, fwnode,
+				__switch_match_fwnode);
+	if (!dev)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	sw = to_role_switch(dev);
+	WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
+
+	return sw;
+}
+EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
+
 /**
  * usb_role_switch_put - Release handle to a switch
  * @sw: USB Role Switch
diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
index c05ffa6abda9..d21cd55d9e45 100644
--- a/include/linux/usb/role.h
+++ b/include/linux/usb/role.h
@@ -46,6 +46,8 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role);
 enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw);
 struct usb_role_switch *usb_role_switch_get(struct device *dev);
 void usb_role_switch_put(struct usb_role_switch *sw);
+struct usb_role_switch *
+fwnode_usb_role_switch_get(struct fwnode_handle *fwnode);
 
 struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
-- 
2.20.1


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

* [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
                   ` (3 preceding siblings ...)
  2019-04-03  2:09 ` [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-04 16:35   ` Linus Walleij
  2019-04-03  2:09 ` [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode Chunfeng Yun
  5 siblings, 1 reply; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Due to the requirement of usb-connector.txt binding, the old way
using extcon to support USB Dual-Role switch is now deprecated
when use Type-B connector.
This patch introduces a driver of Type-B connector which typically
uses an input GPIO to detect USB ID pin, and try to replace the
function provided by extcon-usb-gpio driver

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3 changes:
  1. treat bype-B connector as a virtual device;
  2. change file name again

v2 changes:
  1. file name is changed
  2. use new compatible
---
 drivers/usb/roles/Kconfig           |  11 +
 drivers/usb/roles/Makefile          |   1 +
 drivers/usb/roles/typeb-conn-gpio.c | 301 ++++++++++++++++++++++++++++
 3 files changed, 313 insertions(+)
 create mode 100644 drivers/usb/roles/typeb-conn-gpio.c

diff --git a/drivers/usb/roles/Kconfig b/drivers/usb/roles/Kconfig
index f8b31aa67526..d1156e18a81a 100644
--- a/drivers/usb/roles/Kconfig
+++ b/drivers/usb/roles/Kconfig
@@ -26,4 +26,15 @@ config USB_ROLES_INTEL_XHCI
 	  To compile the driver as a module, choose M here: the module will
 	  be called intel-xhci-usb-role-switch.
 
+config TYPEB_CONN_GPIO
+	tristate "USB Type-B GPIO Connector"
+	depends on GPIOLIB
+	help
+	  The driver supports USB role switch between host and device via GPIO
+	  based USB cable detection, used typically if an input GPIO is used
+	  to detect USB ID pin.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called typeb-conn-gpio.ko
+
 endif # USB_ROLE_SWITCH
diff --git a/drivers/usb/roles/Makefile b/drivers/usb/roles/Makefile
index 757a7d2797eb..5d5620d9d113 100644
--- a/drivers/usb/roles/Makefile
+++ b/drivers/usb/roles/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_USB_ROLE_SWITCH)		+= roles.o
 roles-y					:= class.o
 obj-$(CONFIG_USB_ROLES_INTEL_XHCI)	+= intel-xhci-usb-role-switch.o
+obj-$(CONFIG_TYPEB_CONN_GPIO)		+= typeb-conn-gpio.o
diff --git a/drivers/usb/roles/typeb-conn-gpio.c b/drivers/usb/roles/typeb-conn-gpio.c
new file mode 100644
index 000000000000..83804141ab9e
--- /dev/null
+++ b/drivers/usb/roles/typeb-conn-gpio.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB Type-B GPIO Connector Driver
+ *
+ * Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * Some code borrowed from drivers/extcon/extcon-usb-gpio.c
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/role.h>
+
+#define USB_GPIO_DEB_MS		20	/* ms */
+#define USB_GPIO_DEB_US		((USB_GPIO_DEB_MS) * 1000)	/* us */
+
+#define USB_CONN_IRQF	\
+	(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT)
+
+struct usb_conn_info {
+	struct device *dev;
+	struct usb_role_switch *role_sw;
+	enum usb_role last_role;
+	struct regulator *vbus;
+	struct delayed_work dw_det;
+	unsigned long debounce_jiffies;
+
+	struct gpio_desc *id_gpiod;
+	struct gpio_desc *vbus_gpiod;
+	int id_irq;
+	int vbus_irq;
+};
+
+/**
+ * "DEVICE" = VBUS and "HOST" = !ID, so we have:
+ * Both "DEVICE" and "HOST" can't be set as active at the same time
+ * so if "HOST" is active (i.e. ID is 0)  we keep "DEVICE" inactive
+ * even if VBUS is on.
+ *
+ *  Role          |   ID  |  VBUS
+ * ------------------------------------
+ *  [1] DEVICE    |   H   |   H
+ *  [2] NONE      |   H   |   L
+ *  [3] HOST      |   L   |   H
+ *  [4] HOST      |   L   |   L
+ *
+ * In case we have only one of these signals:
+ * - VBUS only - we want to distinguish between [1] and [2], so ID is always 1
+ * - ID only - we want to distinguish between [1] and [4], so VBUS = ID
+ */
+static void usb_conn_detect_cable(struct work_struct *work)
+{
+	struct usb_conn_info *info;
+	enum usb_role role;
+	int id, vbus, ret;
+
+	info = container_of(to_delayed_work(work),
+			    struct usb_conn_info, dw_det);
+
+	/* check ID and VBUS */
+	id = info->id_gpiod ?
+		gpiod_get_value_cansleep(info->id_gpiod) : 1;
+	vbus = info->vbus_gpiod ?
+		gpiod_get_value_cansleep(info->vbus_gpiod) : id;
+
+	if (!id)
+		role = USB_ROLE_HOST;
+	else if (vbus)
+		role = USB_ROLE_DEVICE;
+	else
+		role = USB_ROLE_NONE;
+
+	dev_dbg(info->dev, "role %d/%d, gpios: id %d, vbus %d\n",
+		info->last_role, role, id, vbus);
+
+	if (info->last_role == role) {
+		dev_warn(info->dev, "repeated role: %d\n", role);
+		return;
+	}
+
+	if (info->last_role == USB_ROLE_HOST)
+		regulator_disable(info->vbus);
+
+	ret = usb_role_switch_set_role(info->role_sw, role);
+	if (ret)
+		dev_err(info->dev, "failed to set role: %d\n", ret);
+
+	if (role == USB_ROLE_HOST) {
+		ret = regulator_enable(info->vbus);
+		if (ret)
+			dev_err(info->dev, "enable vbus regulator failed\n");
+	}
+
+	info->last_role = role;
+
+	dev_dbg(info->dev, "vbus regulator is %s\n",
+		regulator_is_enabled(info->vbus) ? "enabled" : "disabled");
+}
+
+static void usb_conn_queue_dwork(struct usb_conn_info *info,
+				 unsigned long delay)
+{
+	queue_delayed_work(system_power_efficient_wq, &info->dw_det, delay);
+}
+
+static irqreturn_t usb_conn_isr(int irq, void *dev_id)
+{
+	struct usb_conn_info *info = dev_id;
+
+	usb_conn_queue_dwork(info, info->debounce_jiffies);
+
+	return IRQ_HANDLED;
+}
+
+static int usb_conn_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *parent;
+	struct device_node *child;
+	struct usb_conn_info *info;
+	int ret = 0;
+
+	if (!np)
+		return -EINVAL;
+
+	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = dev;
+
+	child = of_get_child_by_name(np, "connector");
+	if (!child) {
+		dev_err(dev, "failed to find connector node\n");
+		return -ENODEV;
+	}
+
+	info->id_gpiod = devm_gpiod_get_from_of_node(
+				dev, child, "id-gpios", 0, GPIOD_IN, "idpin");
+	if (IS_ERR(info->id_gpiod))
+		return PTR_ERR(info->id_gpiod);
+
+	info->vbus_gpiod = devm_gpiod_get_from_of_node(
+				dev, child, "vbus-gpios", 0, GPIOD_IN,
+				"vbuspin");
+	if (IS_ERR(info->vbus_gpiod))
+		return PTR_ERR(info->vbus_gpiod);
+
+	if (!info->id_gpiod && !info->vbus_gpiod) {
+		dev_err(dev, "failed to get gpios\n");
+		return -ENODEV;
+	}
+
+	of_node_put(child);
+
+	if (info->id_gpiod)
+		ret = gpiod_set_debounce(info->id_gpiod, USB_GPIO_DEB_US);
+	if (!ret && info->vbus_gpiod)
+		ret = gpiod_set_debounce(info->vbus_gpiod, USB_GPIO_DEB_US);
+	if (ret < 0)
+		info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEB_MS);
+
+	INIT_DELAYED_WORK(&info->dw_det, usb_conn_detect_cable);
+
+	info->vbus = devm_regulator_get(dev, "vbus");
+	if (IS_ERR(info->vbus)) {
+		dev_err(dev, "failed to get vbus\n");
+		return PTR_ERR(info->vbus);
+	}
+
+	child = of_graph_get_endpoint_by_regs(np, -1, 0);
+	parent = of_graph_get_remote_port_parent(child);
+	info->role_sw = fwnode_usb_role_switch_get(of_fwnode_handle(parent));
+	if (IS_ERR_OR_NULL(info->role_sw)) {
+		dev_err(dev, "failed to get role switch\n");
+		return PTR_ERR(info->role_sw);
+	}
+
+	of_node_put(child);
+	of_node_put(parent);
+
+	if (info->id_gpiod) {
+		info->id_irq = gpiod_to_irq(info->id_gpiod);
+		if (info->id_irq < 0) {
+			dev_err(dev, "failed to get ID IRQ\n");
+			return info->id_irq;
+		}
+
+		ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
+						usb_conn_isr, USB_CONN_IRQF,
+						pdev->name, info);
+		if (ret < 0) {
+			dev_err(dev, "failed to request ID IRQ\n");
+			return ret;
+		}
+	}
+
+	if (info->vbus_gpiod) {
+		info->vbus_irq = gpiod_to_irq(info->vbus_gpiod);
+		if (info->vbus_irq < 0) {
+			dev_err(dev, "failed to get VBUS IRQ\n");
+			return info->vbus_irq;
+		}
+
+		ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
+						usb_conn_isr, USB_CONN_IRQF,
+						pdev->name, info);
+		if (ret < 0) {
+			dev_err(dev, "failed to request VBUS IRQ\n");
+			return ret;
+		}
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	/* Perform initial detection */
+	usb_conn_queue_dwork(info, 0);
+
+	return 0;
+}
+
+static int usb_conn_remove(struct platform_device *pdev)
+{
+	struct usb_conn_info *info = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&info->dw_det);
+
+	if (info->last_role == USB_ROLE_HOST)
+		regulator_disable(info->vbus);
+
+	usb_role_switch_put(info->role_sw);
+
+	return 0;
+}
+
+static int __maybe_unused usb_conn_suspend(struct device *dev)
+{
+	struct usb_conn_info *info = dev_get_drvdata(dev);
+
+	if (info->id_gpiod)
+		disable_irq(info->id_irq);
+	if (info->vbus_gpiod)
+		disable_irq(info->vbus_irq);
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int __maybe_unused usb_conn_resume(struct device *dev)
+{
+	struct usb_conn_info *info = dev_get_drvdata(dev);
+
+	pinctrl_pm_select_default_state(dev);
+
+	if (info->id_gpiod)
+		enable_irq(info->id_irq);
+	if (info->vbus_gpiod)
+		enable_irq(info->vbus_irq);
+
+	usb_conn_queue_dwork(info, 0);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(usb_conn_pm_ops,
+			 usb_conn_suspend, usb_conn_resume);
+
+#define DEV_PMS_OPS (IS_ENABLED(CONFIG_PM_SLEEP) ? &usb_conn_pm_ops : NULL)
+
+static const struct of_device_id usb_conn_dt_match[] = {
+	{ .compatible = "linux,typeb-conn-gpio", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, usb_conn_dt_match);
+
+static struct platform_driver usb_conn_driver = {
+	.probe		= usb_conn_probe,
+	.remove		= usb_conn_remove,
+	.driver		= {
+		.name	= "typeb-conn-gpio",
+		.pm	= DEV_PMS_OPS,
+		.of_match_table = usb_conn_dt_match,
+	},
+};
+
+module_platform_driver(usb_conn_driver);
+
+MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
+MODULE_DESCRIPTION("USB Type-B GPIO connector driver");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


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

* [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode
  2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
                   ` (4 preceding siblings ...)
  2019-04-03  2:09 ` [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver Chunfeng Yun
@ 2019-04-03  2:09 ` Chunfeng Yun
  2019-04-10 10:24   ` Heikki Krogerus
  5 siblings, 1 reply; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-03  2:09 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus
  Cc: Mark Rutland, Chunfeng Yun, Matthias Brugger, Adam Thomson,
	Li Jun, Badhri Jagan Sridharan, Hans de Goede, Andy Shevchenko,
	Min Guo, Alan Stern, devicetree, linux-kernel, linux-usb,
	linux-arm-kernel, linux-mediatek

Because extcon is not allowed for new bindings, and the
dual role switch is supported by USB Role Switch,
especially for Type-C drivers, so register a USB Role
Switch to support the new way

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
v3 changes:
  1. select USB_ROLE_SWITCH in Kconfig suggested by Heikki
  2. rename ssusb_mode_manual_switch() to ssusb_mode_switch()

v2 no change
---
 drivers/usb/mtu3/Kconfig        |  1 +
 drivers/usb/mtu3/mtu3.h         |  5 ++++
 drivers/usb/mtu3/mtu3_debugfs.c |  4 +--
 drivers/usb/mtu3/mtu3_dr.c      | 47 ++++++++++++++++++++++++++++++++-
 drivers/usb/mtu3/mtu3_dr.h      |  6 ++---
 drivers/usb/mtu3/mtu3_plat.c    |  3 ++-
 6 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index bcc23486c4ed..88e3db7b3016 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -43,6 +43,7 @@ config USB_MTU3_DUAL_ROLE
 	bool "Dual Role mode"
 	depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
 	depends on (EXTCON=y || EXTCON=USB_MTU3)
+	select USB_ROLE_SWITCH
 	help
 	  This is the default mode of working of MTU3 controller where
 	  both host and gadget features are enabled.
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 76ecf12fdf62..6087be236a35 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -199,6 +199,9 @@ struct mtu3_gpd_ring {
 * @id_nb : notifier for iddig(idpin) detection
 * @id_work : work of iddig detection notifier
 * @id_event : event of iddig detecion notifier
+* @role_sw : use USB Role Switch to support dual-role switch, can't use
+*		extcon at the same time, and extcon is deprecated.
+* @role_sw_used : true when the USB Role Switch is used.
 * @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
 * @manual_drd_enabled: it's true when supports dual-role device by debugfs
 *		to switch host/device modes depending on user input.
@@ -212,6 +215,8 @@ struct otg_switch_mtk {
 	struct notifier_block id_nb;
 	struct work_struct id_work;
 	unsigned long id_event;
+	struct usb_role_switch *role_sw;
+	bool role_sw_used;
 	bool is_u3_drd;
 	bool manual_drd_enabled;
 };
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index 62c57ddc554e..c96e5dab0a48 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -453,9 +453,9 @@ static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
 		return -EFAULT;
 
 	if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
-		ssusb_mode_manual_switch(ssusb, 1);
+		ssusb_mode_switch(ssusb, 1);
 	} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
-		ssusb_mode_manual_switch(ssusb, 0);
+		ssusb_mode_switch(ssusb, 0);
 	} else {
 		dev_err(ssusb->dev, "wrong or duplicated setting\n");
 		return -EINVAL;
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 5fcb71af875a..5f20141dd57f 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -7,6 +7,8 @@
  * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
  */
 
+#include <linux/usb/role.h>
+
 #include "mtu3.h"
 #include "mtu3_dr.h"
 #include "mtu3_debug.h"
@@ -280,7 +282,7 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
  * This is useful in special cases, such as uses TYPE-A receptacle but also
  * wants to support dual-role mode.
  */
-void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
+void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
 {
 	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
 
@@ -318,6 +320,46 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
 	mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
 }
 
+static int ssusb_role_sw_set(struct device *dev, enum usb_role role)
+{
+	struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
+	bool to_host = false;
+
+	if (role == USB_ROLE_HOST)
+		to_host = true;
+
+	if (to_host ^ ssusb->is_host)
+		ssusb_mode_switch(ssusb, to_host);
+
+	return 0;
+}
+
+static enum usb_role ssusb_role_sw_get(struct device *dev)
+{
+	struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
+	enum usb_role role;
+
+	role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+
+	return role;
+}
+
+static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
+{
+	struct usb_role_switch_desc role_sx_desc = { 0 };
+	struct ssusb_mtk *ssusb =
+		container_of(otg_sx, struct ssusb_mtk, otg_switch);
+
+	if (!otg_sx->role_sw_used)
+		return 0;
+
+	role_sx_desc.set = ssusb_role_sw_set;
+	role_sx_desc.get = ssusb_role_sw_get;
+	otg_sx->role_sw = usb_role_switch_register(ssusb->dev, &role_sx_desc);
+
+	return PTR_ERR_OR_ZERO(otg_sx->role_sw);
+}
+
 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
 {
 	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
@@ -328,6 +370,8 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
 
 	if (otg_sx->manual_drd_enabled)
 		ssusb_dr_debugfs_init(ssusb);
+	else if (otg_sx->role_sw_used)
+		ret = ssusb_role_sw_register(otg_sx);
 	else
 		ret = ssusb_extcon_register(otg_sx);
 
@@ -340,4 +384,5 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
 
 	cancel_work_sync(&otg_sx->id_work);
 	cancel_work_sync(&otg_sx->vbus_work);
+	usb_role_switch_unregister(otg_sx->role_sw);
 }
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index ba6fe357ce29..5e58c4dbd54a 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -71,7 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
 #if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
 void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
-void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host);
+void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host);
 int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
 void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
 			  enum mtu3_dr_force_mode mode);
@@ -86,8 +86,8 @@ static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
 static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
 {}
 
-static inline void
-ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) {}
+static inline void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
+{}
 
 static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
 {
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index fd0f6c5dfbc1..9c256ea3cdf5 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -299,8 +299,9 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
 	otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
 	otg_sx->manual_drd_enabled =
 		of_property_read_bool(node, "enable-manual-drd");
+	otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch");
 
-	if (of_property_read_bool(node, "extcon")) {
+	if (!otg_sx->role_sw_used && of_property_read_bool(node, "extcon")) {
 		otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
 		if (IS_ERR(otg_sx->edev)) {
 			dev_err(ssusb->dev, "couldn't get extcon device\n");
-- 
2.20.1


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

* Re: [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver
  2019-04-03  2:09 ` [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver Chunfeng Yun
@ 2019-04-04 16:35   ` Linus Walleij
  2019-04-08  8:14     ` Chunfeng Yun
  0 siblings, 1 reply; 13+ messages in thread
From: Linus Walleij @ 2019-04-04 16:35 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus, Mark Rutland,
	Matthias Brugger, Adam Thomson, Li Jun, Badhri Jagan Sridharan,
	Hans de Goede, Andy Shevchenko, Min Guo, Alan Stern,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel, linux-usb, Linux ARM,
	moderated list:ARM/Mediatek SoC support

On Wed, Apr 3, 2019 at 9:09 AM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:

> Due to the requirement of usb-connector.txt binding, the old way
> using extcon to support USB Dual-Role switch is now deprecated
> when use Type-B connector.
> This patch introduces a driver of Type-B connector which typically
> uses an input GPIO to detect USB ID pin, and try to replace the
> function provided by extcon-usb-gpio driver
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
(...)
> +#include <linux/gpio.h>

If you need this include in a consumer, something is wrong. Just delete it,

> +       info->id_gpiod = devm_gpiod_get_from_of_node(
> +                               dev, child, "id-gpios", 0, GPIOD_IN, "idpin");

This is OK if the child does not have any Linux device (struct platform_device
etc) created from it. Is this the case?

Yours,
Linus Walleij

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

* Re: [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver
  2019-04-04 16:35   ` Linus Walleij
@ 2019-04-08  8:14     ` Chunfeng Yun
  0 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-08  8:14 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Greg Kroah-Hartman, Heikki Krogerus, Mark Rutland,
	Matthias Brugger, Adam Thomson, Li Jun, Badhri Jagan Sridharan,
	Hans de Goede, Andy Shevchenko, Min Guo, Alan Stern,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel, linux-usb, Linux ARM,
	moderated list:ARM/Mediatek SoC support

Hi,
On Thu, 2019-04-04 at 23:35 +0700, Linus Walleij wrote:
> On Wed, Apr 3, 2019 at 9:09 AM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
> 
> > Due to the requirement of usb-connector.txt binding, the old way
> > using extcon to support USB Dual-Role switch is now deprecated
> > when use Type-B connector.
> > This patch introduces a driver of Type-B connector which typically
> > uses an input GPIO to detect USB ID pin, and try to replace the
> > function provided by extcon-usb-gpio driver
> >
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> (...)
> > +#include <linux/gpio.h>
> 
> If you need this include in a consumer, something is wrong. Just delete it,
Ok
> 
> > +       info->id_gpiod = devm_gpiod_get_from_of_node(
> > +                               dev, child, "id-gpios", 0, GPIOD_IN, "idpin");
> 
> This is OK if the child does not have any Linux device (struct platform_device
> etc) created from it. Is this the case?
Yes, it is.

Thanks

> 
> Yours,
> Linus Walleij



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

* Re: [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node
  2019-04-03  2:09 ` [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node Chunfeng Yun
@ 2019-04-10 10:22   ` Heikki Krogerus
  2019-04-11  3:11     ` Chunfeng Yun
  0 siblings, 1 reply; 13+ messages in thread
From: Heikki Krogerus @ 2019-04-10 10:22 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: Rob Herring, Greg Kroah-Hartman, Mark Rutland, Matthias Brugger,
	Adam Thomson, Li Jun, Badhri Jagan Sridharan, Hans de Goede,
	Andy Shevchenko, Min Guo, Alan Stern, devicetree, linux-kernel,
	linux-usb, linux-arm-kernel, linux-mediatek

On Wed, Apr 03, 2019 at 10:09:12AM +0800, Chunfeng Yun wrote:
> Add fwnode_usb_role_switch_get() to make easier to get
> usb_role_switch by fwnode which register it.
> It's useful when there is not device_connection registered
> between two drivers and only knows the fwnode which register
> usb_role_switch.
> 
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> v3 changes:
>   1. use fwnodes instead of node suggested by Andy
>   2. rebuild the API suggested by Heikki
> 
> v2 no changes
> ---
>  drivers/usb/roles/class.c | 31 +++++++++++++++++++++++++++++++
>  include/linux/usb/role.h  |  2 ++
>  2 files changed, 33 insertions(+)
> 
> diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
> index f45d8df5cfb8..5ecb57f8960b 100644
> --- a/drivers/usb/roles/class.c
> +++ b/drivers/usb/roles/class.c
> @@ -12,6 +12,7 @@
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/mutex.h>
> +#include <linux/of.h>
>  #include <linux/slab.h>
>  
>  static struct class *role_class;
> @@ -135,6 +136,36 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(usb_role_switch_get);
>  
> +static int __switch_match_fwnode(struct device *dev, const void *fwnode)
> +{
> +	return dev_fwnode(dev->parent) == (const struct fwnode_handle *)fwnode;
> +}

I don't think this is actually needed. Why not just assign the
parent's fwnode for the mux as well?

I'll add an example to the patch 6/6 in this series.

> +/**
> + * fwnode_usb_role_switch_get - Find USB role switch by it's parent fwnode
> + * @fwnode: The fwnode that register USB role switch
> + *
> + * Finds and returns role switch registered by @fwnode. The reference count
> + * for the found switch is incremented.
> + */
> +struct usb_role_switch *
> +fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
> +{
> +	struct usb_role_switch *sw;
> +	struct device *dev;
> +
> +	dev = class_find_device(role_class, NULL, fwnode,
> +				__switch_match_fwnode);

So here you can then reuse switch_fwnode_match():

	dev = class_find_device(role_class, NULL, fwnode, switch_fwnode_match);

> +	if (!dev)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	sw = to_role_switch(dev);
> +	WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
> +
> +	return sw;
> +}
> +EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
> +
>  /**
>   * usb_role_switch_put - Release handle to a switch
>   * @sw: USB Role Switch
> diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
> index c05ffa6abda9..d21cd55d9e45 100644
> --- a/include/linux/usb/role.h
> +++ b/include/linux/usb/role.h
> @@ -46,6 +46,8 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role);
>  enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw);
>  struct usb_role_switch *usb_role_switch_get(struct device *dev);
>  void usb_role_switch_put(struct usb_role_switch *sw);
> +struct usb_role_switch *
> +fwnode_usb_role_switch_get(struct fwnode_handle *fwnode);
>  
>  struct usb_role_switch *
>  usb_role_switch_register(struct device *parent,
> -- 
> 2.20.1

thanks,

-- 
heikki

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

* Re: [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode
  2019-04-03  2:09 ` [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode Chunfeng Yun
@ 2019-04-10 10:24   ` Heikki Krogerus
  2019-04-11  1:05     ` Chunfeng Yun
  0 siblings, 1 reply; 13+ messages in thread
From: Heikki Krogerus @ 2019-04-10 10:24 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: Rob Herring, Greg Kroah-Hartman, Mark Rutland, Matthias Brugger,
	Adam Thomson, Li Jun, Badhri Jagan Sridharan, Hans de Goede,
	Andy Shevchenko, Min Guo, Alan Stern, devicetree, linux-kernel,
	linux-usb, linux-arm-kernel, linux-mediatek

On Wed, Apr 03, 2019 at 10:09:14AM +0800, Chunfeng Yun wrote:
> +static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
> +{
> +	struct usb_role_switch_desc role_sx_desc = { 0 };
> +	struct ssusb_mtk *ssusb =
> +		container_of(otg_sx, struct ssusb_mtk, otg_switch);
> +
> +	if (!otg_sx->role_sw_used)
> +		return 0;
> +
> +	role_sx_desc.set = ssusb_role_sw_set;
> +	role_sx_desc.get = ssusb_role_sw_get;

        role_sw_desc.fwnode = dev_fwnode(ssusb->dev);

> +	otg_sx->role_sw = usb_role_switch_register(ssusb->dev, &role_sx_desc);
> +
> +	return PTR_ERR_OR_ZERO(otg_sx->role_sw);
> +}

thanks,

-- 
heikki

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

* Re: [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode
  2019-04-10 10:24   ` Heikki Krogerus
@ 2019-04-11  1:05     ` Chunfeng Yun
  0 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-11  1:05 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Rob Herring, Greg Kroah-Hartman, Mark Rutland, Matthias Brugger,
	Adam Thomson, Li Jun, Badhri Jagan Sridharan, Hans de Goede,
	Andy Shevchenko, Min Guo, Alan Stern, devicetree, linux-kernel,
	linux-usb, linux-arm-kernel, linux-mediatek

On Wed, 2019-04-10 at 13:24 +0300, Heikki Krogerus wrote:
> On Wed, Apr 03, 2019 at 10:09:14AM +0800, Chunfeng Yun wrote:
> > +static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
> > +{
> > +	struct usb_role_switch_desc role_sx_desc = { 0 };
> > +	struct ssusb_mtk *ssusb =
> > +		container_of(otg_sx, struct ssusb_mtk, otg_switch);
> > +
> > +	if (!otg_sx->role_sw_used)
> > +		return 0;
> > +
> > +	role_sx_desc.set = ssusb_role_sw_set;
> > +	role_sx_desc.get = ssusb_role_sw_get;
> 
>         role_sw_desc.fwnode = dev_fwnode(ssusb->dev);
Ok, thanks

> 
> > +	otg_sx->role_sw = usb_role_switch_register(ssusb->dev, &role_sx_desc);
> > +
> > +	return PTR_ERR_OR_ZERO(otg_sx->role_sw);
> > +}
> 
> thanks,
> 



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

* Re: [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node
  2019-04-10 10:22   ` Heikki Krogerus
@ 2019-04-11  3:11     ` Chunfeng Yun
  0 siblings, 0 replies; 13+ messages in thread
From: Chunfeng Yun @ 2019-04-11  3:11 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Rob Herring, Greg Kroah-Hartman, Mark Rutland, Matthias Brugger,
	Adam Thomson, Li Jun, Badhri Jagan Sridharan, Hans de Goede,
	Andy Shevchenko, Min Guo, Alan Stern, devicetree, linux-kernel,
	linux-usb, linux-arm-kernel, linux-mediatek

On Wed, 2019-04-10 at 13:22 +0300, Heikki Krogerus wrote:
> On Wed, Apr 03, 2019 at 10:09:12AM +0800, Chunfeng Yun wrote:
> > Add fwnode_usb_role_switch_get() to make easier to get
> > usb_role_switch by fwnode which register it.
> > It's useful when there is not device_connection registered
> > between two drivers and only knows the fwnode which register
> > usb_role_switch.
> > 
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> > v3 changes:
> >   1. use fwnodes instead of node suggested by Andy
> >   2. rebuild the API suggested by Heikki
> > 
> > v2 no changes
> > ---
> >  drivers/usb/roles/class.c | 31 +++++++++++++++++++++++++++++++
> >  include/linux/usb/role.h  |  2 ++
> >  2 files changed, 33 insertions(+)
> > 
> > diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
> > index f45d8df5cfb8..5ecb57f8960b 100644
> > --- a/drivers/usb/roles/class.c
> > +++ b/drivers/usb/roles/class.c
> > @@ -12,6 +12,7 @@
> >  #include <linux/device.h>
> >  #include <linux/module.h>
> >  #include <linux/mutex.h>
> > +#include <linux/of.h>
> >  #include <linux/slab.h>
> >  
> >  static struct class *role_class;
> > @@ -135,6 +136,36 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
> >  }
> >  EXPORT_SYMBOL_GPL(usb_role_switch_get);
> >  
> > +static int __switch_match_fwnode(struct device *dev, const void *fwnode)
> > +{
> > +	return dev_fwnode(dev->parent) == (const struct fwnode_handle *)fwnode;
> > +}
> 
> I don't think this is actually needed. 
Yes, you are right

> Why not just assign the
> parent's fwnode for the mux as well?
will do it in next version

> 
> I'll add an example to the patch 6/6 in this series.
> 
> > +/**
> > + * fwnode_usb_role_switch_get - Find USB role switch by it's parent fwnode
> > + * @fwnode: The fwnode that register USB role switch
> > + *
> > + * Finds and returns role switch registered by @fwnode. The reference count
> > + * for the found switch is incremented.
> > + */
> > +struct usb_role_switch *
> > +fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
> > +{
> > +	struct usb_role_switch *sw;
> > +	struct device *dev;
> > +
> > +	dev = class_find_device(role_class, NULL, fwnode,
> > +				__switch_match_fwnode);
> 
> So here you can then reuse switch_fwnode_match():
> 
> 	dev = class_find_device(role_class, NULL, fwnode, switch_fwnode_match);
I make a fast test, it works, thanks a lot Heikki

> 
> > +	if (!dev)
> > +		return ERR_PTR(-EPROBE_DEFER);
> > +
> > +	sw = to_role_switch(dev);
> > +	WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
> > +
> > +	return sw;
> > +}
> > +EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
> > +
> >  /**
> >   * usb_role_switch_put - Release handle to a switch
> >   * @sw: USB Role Switch
> > diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
> > index c05ffa6abda9..d21cd55d9e45 100644
> > --- a/include/linux/usb/role.h
> > +++ b/include/linux/usb/role.h
> > @@ -46,6 +46,8 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role);
> >  enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw);
> >  struct usb_role_switch *usb_role_switch_get(struct device *dev);
> >  void usb_role_switch_put(struct usb_role_switch *sw);
> > +struct usb_role_switch *
> > +fwnode_usb_role_switch_get(struct fwnode_handle *fwnode);
> >  
> >  struct usb_role_switch *
> >  usb_role_switch_register(struct device *parent,
> > -- 
> > 2.20.1
> 
> thanks,
> 



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

end of thread, other threads:[~2019-04-11  3:11 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-03  2:09 [v3 PATCH 0/6] add USB Type-B GPIO connector driver Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 1/6] dt-bindings: connector: add optional properties for Type-B Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 2/6] dt-bindings: usb: add binding for Type-B GPIO connector driver Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 3/6] dt-bindings: usb: mtu3: add properties about USB Role Switch Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 4/6] usb: roles: add API to get usb_role_switch by node Chunfeng Yun
2019-04-10 10:22   ` Heikki Krogerus
2019-04-11  3:11     ` Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 5/6] usb: roles: add USB Type-B GPIO connector driver Chunfeng Yun
2019-04-04 16:35   ` Linus Walleij
2019-04-08  8:14     ` Chunfeng Yun
2019-04-03  2:09 ` [v3 PATCH 6/6] usb: mtu3: register a USB Role Switch for dual role mode Chunfeng Yun
2019-04-10 10:24   ` Heikki Krogerus
2019-04-11  1:05     ` Chunfeng Yun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).