linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/13]  USB: OTG/DRD Core functionality
@ 2015-08-24 13:21 Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 01/13] usb: otg-fsm: Add documentation for struct otg_fsm Roger Quadros
                   ` (15 more replies)
  0 siblings, 16 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

Hi,

This series centralizes OTG/Dual-role functionality in the kernel.
As of now I've got Dual-role functionality working pretty reliably on
dra7-evm and am437x-gp-evm.

DWC3 controller and platform related patches will be sent separately.

Series is based on Greg's usb-next tree.

Changelog:
---------
v4:
- Added DT support for tying otg-controller to host and gadget
 controllers. For DT we no longer have the constraint that
 OTG controller needs to be parent of host and gadget. They can be
 tied together using the "otg-controller" property.
- Relax the requirement for DT case that otg controller must register before
 host/gadget. We maintain a wait list of host/gadget devices
 waiting on the otg controller.
- Use a single struct usb_otg for otg data.
- Don't override host/gadget start/stop APIs. Let the controller
 drivers do what they want as they know best. Helper API is provided
 for controller start/stop that controller driver can use.
- Introduce struct usb_otg_config to pass the otg capabilities,
 otg ops and otg timer timeouts during otg controller registration.
- rebased on Greg's usb.git/usb-next

v3:
- all otg related definations now in otg.h
- single kernel config USB_OTG to enable OTG core and FSM.
- resolved symbol dependency issues.
- use dev_vdbg instead of VDBG() in usb-otg-fsm.c
- rebased on v4.2-rc1

v2:
- Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
 the host controller
- added dual-role-device (DRD) state machine which is a much simpler
 mode of operation when compared to OTG. Here we don't support fancy
 OTG features like HNP, SRP, on the fly role-swap. The mode of operation
 is determined based on ID pin (cable type) and the role doesn't change
 till the cable type changes.

Why?:
----

Most of the OTG drivers have been dealing with the OTG state machine
themselves and there is a scope for code re-use. This has been
partly addressed by the usb/common/usb-otg-fsm.c but it still
leaves the instantiation of the state machine and OTG timers
to the controller drivers. We re-use usb-otg-fsm.c but
go one step further by instantiating the state machine and timers
thus making it easier for drivers to implement OTG functionality.

Newer OTG cores support standard host interface (e.g. xHCI) so
host and gadget functionality are no longer closely knit like older
cores. There needs to be a way to co-ordinate the operation of the
host and gadget in OTG mode. i.e. to stop and start them from a
central location. This central location should be the USB OTG core.

Host and gadget controllers might be sharing resources and can't
be always running. One has to be stopped for the other to run.
This can't be done as of now and can be done from the OTG core.

What?:
-----

The OTG core instantiates the OTG/DRD Finite State Machine
per OTG controller and manages starting/stopping the
host and gadget controllers based on the bus state.
    
It provides APIs for the following
    
- Registering an OTG capable controller
struct otg_fsm *usb_otg_register(struct device *dev,
                                 struct usb_otg_config *config);

int usb_otg_unregister(struct device *dev);

- Registering Host controllers to OTG core (used by hcd-core)
int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
                         unsigned long irqflags, struct otg_hcd_ops *ops);
int usb_otg_unregister_hcd(struct usb_hcd *hcd);


- Registering Gadget controllers to OTG core (used by udc-core)
int usb_otg_register_gadget(struct usb_gadget *gadget,
                            struct otg_gadget_ops *ops);
int usb_otg_unregister_gadget(struct usb_gadget *gadget);


- Providing inputs to and kicking the OTG state machine
void usb_otg_sync_inputs(struct otg_fsm *fsm);
int usb_otg_kick_fsm(struct device *hcd_gcd_device);

- Getting controller device structure from OTG state machine instance
struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);

'struct otg_fsm' is the interface to the OTG state machine.
It contains inputs to the fsm, status of the fsm and operations
for the OTG controller driver.

- Helper APIs for starting/stopping host/gadget controllers
int usb_otg_start_host(struct otg_fsm *fsm, int on);
int usb_otg_start_gadget(struct otg_fsm *fsm, int on);

Usage model:
-----------

- The OTG core needs to know what host and gadget controllers are
linked to the OTG controller. For DT boots we can provide that
information by adding "otg-controller" property to the host and
gadget controller nodes that points to the right otg controller.
For legacy boot we assume that OTG controller is the parent
of the host and gadget controllers. For DT if "otg-controller"
property is not present then parent child relationship constraint
applies.

- The OTG controller driver must call usb_otg_register() to register
itself with the OTG core. It must also provide the required
OTG configuration, fsm operations and timer timeouts (optional)
via struct usb_otg_config. The fsm operations will be called
depending on the OTG bus state.

- The host/gadget core stacks are modified to inform the OTG core
whenever a new host/gadget device is added. The OTG core then
checks if the host/gadget is part of the OTG controller and if yes
then prevents the host/gadget from starting till both host and
gadget are registered, OTG state machine is running and the
USB bus state is appropriate to start host/gadget.
For this, APIs have been added to host/gadget stacks to start/stop
the controllers from the OTG core.
For DT boots, If the OTG controller hasn't yet been registered
while the host/gadget are added, the OTG core will hold it in a wait list
and register them when the OTG controller registers.

- No modification is needed for the host/gadget controller drivers.
They must ensure that their start/stop methods can be called repeatedly
and any shared resources between host & gadget are properly managed.
The OTG core ensures that both are not started simultaneously.

- The OTG core instantiates one OTG state machine per OTG controller
and the necessary OTG timers to manage OTG state timeouts.
If none of the otg features are set during usb_otg_register() then it
instanciates a DRD (dual-role device) state machine instead.
The state machine is started when both host & gadget register and
stopped when either of them unregisters. The controllers are started
and stopped depending on bus state.

- During the lifetime of the OTG state machine, inputs can be
provided to it by modifying the appropriate members of 'struct otg_fsm'
and calling usb_otg_sync_inputs(). This is typically done by the
OTG controller driver that called usb_otg_register().

--
cheers,
-roger

Roger Quadros (13):
  usb: otg-fsm: Add documentation for struct otg_fsm
  usb: otg-fsm: support multiple instances
  usb: otg-fsm: Prevent build warning "VDBG" redefined
  otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  usb: hcd.h: Add OTG to HCD interface
  usb: gadget.h: Add OTG to gadget interface
  usb: otg: add OTG core
  usb: doc: dt-binding: Add otg-controller property
  usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
  usb: hcd: Adapt to OTG core
  usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
  usb: gadget: udc: adapt to OTG core
  usb: otg: Add dual-role device (DRD) support

 Documentation/devicetree/bindings/usb/generic.txt |    5 +
 Documentation/usb/chipidea.txt                    |    2 +-
 MAINTAINERS                                       |    4 +-
 drivers/usb/Kconfig                               |    2 +-
 drivers/usb/Makefile                              |    1 +
 drivers/usb/chipidea/Makefile                     |    2 +-
 drivers/usb/chipidea/ci.h                         |    2 +-
 drivers/usb/chipidea/otg_fsm.c                    |    1 +
 drivers/usb/chipidea/otg_fsm.h                    |    2 +-
 drivers/usb/common/Makefile                       |    3 +-
 drivers/usb/common/usb-otg-fsm.c                  |   26 +-
 drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
 drivers/usb/common/usb-otg.h                      |   71 ++
 drivers/usb/core/Kconfig                          |   11 +-
 drivers/usb/core/hcd.c                            |   55 +-
 drivers/usb/core/hub.c                            |   10 +-
 drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
 drivers/usb/phy/Kconfig                           |    2 +-
 drivers/usb/phy/phy-fsl-usb.c                     |    3 +
 include/linux/usb/gadget.h                        |   14 +
 include/linux/usb/hcd.h                           |   14 +
 include/linux/usb/otg-fsm.h                       |  116 +-
 include/linux/usb/otg.h                           |  191 +++-
 23 files changed, 1808 insertions(+), 76 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c
 create mode 100644 drivers/usb/common/usb-otg.h

-- 
2.1.4


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

* [PATCH v4 01/13] usb: otg-fsm: Add documentation for struct otg_fsm
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 02/13] usb: otg-fsm: support multiple instances Roger Quadros
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

struct otg_fsm is the interface to the OTG state machine.

Document the input, output and internal state variables.
Definations are taken from Table 7-2 and Table 7-4 of
the USB OTG & EH Specification Rev.2.0

Re-arrange some of the members as per use case for more
clarity.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@freescale.com>
---
 include/linux/usb/otg-fsm.h | 90 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 83 insertions(+), 7 deletions(-)

diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index f728f18..fc5b4d9 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -59,37 +59,113 @@ enum otg_fsm_timer {
 	NUM_OTG_FSM_TIMERS,
 };
 
-/* OTG state machine according to the OTG spec */
+/**
+ * struct otg_fsm - OTG state machine according to the OTG spec
+ *
+ * OTG hardware Inputs
+ *
+ *	Common inputs for A and B device
+ * @id:		TRUE for B-device, FALSE for A-device.
+ * @adp_change: TRUE when current ADP measurement (n) value, compared to the
+ *		ADP measurement taken at n-2, differs by more than CADP_THR
+ * @power_up:	TRUE when the OTG device first powers up its USB system and
+ *		ADP measurement taken if ADP capable
+ *
+ *	A-Device state inputs
+ * @a_srp_det:	TRUE if the A-device detects SRP
+ * @a_vbus_vld:	TRUE when VBUS voltage is in regulation
+ * @b_conn:	TRUE if the A-device detects connection from the B-device
+ * @a_bus_resume: TRUE when the B-device detects that the A-device is signaling
+ *		  a resume (K state)
+ *	B-Device state inputs
+ * @a_bus_suspend: TRUE when the B-device detects that the A-device has put the
+ *		bus into suspend
+ * @a_conn:	TRUE if the B-device detects a connection from the A-device
+ * @b_se0_srp:	TRUE when the line has been at SE0 for more than the minimum
+ *		time before generating SRP
+ * @b_ssend_srp: TRUE when the VBUS has been below VOTG_SESS_VLD for more than
+ *		 the minimum time before generating SRP
+ * @b_sess_vld:	TRUE when the B-device detects that the voltage on VBUS is
+ *		above VOTG_SESS_VLD
+ * @test_device: TRUE when the B-device switches to B-Host and detects an OTG
+ *		test device. This must be set by host/hub driver
+ *
+ *	Application inputs (A-Device)
+ * @a_bus_drop:	TRUE when A-device application needs to power down the bus
+ * @a_bus_req:	TRUE when A-device application wants to use the bus.
+ *		FALSE to suspend the bus
+ *
+ *	Application inputs (B-Device)
+ * @b_bus_req:	TRUE during the time that the Application running on the
+ *		B-device wants to use the bus
+ *
+ *	Auxilary inputs (OTG v1.3 only. Obsolete now.)
+ * @a_sess_vld:	TRUE if the A-device detects that VBUS is above VA_SESS_VLD
+ * @b_bus_suspend: TRUE when the A-device detects that the B-device has put
+ *		the bus into suspend
+ * @b_bus_resume: TRUE when the A-device detects that the B-device is signaling
+ *		 resume on the bus
+ *
+ * OTG Output status. Read only for users. Updated by OTG FSM helpers defined
+ * in this file
+ *
+ *	Outputs for Both A and B device
+ * @drv_vbus:	TRUE when A-device is driving VBUS
+ * @loc_conn:	TRUE when the local device has signaled that it is connected
+ *		to the bus
+ * @loc_sof:	TRUE when the local device is generating activity on the bus
+ * @adp_prb:	TRUE when the local device is in the process of doing
+ *		ADP probing
+ *
+ *	Outputs for B-device state
+ * @adp_sns:	TRUE when the B-device is in the process of carrying out
+ *		ADP sensing
+ * @data_pulse: TRUE when the B-device is performing data line pulsing
+ *
+ * Internal Variables
+ *
+ * a_set_b_hnp_en: TRUE when the A-device has successfully set the
+ *		b_hnp_enable bit in the B-device.
+ *		   Unused as OTG fsm uses otg->host->b_hnp_enable instead
+ * b_srp_done:	TRUE when the B-device has completed initiating SRP
+ * b_hnp_enable: TRUE when the B-device has accepted the
+ *		SetFeature(b_hnp_enable) B-device.
+ *		Unused as OTG fsm uses otg->gadget->b_hnp_enable instead
+ * a_clr_err:	Asserted (by application ?) to clear a_vbus_err due to an
+ *		overcurrent condition and causes the A-device to transition
+ *		to a_wait_vfall
+ */
 struct otg_fsm {
 	/* Input */
 	int id;
 	int adp_change;
 	int power_up;
-	int test_device;
-	int a_bus_drop;
-	int a_bus_req;
 	int a_srp_det;
 	int a_vbus_vld;
 	int b_conn;
 	int a_bus_resume;
 	int a_bus_suspend;
 	int a_conn;
-	int b_bus_req;
 	int b_se0_srp;
 	int b_ssend_srp;
 	int b_sess_vld;
+	int test_device;
+	int a_bus_drop;
+	int a_bus_req;
+	int b_bus_req;
+
 	/* Auxilary inputs */
 	int a_sess_vld;
 	int b_bus_resume;
 	int b_bus_suspend;
 
 	/* Output */
-	int data_pulse;
 	int drv_vbus;
 	int loc_conn;
 	int loc_sof;
 	int adp_prb;
 	int adp_sns;
+	int data_pulse;
 
 	/* Internal variables */
 	int a_set_b_hnp_en;
@@ -97,7 +173,7 @@ struct otg_fsm {
 	int b_hnp_enable;
 	int a_clr_err;
 
-	/* Informative variables */
+	/* Informative variables. All unused as of now */
 	int a_bus_drop_inf;
 	int a_bus_req_inf;
 	int a_clr_err_inf;
-- 
2.1.4


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

* [PATCH v4 02/13] usb: otg-fsm: support multiple instances
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 01/13] usb: otg-fsm: Add documentation for struct otg_fsm Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-09-06  5:52   ` Peter Chen
  2015-08-24 13:21 ` [PATCH v4 03/13] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

Move the state_changed variable into struct otg_fsm
so that we can support multiple instances.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/common/usb-otg-fsm.c | 10 ++++------
 include/linux/usb/otg-fsm.h      |  1 +
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 61d538a..32862a4 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 	return 0;
 }
 
-static int state_changed;
-
 /* Called when leaving a state.  Do state clean up jobs here */
 static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 {
@@ -123,7 +121,6 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 /* Called when entering a state */
 static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 {
-	state_changed = 1;
 	if (fsm->otg->state == new_state)
 		return 0;
 	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
@@ -237,6 +234,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 	}
 
 	fsm->otg->state = new_state;
+	fsm->state_changed = 1;
 	return 0;
 }
 
@@ -248,7 +246,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 	mutex_lock(&fsm->lock);
 
 	state = fsm->otg->state;
-	state_changed = 0;
+	fsm->state_changed = 0;
 	/* State machine state change judgement */
 
 	switch (state) {
@@ -361,7 +359,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 	}
 	mutex_unlock(&fsm->lock);
 
-	VDBG("quit statemachine, changed = %d\n", state_changed);
-	return state_changed;
+	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
+	return fsm->state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index fc5b4d9..20c8219 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -195,6 +195,7 @@ struct otg_fsm {
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
 	int protocol;
 	struct mutex lock;
+	bool state_changed;
 };
 
 struct otg_fsm_ops {
-- 
2.1.4


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

* [PATCH v4 03/13] usb: otg-fsm: Prevent build warning "VDBG" redefined
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 01/13] usb: otg-fsm: Add documentation for struct otg_fsm Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 02/13] usb: otg-fsm: support multiple instances Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops Roger Quadros
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

If usb/otg-fsm.h and usb/composite.h are included together
then it results in the build warning [1].

Prevent that by using dev_vdbg() instead.

Also get rid of MPC_LOC which doesn't seem to be used
by anyone.

[1] - warning fixed by this patch:

   In file included from drivers/usb/dwc3/core.h:33,
                    from drivers/usb/dwc3/ep0.c:33:
   include/linux/usb/otg-fsm.h:30:1: warning: "VDBG" redefined
   In file included from drivers/usb/dwc3/ep0.c:31:
   include/linux/usb/composite.h:615:1: warning: this is the location
	of the previous definition

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/otg_fsm.c   |  1 +
 drivers/usb/common/usb-otg-fsm.c | 12 +++++++-----
 drivers/usb/phy/phy-fsl-usb.c    |  1 +
 include/linux/usb/otg-fsm.h      | 19 ++++---------------
 4 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 00ab59d..f644752 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -776,6 +776,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 	ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
 	ci->fsm.otg->state = OTG_STATE_UNDEFINED;
 	ci->fsm.ops = &ci_otg_ops;
+	ci->fsm.dev = ci->dev;
 
 	mutex_init(&ci->fsm.lock);
 
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 32862a4..a46f29a 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -36,8 +36,9 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 	int ret = 0;
 
 	if (fsm->protocol != protocol) {
-		VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
-			fsm->protocol, protocol);
+		dev_vdbg(fsm->dev,
+			 "Changing role fsm->protocol= %d; new protocol= %d\n",
+			 fsm->protocol, protocol);
 		/* stop old protocol */
 		if (fsm->protocol == PROTO_HOST)
 			ret = otg_start_host(fsm, 0);
@@ -123,7 +124,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 {
 	if (fsm->otg->state == new_state)
 		return 0;
-	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
+	dev_vdbg(fsm->dev, "Set state: %s\n", usb_otg_state_string(new_state));
 	otg_leave_state(fsm, fsm->otg->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
@@ -251,7 +252,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 
 	switch (state) {
 	case OTG_STATE_UNDEFINED:
-		VDBG("fsm->id = %d\n", fsm->id);
+		dev_vdbg(fsm->dev, "fsm->id = %d\n", fsm->id);
 		if (fsm->id)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
 		else
@@ -359,7 +360,8 @@ int otg_statemachine(struct otg_fsm *fsm)
 	}
 	mutex_unlock(&fsm->lock);
 
-	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
+	dev_vdbg(fsm->dev, "quit statemachine, changed = %d\n",
+		 fsm->state_changed);
 	return fsm->state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 94eb292..ee3f2c2 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -817,6 +817,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
 
 	/* Set OTG state machine operations */
 	fsl_otg_tc->fsm.ops = &fsl_otg_ops;
+	fsl_otg_tc->fsm.dev = &pdev->dev;
 
 	/* initialize the otg structure */
 	fsl_otg_tc->phy.label = DRIVER_DESC;
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 20c8219..672551c 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -18,24 +18,10 @@
 #ifndef __LINUX_USB_OTG_FSM_H
 #define __LINUX_USB_OTG_FSM_H
 
+#include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/errno.h>
 
-#undef VERBOSE
-
-#ifdef VERBOSE
-#define VDBG(fmt, args...) pr_debug("[%s]  " fmt , \
-				 __func__, ## args)
-#else
-#define VDBG(stuff...)	do {} while (0)
-#endif
-
-#ifdef VERBOSE
-#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__)
-#else
-#define MPC_LOC do {} while (0)
-#endif
-
 #define PROTO_UNDEF	(0)
 #define PROTO_HOST	(1)
 #define PROTO_GADGET	(2)
@@ -196,6 +182,9 @@ struct otg_fsm {
 	int protocol;
 	struct mutex lock;
 	bool state_changed;
+
+	/* for debug prints */
+	struct device *dev;
 };
 
 struct otg_fsm_ops {
-- 
2.1.4


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

* [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (2 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 03/13] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-09-07  1:24   ` Peter Chen
  2015-08-24 13:21 ` [PATCH v4 05/13] usb: hcd.h: Add OTG to HCD interface Roger Quadros
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

This is to prevent missing symbol build error if OTG is
enabled (built-in) and HCD core (CONFIG_USB) is module.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/common/usb-otg-fsm.c | 6 ++++--
 drivers/usb/phy/phy-fsl-usb.c    | 2 ++
 include/linux/usb/otg-fsm.h      | 1 +
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index a46f29a..6e56c8c 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -165,8 +165,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_conn(fsm, 0);
 		otg_loc_sof(fsm, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(fsm->otg->host,
-				fsm->otg->host->otg_port);
+		if (fsm->ops->start_enum) {
+			fsm->ops->start_enum(fsm->otg->host,
+					     fsm->otg->host->otg_port);
+		}
 		break;
 	case OTG_STATE_A_IDLE:
 		otg_drv_vbus(fsm, 0);
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index ee3f2c2..19541ed 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -783,6 +783,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
 
 	.start_host = fsl_otg_start_host,
 	.start_gadget = fsl_otg_start_gadget,
+
+	.start_enum = usb_bus_start_enum,
 };
 
 /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 672551c..75e82cc 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -199,6 +199,7 @@ struct otg_fsm_ops {
 	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
 	int	(*start_host)(struct otg_fsm *fsm, int on);
 	int	(*start_gadget)(struct otg_fsm *fsm, int on);
+	int	(*start_enum)(struct usb_bus *bus, unsigned port_num);
 };
 
 
-- 
2.1.4


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

* [PATCH v4 05/13] usb: hcd.h: Add OTG to HCD interface
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (3 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 06/13] usb: gadget.h: Add OTG to gadget interface Roger Quadros
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The OTG core will use struct otg_hcd_ops to
add/remove the HCD controller.

The main purpose of this interface is to avoid directly
calling usb_add/remove_hcd() from the OTG core as they
wouldn't be defined in the built-in symbol table if
CONFIG_USB is m.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@freescale.com>
---
 include/linux/usb/hcd.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d2784c1..27d78b1 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -386,6 +386,20 @@ struct hc_driver {
 
 };
 
+/**
+ * struct otg_hcd_ops - Interface between OTG core and HCD
+ *
+ * Provided by the HCD core to allow the OTG core to start/stop the HCD
+ *
+ * @add: function to add the HCD
+ * @remove: function to remove the HCD
+ */
+struct otg_hcd_ops {
+	int (*add)(struct usb_hcd *hcd,
+		   unsigned int irqnum, unsigned long irqflags);
+	void (*remove)(struct usb_hcd *hcd);
+};
+
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
 {
 	return hcd->driver->flags & HCD_BH;
-- 
2.1.4


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

* [PATCH v4 06/13] usb: gadget.h: Add OTG to gadget interface
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (4 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 05/13] usb: hcd.h: Add OTG to HCD interface Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The OTG core will use struct otg_gadget_ops to
start/stop the gadget controller.

The main purpose of this interface is to avoid directly
calling usb_gadget_start/stop() from the OTG core as they
wouldn't be defined in the built-in symbol table if
CONFIG_USB_GADGET is m.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@freescale.com>
---
 include/linux/usb/gadget.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index c14a69b..c019242 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -1052,6 +1052,20 @@ struct usb_gadget_driver {
 };
 
 
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct otg_gadget_ops - Interface between OTG core and gadget
+ *
+ * Provided by the gadget core to allow the OTG core to start/stop the gadget
+ *
+ * @start: function to start the gadget
+ * @stop: function to stop the gadget
+ */
+struct otg_gadget_ops {
+	int (*start)(struct usb_gadget *gadget);
+	int (*stop)(struct usb_gadget *gadget);
+};
 
 /*-------------------------------------------------------------------------*/
 
-- 
2.1.4


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

* [PATCH v4 07/13] usb: otg: add OTG core
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (5 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 06/13] usb: gadget.h: Add OTG to gadget interface Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-09-07  1:23   ` Peter Chen
  2015-09-07  7:40   ` Li Jun
  2015-08-24 13:21 ` [PATCH v4 08/13] usb: doc: dt-binding: Add otg-controller property Roger Quadros
                   ` (8 subsequent siblings)
  15 siblings, 2 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The OTG core instantiates the OTG Finite State Machine
per OTG controller and manages starting/stopping the
host and gadget controllers based on the bus state.

It provides APIs for the following tasks

- Registering an OTG capable controller
- Registering Host and Gadget controllers to OTG core
- Providing inputs to and kicking the OTG state machine

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 MAINTAINERS                  |    4 +-
 drivers/usb/Kconfig          |    2 +-
 drivers/usb/Makefile         |    1 +
 drivers/usb/common/Makefile  |    3 +-
 drivers/usb/common/usb-otg.c | 1061 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/common/usb-otg.h |   71 +++
 drivers/usb/core/Kconfig     |   11 +-
 include/linux/usb/otg.h      |  189 +++++++-
 8 files changed, 1321 insertions(+), 21 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c
 create mode 100644 drivers/usb/common/usb-otg.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a9ae6c1..4bc1279 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10667,12 +10667,14 @@ S:	Maintained
 F:	Documentation/usb/ohci.txt
 F:	drivers/usb/host/ohci*
 
-USB OTG FSM (Finite State Machine)
+USB OTG/DRD core and FSM (Finite State Machine)
 M:	Peter Chen <Peter.Chen@freescale.com>
+M:	Roger Quadros <rogerq@ti.com>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 L:	linux-usb@vger.kernel.org
 S:	Maintained
 F:	drivers/usb/common/usb-otg-fsm.c
+F:	drivers/usb/common/usb-otg.c
 
 USB OVER IP DRIVER
 M:	Valentina Manea <valentina.manea.m@gmail.com>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8ed451d..5b625e2 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,7 +32,7 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 	default y
-	depends on USB || USB_GADGET
+	depends on USB || USB_GADGET || USB_OTG
 
 config USB_ARCH_HAS_HCD
 	def_bool y
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index d8926c6..769d13b 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -60,5 +60,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= common/
+obj-$(CONFIG_USB_OTG)		+= common/
 
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 6bbb3ec..730d928 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_USB_COMMON)	  += usb-common.o
 usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
-obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG)	+= usbotg.o
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..930c2fe
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,1061 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>	/* enum usb_otg_state */
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+#include "usb-otg.h"
+
+struct otg_gcd {
+	struct usb_gadget *gadget;
+	struct otg_gadget_ops *ops;
+};
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_list_mutex);
+
+/* Hosts and Gadgets waiting for OTG controller */
+struct otg_wait_data {
+	struct device *dev;		/* OTG controller device */
+
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gcd gcd;
+	struct list_head list;
+};
+
+LIST_HEAD(wait_list);
+static DEFINE_MUTEX(wait_list_mutex);
+
+static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
+{
+	if (!hcd->primary_hcd)
+		return 1;
+	return hcd == hcd->primary_hcd;
+}
+
+/**
+ * Check if the OTG device is in our wait list and return
+ * otg_wait_data, else NULL.
+ *
+ * wait_list_mutex must be held.
+ */
+static struct otg_wait_data *usb_otg_get_wait(struct device *otg_dev)
+{
+	struct otg_wait_data *wait;
+
+	if (!otg_dev)
+		return NULL;
+
+	/* is there an entry for this otg_dev ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->dev == otg_dev)
+			return wait;
+	}
+
+	return NULL;
+}
+
+/**
+ * Add the hcd to our wait list
+ */
+static int usb_otg_hcd_wait_add(struct device *otg_dev, struct usb_hcd *hcd,
+				unsigned int irqnum, unsigned long irqflags,
+				struct otg_hcd_ops *ops)
+{
+	struct otg_wait_data *wait;
+	int ret = -EINVAL;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait) {
+		/* Not yet in wait list? allocate and add */
+		wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+		if (!wait) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		wait->dev = otg_dev;
+		list_add_tail(&wait->list, &wait_list);
+	}
+
+	if (usb_otg_hcd_is_primary_hcd(hcd)) {
+		if (wait->primary_hcd.hcd)	/* already assigned? */
+			goto fail;
+
+		wait->primary_hcd.hcd = hcd;
+		wait->primary_hcd.irqnum = irqnum;
+		wait->primary_hcd.irqflags = irqflags;
+		wait->primary_hcd.ops = ops;
+	} else {
+		if (wait->shared_hcd.hcd)	/* already assigned? */
+			goto fail;
+
+		wait->shared_hcd.hcd = hcd;
+		wait->shared_hcd.irqnum = irqnum;
+		wait->shared_hcd.irqflags = irqflags;
+		wait->shared_hcd.ops = ops;
+	}
+
+	mutex_unlock(&wait_list_mutex);
+	return 0;
+
+fail:
+	mutex_unlock(&wait_list_mutex);
+	return ret;
+}
+
+/**
+ * Check and free wait list entry if empty
+ *
+ * wait_list_mutex must be held
+ */
+static void usb_otg_check_free_wait(struct otg_wait_data *wait)
+{
+	if (wait->primary_hcd.hcd || wait->shared_hcd.hcd || wait->gcd.gadget)
+		return;
+
+	list_del(&wait->list);
+	kfree(wait);
+}
+
+/**
+ * Remove the hcd from our wait list
+ */
+static int usb_otg_hcd_wait_remove(struct usb_hcd *hcd)
+{
+	struct otg_wait_data *wait;
+
+	mutex_lock(&wait_list_mutex);
+
+	/* is there an entry for this hcd ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->primary_hcd.hcd == hcd) {
+			wait->primary_hcd.hcd = 0;
+			goto found;
+		} else if (wait->shared_hcd.hcd == hcd) {
+			wait->shared_hcd.hcd = 0;
+			goto found;
+		}
+	}
+
+	mutex_unlock(&wait_list_mutex);
+	return -EINVAL;
+
+found:
+	usb_otg_check_free_wait(wait);
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+}
+
+/**
+ * Add the gadget to our wait list
+ */
+static int usb_otg_gadget_wait_add(struct device *otg_dev,
+				   struct usb_gadget *gadget,
+				   struct otg_gadget_ops *ops)
+{
+	struct otg_wait_data *wait;
+	int ret = -EINVAL;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait) {
+		/* Not yet in wait list? allocate and add */
+		wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+		if (!wait) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		wait->dev = otg_dev;
+		list_add_tail(&wait->list, &wait_list);
+	}
+
+	if (wait->gcd.gadget) /* already assigned? */
+		goto fail;
+
+	wait->gcd.gadget = gadget;
+	wait->gcd.ops = ops;
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+
+fail:
+	mutex_unlock(&wait_list_mutex);
+	return ret;
+}
+
+/**
+ * Remove the gadget from our wait list
+ */
+static int usb_otg_gadget_wait_remove(struct usb_gadget *gadget)
+{
+	struct otg_wait_data *wait;
+
+	mutex_lock(&wait_list_mutex);
+
+	/* is there an entry for this gadget ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->gcd.gadget == gadget) {
+			wait->gcd.gadget = 0;
+			goto found;
+		}
+	}
+
+	mutex_unlock(&wait_list_mutex);
+
+	return -EINVAL;
+
+found:
+	usb_otg_check_free_wait(wait);
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+}
+
+/**
+ * Register pending host/gadget and remove entry from wait list
+ */
+static void usb_otg_flush_wait(struct device *otg_dev)
+{
+	struct otg_wait_data *wait;
+	struct otg_hcd *host;
+	struct otg_gcd *gadget;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait)
+		goto done;
+
+	dev_dbg(otg_dev, "otg: registering pending host/gadget\n");
+	gadget = &wait->gcd;
+	if (gadget)
+		usb_otg_register_gadget(gadget->gadget, gadget->ops);
+
+	host = &wait->primary_hcd;
+	if (host->hcd)
+		usb_otg_register_hcd(host->hcd, host->irqnum, host->irqflags,
+				     host->ops);
+
+	host = &wait->shared_hcd;
+	if (host->hcd)
+		usb_otg_register_hcd(host->hcd, host->irqnum, host->irqflags,
+				     host->ops);
+
+	list_del(&wait->list);
+	kfree(wait);
+
+done:
+	mutex_unlock(&wait_list_mutex);
+}
+
+/**
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otgd;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otgd, &otg_list, list) {
+		if (otgd->dev == otg_dev)
+			return otgd;
+	}
+
+	return NULL;
+}
+
+/**
+ * Get OTG device from host or gadget device.
+ *
+ * For non device tree boot, the OTG controller is assumed to be
+ * the parent of the host/gadget device.
+ * For device tree boot, the OTG controller is derived from the
+ * "otg-controller" property.
+ */
+static struct device *usb_otg_get_device(struct device *hcd_gcd_dev)
+{
+	struct device *otg_dev;
+
+	if (!hcd_gcd_dev)
+		return NULL;
+
+	if (hcd_gcd_dev->of_node) {
+		struct device_node *np;
+		struct platform_device *pdev;
+
+		np = of_parse_phandle(hcd_gcd_dev->of_node, "otg-controller",
+				      0);
+		if (!np)
+			goto legacy;	/* continue legacy way */
+
+		pdev = of_find_device_by_node(np);
+		of_node_put(np);
+		if (!pdev) {
+			dev_err(&pdev->dev, "couldn't get otg-controller device\n");
+			return NULL;
+		}
+
+		otg_dev = &pdev->dev;
+		return otg_dev;
+	}
+
+legacy:
+	/* otg device is parent and must be registered */
+	otg_dev = hcd_gcd_dev->parent;
+	if (!usb_otg_get_data(otg_dev))
+		return NULL;
+
+	return otg_dev;
+}
+
+/**
+ * timer callback to set timeout bit and kick FSM
+ */
+static enum hrtimer_restart set_tmout(struct hrtimer *data)
+{
+	struct otg_timer *otgtimer;
+
+	otgtimer = container_of(data, struct otg_timer, timer);
+	if (otgtimer->timeout_bit)
+		*otgtimer->timeout_bit = 1;
+
+	usb_otg_sync_inputs(&otgtimer->otgd->fsm);
+
+	return HRTIMER_NORESTART;
+}
+
+/**
+ * Initialize one OTG timer with callback, timeout and timeout bit
+ */
+static void otg_timer_init(enum otg_fsm_timer id, struct usb_otg *otgd,
+			   enum hrtimer_restart (*callback)(struct hrtimer *),
+			   unsigned long expires_ms,
+			   int *timeout_bit)
+{
+	struct otg_timer *otgtimer = &otgd->timers[id];
+	struct hrtimer *timer = &otgtimer->timer;
+
+	otgtimer->timeout = ms_to_ktime(expires_ms);
+	hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer->function = callback;
+
+	otgtimer->timeout_bit = timeout_bit;
+	otgtimer->otgd = otgd;
+}
+
+/**
+ * Initialize standard OTG timers
+ */
+static void usb_otg_init_timers(struct usb_otg *otgd, unsigned *timeouts)
+{
+	struct otg_fsm *fsm = &otgd->fsm;
+	unsigned long tmouts[NUM_OTG_FSM_TIMERS];
+	int i;
+
+	/* set default timeouts */
+	tmouts[A_WAIT_VRISE] = TA_WAIT_VRISE;
+	tmouts[A_WAIT_VFALL] = TA_WAIT_VFALL;
+	tmouts[A_WAIT_BCON] = TA_WAIT_BCON;
+	tmouts[A_AIDL_BDIS] = TA_AIDL_BDIS;
+	tmouts[A_BIDL_ADIS] = TA_BIDL_ADIS;
+	tmouts[B_ASE0_BRST] = TB_ASE0_BRST;
+	tmouts[B_SE0_SRP] = TB_SE0_SRP;
+	tmouts[B_SRP_FAIL] = TB_SRP_FAIL;
+
+	/* set controller provided timeouts */
+	if (timeouts) {
+		for (i = 0; i < NUM_OTG_FSM_TIMERS; i++) {
+			if (timeouts[i])
+				tmouts[i] = timeouts[i];
+		}
+	}
+
+	otg_timer_init(A_WAIT_VRISE, otgd, set_tmout, TA_WAIT_VRISE,
+		       &fsm->a_wait_vrise_tmout);
+	otg_timer_init(A_WAIT_VFALL, otgd, set_tmout, TA_WAIT_VFALL,
+		       &fsm->a_wait_vfall_tmout);
+	otg_timer_init(A_WAIT_BCON, otgd, set_tmout, TA_WAIT_BCON,
+		       &fsm->a_wait_bcon_tmout);
+	otg_timer_init(A_AIDL_BDIS, otgd, set_tmout, TA_AIDL_BDIS,
+		       &fsm->a_aidl_bdis_tmout);
+	otg_timer_init(A_BIDL_ADIS, otgd, set_tmout, TA_BIDL_ADIS,
+		       &fsm->a_bidl_adis_tmout);
+	otg_timer_init(B_ASE0_BRST, otgd, set_tmout, TB_ASE0_BRST,
+		       &fsm->b_ase0_brst_tmout);
+
+	otg_timer_init(B_SE0_SRP, otgd, set_tmout, TB_SE0_SRP,
+		       &fsm->b_se0_srp);
+	otg_timer_init(B_SRP_FAIL, otgd, set_tmout, TB_SRP_FAIL,
+		       &fsm->b_srp_done);
+
+	/* FIXME: what about A_WAIT_ENUM? */
+}
+
+/**
+ * OTG FSM ops function to add timer
+ */
+static void usb_otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	struct otg_timer *otgtimer = &otgd->timers[id];
+	struct hrtimer *timer = &otgtimer->timer;
+
+	if (!otgd->fsm_running)
+		return;
+
+	/* if timer is already active, exit */
+	if (hrtimer_active(timer)) {
+		dev_err(otgd->dev, "otg: timer %d is already running\n", id);
+		return;
+	}
+
+	hrtimer_start(timer, otgtimer->timeout, HRTIMER_MODE_REL);
+}
+
+/**
+ * OTG FSM ops function to delete timer
+ */
+static void usb_otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	struct hrtimer *timer = &otgd->timers[id].timer;
+
+	hrtimer_cancel(timer);
+}
+
+/**
+ * Helper function to start/stop otg host. For use by otg controller.
+ */
+int usb_otg_start_host(struct otg_fsm *fsm, int on)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	struct otg_hcd_ops *hcd_ops;
+
+	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
+	if (!fsm->otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		/* start host */
+		hcd_ops = otgd->primary_hcd.ops;
+		hcd_ops->add(otgd->primary_hcd.hcd, otgd->primary_hcd.irqnum,
+			     otgd->primary_hcd.irqflags);
+		if (otgd->shared_hcd.hcd) {
+			hcd_ops = otgd->shared_hcd.ops;
+			hcd_ops->add(otgd->shared_hcd.hcd,
+				     otgd->shared_hcd.irqnum,
+				     otgd->shared_hcd.irqflags);
+		}
+	} else {
+		/* stop host */
+		if (otgd->shared_hcd.hcd) {
+			hcd_ops = otgd->shared_hcd.ops;
+			hcd_ops->remove(otgd->shared_hcd.hcd);
+		}
+		hcd_ops = otgd->primary_hcd.ops;
+		hcd_ops->remove(otgd->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * Helper function to start/stop otg gadget. For use by otg controller.
+ */
+int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	struct usb_gadget *gadget = fsm->otg->gadget;
+
+	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on)
+		otgd->gadget_ops->start(fsm->otg->gadget);
+	else
+		otgd->gadget_ops->stop(fsm->otg->gadget);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * OTG FSM work function
+ */
+static void usb_otg_work(struct work_struct *work)
+{
+	struct usb_otg *otgd = container_of(work, struct usb_otg, work);
+
+	otg_statemachine(&otgd->fsm);
+}
+
+/**
+ * usb_otg_register() - Register the OTG device to OTG core
+ * @dev: OTG controller device.
+ * @config: OTG configuration.
+ *
+ * Register the OTG controller device with the USB OTG core.
+ * The associated Host and Gadget controllers will be prevented from
+ * being started till both are available for use.
+ *
+ * For non device tree boots, the OTG controller device must be the
+ * parent node of the Host and Gadget controllers.
+ *
+ * For device tree case, the otg-controller property must be present
+ * in the Host and Gadget controller node and it must point to the
+ * same OTG controller node.
+ *
+ * Return: struct otg_fsm * if success, NULL if error.
+ */
+struct otg_fsm *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otgd;
+	struct otg_wait_data *wait;
+	int ret = 0;
+
+	if (!dev || !config || !config->fsm_ops)
+		return ERR_PTR(-EINVAL);
+
+	/* already in list? */
+	mutex_lock(&otg_list_mutex);
+	if (usb_otg_get_data(dev)) {
+		dev_err(dev, "otg: %s: device already in otg list\n",
+			__func__);
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	/* allocate and add to list */
+	otgd = kzalloc(sizeof(*otgd), GFP_KERNEL);
+	if (!otgd) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otgd->dev = dev;
+	otgd->caps = &config->otg_caps;
+	INIT_WORK(&otgd->work, usb_otg_work);
+	otgd->wq = create_singlethread_workqueue("usb_otg");
+	if (!otgd->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	usb_otg_init_timers(otgd, config->otg_timeouts);
+
+	/* create copy of original ops */
+	otgd->fsm_ops = *config->fsm_ops;
+	/* FIXME: we ignore caller's timer ops */
+	otgd->fsm_ops.add_timer = usb_otg_add_timer;
+	otgd->fsm_ops.del_timer = usb_otg_del_timer;
+	/* set otg ops */
+	otgd->fsm.ops = &otgd->fsm_ops;
+	otgd->fsm.otg = otgd;
+
+	mutex_init(&otgd->fsm.lock);
+
+	list_add_tail(&otgd->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	/* were we in wait list? */
+	mutex_lock(&wait_list_mutex);
+	wait = usb_otg_get_wait(dev);
+	mutex_unlock(&wait_list_mutex);
+	if (wait) {
+		/* register pending host/gadget and flush from list */
+		usb_otg_flush_wait(dev);
+	}
+
+	return &otgd->fsm;
+
+err_wq:
+	kfree(otgd);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregister OTG controller device from USB OTG core.
+ * Prevents unregistering till both the associated Host and Gadget controllers
+ * have unregistered from the OTG core.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister(struct device *dev)
+{
+	struct usb_otg *otgd;
+
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(dev);
+	if (!otgd) {
+		dev_err(dev, "otg: %s: device not in otg list\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EINVAL;
+	}
+
+	/* prevent unregister till both host & gadget have unregistered */
+	if (otgd->fsm.otg->host || otgd->fsm.otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otgd->wq);
+
+	/* remove from otg list */
+	list_del(&otgd->list);
+	kfree(otgd);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * start/kick the OTG FSM if we can
+ * fsm->lock must be held
+ */
+static void usb_otg_start_fsm(struct otg_fsm *fsm)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+
+	if (otgd->fsm_running)
+		goto kick_fsm;
+
+	if (!fsm->otg->host) {
+		dev_info(otgd->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!fsm->otg->gadget) {
+		dev_info(otgd->dev, "otg: can't start till gadget registers\n");
+		return;
+	}
+
+	otgd->fsm_running = true;
+kick_fsm:
+	queue_work(otgd->wq, &otgd->work);
+}
+
+/**
+ * stop the OTG FSM. Stops Host & Gadget controllers as well.
+ * fsm->lock must be held
+ */
+static void usb_otg_stop_fsm(struct otg_fsm *fsm)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	int i;
+
+	if (!otgd->fsm_running)
+		return;
+
+	/* no more new events queued */
+	otgd->fsm_running = false;
+
+	/* Stop state machine / timers */
+	for (i = 0; i < ARRAY_SIZE(otgd->timers); i++)
+		hrtimer_cancel(&otgd->timers[i].timer);
+
+	flush_workqueue(otgd->wq);
+	fsm->otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST)
+		otg_start_host(fsm, 0);
+	else if (fsm->protocol == PROTO_GADGET)
+		otg_start_gadget(fsm, 0);
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs - Sync OTG inputs with the OTG state machine
+ * @fsm:	OTG FSM instance
+ *
+ * Used by the OTG driver to update the inputs to the OTG
+ * state machine.
+ *
+ * Can be called in IRQ context.
+ */
+void usb_otg_sync_inputs(struct otg_fsm *fsm)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+
+	/* Don't kick FSM till it has started */
+	if (!otgd->fsm_running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otgd->wq, &otgd->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm - Kick the OTG state machine
+ * @hcd_gcd_device:	Host/Gadget controller device
+ *
+ * Used by USB host/device stack to sync OTG related
+ * events to the OTG state machine.
+ * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_kick_fsm(struct device *hcd_gcd_device)
+{
+	struct usb_otg *otgd;
+
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(usb_otg_get_device(hcd_gcd_device));
+	mutex_unlock(&otg_list_mutex);
+	if (!otgd) {
+		dev_dbg(hcd_gcd_device, "otg: %s: invalid host/gadget device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(&otgd->fsm);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd - Register Host controller to OTG core
+ * @hcd:	Host controller device
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to add/remove the HCD
+ *
+ * This is used by the USB Host stack to register the Host controller
+ * to the OTG core. Host controller must not be started by the
+ * caller as it is left upto the OTG state machine to do so.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+			 unsigned long irqflags, struct otg_hcd_ops *ops)
+{
+	struct usb_otg *otgd;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = usb_otg_get_device(hcd_dev);
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otgd) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. waiting..\n");
+		/*
+		 * otg controller might register later. Put the hcd in
+		 * wait list and call us back when ready
+		 */
+		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
+			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otgd->fsm.lock);
+	if (otgd->primary_hcd.hcd) {
+		/* probably a shared HCD ? */
+		if (usb_otg_hcd_is_primary_hcd(hcd)) {
+			dev_err(otg_dev, "otg: primary host already registered\n");
+			goto err;
+		}
+
+		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
+			if (otgd->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otgd->shared_hcd.hcd = hcd;
+			otgd->shared_hcd.irqnum = irqnum;
+			otgd->shared_hcd.irqflags = irqflags;
+			otgd->shared_hcd.ops = ops;
+			dev_info(otg_dev, "otg: shared host %s registered\n",
+				 dev_name(hcd->self.controller));
+		} else {
+			dev_err(otg_dev, "otg: invalid shared host %s\n",
+				dev_name(hcd->self.controller));
+			goto err;
+		}
+	} else {
+		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
+			dev_err(otg_dev, "otg: primary host must be registered first\n");
+			goto err;
+		}
+
+		otgd->primary_hcd.hcd = hcd;
+		otgd->primary_hcd.irqnum = irqnum;
+		otgd->primary_hcd.irqflags = irqflags;
+		otgd->primary_hcd.ops = ops;
+		dev_info(otg_dev, "otg: primary host %s registered\n",
+			 dev_name(hcd->self.controller));
+	}
+
+	/*
+	 * we're ready only if we have shared HCD
+	 * or we don't need shared HCD.
+	 */
+	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
+		otgd->fsm.otg->host = hcd_to_bus(hcd);
+		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
+
+		/* start FSM */
+		usb_otg_start_fsm(&otgd->fsm);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otgd->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otgd->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd - Unregister Host controller from OTG core
+ * @hcd:	Host controller device
+ *
+ * This is used by the USB Host stack to unregister the Host controller
+ * from the OTG core. Ensures that Host controller is not running
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_hcd(struct usb_hcd *hcd)
+{
+	struct usb_otg *otgd;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = usb_otg_get_device(hcd_dev);
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otgd) {
+		/* are we in wait list? */
+		if (!usb_otg_hcd_wait_remove(hcd))
+			return 0;
+
+		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&otgd->fsm.lock);
+	if (hcd == otgd->primary_hcd.hcd) {
+		otgd->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otgd->shared_hcd.hcd) {
+		otgd->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		mutex_unlock(&otgd->fsm.lock);
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(&otgd->fsm);
+	otgd->fsm.otg->host = NULL;
+
+	mutex_unlock(&otgd->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget - Register Gadget controller to OTG core
+ * @gadget:	Gadget controller
+ *
+ * This is used by the USB Gadget stack to register the Gadget controller
+ * to the OTG core. Gadget controller must not be started by the
+ * caller as it is left upto the OTG state machine to do so.
+ *
+ * Gadget core must call this only when all resources required for
+ * gadget controller to run are available.
+ * i.e. gadget function driver is available.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otgd;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = usb_otg_get_device(gadget_dev);
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otgd) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered. waiting..\n");
+		/*
+		 * otg controller might register later. Put the gadget in
+		 * wait list and call us back when ready
+		 */
+		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
+			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	mutex_lock(&otgd->fsm.lock);
+	if (otgd->fsm.otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otgd->fsm.lock);
+		return -EINVAL;
+	}
+
+	otgd->fsm.otg->gadget = gadget;
+	otgd->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* start FSM */
+	usb_otg_start_fsm(&otgd->fsm);
+	mutex_unlock(&otgd->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
+ * @gadget:	Gadget controller
+ *
+ * This is used by the USB Gadget stack to unregister the Gadget controller
+ * from the OTG core. Ensures that Gadget controller is not running
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	struct usb_otg *otgd;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = usb_otg_get_device(gadget_dev);
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otgd = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otgd) {
+		/* are we in wait list? */
+		if (!usb_otg_gadget_wait_remove(gadget))
+			return 0;
+
+		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&otgd->fsm.lock);
+	if (otgd->fsm.otg->gadget != gadget) {
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		mutex_unlock(&otgd->fsm.lock);
+		return -EINVAL;
+	}
+
+	/* Stop FSM & gadget */
+	usb_otg_stop_fsm(&otgd->fsm);
+	otgd->fsm.otg->gadget = NULL;
+	mutex_unlock(&otgd->fsm.lock);
+
+	dev_info(otg_dev, "otg: gadget %s unregistered\n",
+		 dev_name(&gadget->dev));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
+
+/**
+ * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
+ * @fsm:	otg_fsm data structure
+ *
+ * This is used by the OTG controller driver to get it's device node
+ * from any of the otg_fsm->ops.
+ */
+struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+
+	return otgd->dev;
+}
+EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
new file mode 100644
index 0000000..05331f0
--- /dev/null
+++ b/drivers/usb/common/usb-otg.h
@@ -0,0 +1,71 @@
+/**
+ * drivers/usb/common/usb-otg.h - USB OTG core local header
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
+#define __DRIVERS_USB_COMMON_USB_OTG_H
+
+/*
+ *  A-DEVICE timing constants
+ */
+
+/* Wait for VBUS Rise  */
+#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
+					 * a_wait_vrise_tmr: section 7.4.5.1
+					 * TA_VBUS_RISE <= 100ms, section 4.4
+					 * Table 4-1: Electrical Characteristics
+					 * ->DC Electrical Timing
+					 */
+/* Wait for VBUS Fall  */
+#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
+					 * a_wait_vfall_tmr: section: 7.4.5.2
+					 */
+/* Wait for B-Connect */
+#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
+					 * TA_WAIT_BCON: should be between 1100
+					 * and 30000 ms, section 5.5, Table 5-1
+					 */
+/* A-Idle to B-Disconnect */
+#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
+					 * TA_AIDL_BDIS: section 5.5, Table 5-1
+					 */
+/* B-Idle to A-Disconnect */
+#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
+					 * 500ms is used for B switch to host
+					 * for safe
+					 */
+
+/*
+ * B-device timing constants
+ */
+
+/* Data-Line Pulse Time*/
+#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
+					 * section:5.1.3
+					 */
+/* SRP Fail Time  */
+#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
+					 * section:5.1.6
+					 */
+/* A-SE0 to B-Reset  */
+#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
+/* SE0 Time Before SRP */
+#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
+/* SSEND time before SRP */
+#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
+
+#define TB_SESS_VLD          (1000)
+
+#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a99c89e..b468a9f 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
 	  If you are unsure about this, say N here.
 
 config USB_OTG
-	bool "OTG support"
+	bool "OTG/Dual-role support"
 	depends on PM
 	default n
 	help
@@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
 	  and software costs by not supporting external hubs.  So
 	  are "Embedded Hosts" that don't offer OTG support.
 
-config USB_OTG_FSM
-	tristate "USB 2.0 OTG FSM implementation"
-	depends on USB
-	select USB_OTG
-	select USB_PHY
-	help
-	  Implements OTG Finite State Machine as specified in On-The-Go
-	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
-
 config USB_ULPI_BUS
 	tristate "USB ULPI PHY interface support"
 	depends on USB_SUPPORT
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index bd1dcf8..38cabe0 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,19 +10,100 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg-fsm.h>
 #include <linux/usb/phy.h>
 
+/**
+ * struct otg_hcd - host controller state and interface
+ *
+ * @hcd: host controller
+ * @irqnum: irq number
+ * @irqflags: irq flags
+ * @ops: otg to host controller interface
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+};
+
+struct usb_otg;
+
+/**
+ * struct otg_timer - otg timer data
+ *
+ * @timer: high resolution timer
+ * @timeout: timeout value
+ * @timetout_bit: pointer to variable that is set on timeout
+ * @otgd: usb otg data
+ */
+struct otg_timer {
+	struct hrtimer timer;
+	ktime_t timeout;
+	/* callback data */
+	int *timeout_bit;
+	struct usb_otg *otgd;
+};
+
+/**
+ * struct usb_otg - usb otg controller state
+ *
+ * @default_a: Indicates we are an A device. i.e. Host.
+ * @phy: USB phy interface
+ * @usb_phy: old usb_phy interface
+ * @host: host controller bus
+ * @gadget: gadget device
+ * @state: current otg state
+ * @dev: otg controller device
+ * @caps: otg capabilities revision, hnp, srp, etc
+ * @fsm: otg finite state machine
+ * @fsm_ops: controller hooks for the state machine
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget interface
+ * @timers: otg timers for state machine
+ * @list: list of otg controllers
+ * @work: otg state machine work
+ * @wq: otg state machine work queue
+ * @fsm_running: state machine running/stopped indicator
+ */
 struct usb_otg {
 	u8			default_a;
 
 	struct phy		*phy;
 	/* old usb_phy interface */
 	struct usb_phy		*usb_phy;
+
 	struct usb_bus		*host;
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
 
+	struct device *dev;
+	struct usb_otg_caps *caps;
+	struct otg_fsm fsm;
+	struct otg_fsm_ops fsm_ops;
+
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	bool fsm_running;
+	/* use otg->fsm.lock for serializing access */
+
+/*------------- deprecated interface -----------------------------*/
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
 
@@ -38,7 +119,7 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
@@ -56,8 +137,105 @@ struct usb_otg_caps {
 	bool adp_support;
 };
 
+/**
+ * struct usb_otg_config - otg controller configuration
+ * @caps: otg capabilities of the controller
+ * @ops: otg fsm operations
+ * @otg_timeouts: override default otg fsm timeouts
+ */
+struct usb_otg_config {
+	struct usb_otg_caps otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
+};
+
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+enum usb_dr_mode {
+	USB_DR_MODE_UNKNOWN,
+	USB_DR_MODE_HOST,
+	USB_DR_MODE_PERIPHERAL,
+	USB_DR_MODE_OTG,
+};
+
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct otg_fsm *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config);
+int usb_otg_unregister(struct device *dev);
+int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+			 unsigned long irqflags, struct otg_hcd_ops *ops);
+int usb_otg_unregister_hcd(struct usb_hcd *hcd);
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops);
+int usb_otg_unregister_gadget(struct usb_gadget *gadget);
+void usb_otg_sync_inputs(struct otg_fsm *fsm);
+int usb_otg_kick_fsm(struct device *hcd_gcd_device);
+struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
+int usb_otg_start_host(struct otg_fsm *fsm, int on);
+int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct otg_fsm *usb_otg_register(struct device *dev,
+					       struct usb_otg_config *config)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
+static inline int usb_otg_unregister(struct device *dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+				       unsigned long irqflags,
+				       struct otg_hcd_ops *ops)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
+					  struct otg_gadget_ops *ops)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	return -ENOTSUPP;
+}
+
+static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
+{
+	return -ENOTSUPP;
+}
+
+static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
+{
+	return NULL;
+}
+
+static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
 	return -ENOTSUPP;
 }
 
+/*---------------------------------------------------------------*/
+
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
 
-enum usb_dr_mode {
-	USB_DR_MODE_UNKNOWN,
-	USB_DR_MODE_HOST,
-	USB_DR_MODE_PERIPHERAL,
-	USB_DR_MODE_OTG,
-};
-
 #endif /* __LINUX_USB_OTG_H */
-- 
2.1.4


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

* [PATCH v4 08/13] usb: doc: dt-binding: Add otg-controller property
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (6 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 09/13] usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG Roger Quadros
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The otg-controller property is used to link the host/gadget
controllers to the otg controller. otg-controller property must
contain the phandle of the otg controller.

The otg core uses this property to tie the host/gadget
controllres to the correct otg controller.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/devicetree/bindings/usb/generic.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index bba8257..5a457bc 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -24,6 +24,11 @@ Optional properties:
 			optional for OTG device.
  - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is
 			optional for OTG device.
+ - otg-controller: phandle to otg controller. Host or gadget controllers can
+			contain this property to link it to a particular otg
+			controller. If this property is not present then otg
+			core assumes that host and gadget controllers are
+			children of the otg controller.
 
 This is an attribute to a USB controller such as:
 
-- 
2.1.4


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

* [PATCH v4 09/13] usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (7 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 08/13] usb: doc: dt-binding: Add otg-controller property Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 10/13] usb: hcd: Adapt to OTG core Roger Quadros
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

CONFIG_USB_OTG_FSM no longer exists and the OTG FSM
is available if CONFIG_USB_OTG is defined so move
to using CONFIG_USB_OTG.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 Documentation/usb/chipidea.txt | 2 +-
 drivers/usb/chipidea/Makefile  | 2 +-
 drivers/usb/chipidea/ci.h      | 2 +-
 drivers/usb/chipidea/otg_fsm.h | 2 +-
 drivers/usb/phy/Kconfig        | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt
index 3f848c1..e7f97da 100644
--- a/Documentation/usb/chipidea.txt
+++ b/Documentation/usb/chipidea.txt
@@ -5,7 +5,7 @@ with 2 Freescale i.MX6Q sabre SD boards.
 
 1.1 How to enable OTG FSM in menuconfig
 ---------------------------------------
-Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules.
+Select CONFIG_USB_OTG, rebuild kernel Image and modules.
 If you want to check some internal variables for otg fsm,
 select CONFIG_USB_CHIPIDEA_DEBUG, there are 2 files which
 can show otg fsm variables and some controller registers value:
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 4decb12..63f2394 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -6,7 +6,7 @@ ci_hdrc-y				:= core.o otg.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
-ci_hdrc-$(CONFIG_USB_OTG_FSM)		+= otg_fsm.o
+ci_hdrc-$(CONFIG_USB_OTG)		+= otg_fsm.o
 
 # Glue/Bridge layers go here
 
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 41d7cf6..438818c 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -407,7 +407,7 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
  */
 static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci)
 {
-#ifdef CONFIG_USB_OTG_FSM
+#ifdef CONFIG_USB_OTG
 	struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
 
 	return ci->is_otg && ci->roles[CI_ROLE_HOST] &&
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 2689375..fb66695 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -62,7 +62,7 @@
 /* SSEND time before SRP */
 #define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
 
-#ifdef CONFIG_USB_OTG_FSM
+#ifdef CONFIG_USB_OTG
 
 int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
 int ci_otg_fsm_work(struct ci_hdrc *ci);
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 7d3beee..664cacb 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -20,7 +20,7 @@ config AB8500_USB
 
 config FSL_USB2_OTG
 	bool "Freescale USB OTG Transceiver Driver"
-	depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
+	depends on USB_EHCI_FSL && USB_FSL_USB2 && PM
 	select USB_OTG
 	select USB_PHY
 	help
-- 
2.1.4


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

* [PATCH v4 10/13] usb: hcd: Adapt to OTG core
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (8 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 09/13] usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-09-09  2:23   ` Peter Chen
  2015-08-24 13:21 ` [PATCH v4 11/13] usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable Roger Quadros
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The existing usb_add/remove_hcd() functionality
remains unchanged for non-OTG devices. For OTG
devices they only register the HCD with the OTG core.

Introduce usb_otg_add/remove_hcd() for use by OTG core.
These functions actually add/remove the HCD.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/core/hcd.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index c0fd1f6..4851682 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -46,6 +46,7 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/otg.h>
 
 #include "usb.h"
 
@@ -2625,8 +2626,8 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
  * buffers of consistent memory, register the bus, request the IRQ line,
  * and call the driver's reset() and start() routines.
  */
-int usb_add_hcd(struct usb_hcd *hcd,
-		unsigned int irqnum, unsigned long irqflags)
+static int usb_otg_add_hcd(struct usb_hcd *hcd,
+			   unsigned int irqnum, unsigned long irqflags)
 {
 	int retval;
 	struct usb_device *rhdev;
@@ -2839,17 +2840,16 @@ err_phy:
 	}
 	return retval;
 }
-EXPORT_SYMBOL_GPL(usb_add_hcd);
 
 /**
- * usb_remove_hcd - shutdown processing for generic HCDs
+ * usb_otg_remove_hcd - shutdown processing for generic HCDs
  * @hcd: the usb_hcd structure to remove
  * Context: !in_interrupt()
  *
  * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
  * invoking the HCD's stop() method.
  */
-void usb_remove_hcd(struct usb_hcd *hcd)
+static void usb_otg_remove_hcd(struct usb_hcd *hcd)
 {
 	struct usb_device *rhdev = hcd->self.root_hub;
 
@@ -2923,6 +2923,51 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 
 	usb_put_invalidate_rhdev(hcd);
 }
+
+static struct otg_hcd_ops otg_hcd_intf = {
+	.add = usb_otg_add_hcd,
+	.remove = usb_otg_remove_hcd,
+};
+
+/**
+ * usb_add_hcd - finish generic HCD structure initialization and register
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ *
+ * Finish the remaining parts of generic HCD initialization: allocate the
+ * buffers of consistent memory, register the bus, request the IRQ line,
+ * and call the driver's reset() and start() routines.
+ * If it is an OTG device then it only registers the HCD with OTG core.
+ *
+ */
+int usb_add_hcd(struct usb_hcd *hcd,
+		unsigned int irqnum, unsigned long irqflags)
+{
+	/* If OTG device, OTG core takes care of adding HCD */
+	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
+		return usb_otg_add_hcd(hcd, irqnum, irqflags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_add_hcd);
+
+/**
+ * usb_remove_hcd - shutdown processing for generic HCDs
+ * @hcd: the usb_hcd structure to remove
+ * Context: !in_interrupt()
+ *
+ * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() method.
+ * If it is an OTG device then it unregisters the HCD from OTG core
+ * as well.
+ */
+void usb_remove_hcd(struct usb_hcd *hcd)
+{
+	/* If OTG device, OTG core takes care of stopping HCD */
+	if (usb_otg_unregister_hcd(hcd))
+		usb_otg_remove_hcd(hcd);
+}
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
 void
-- 
2.1.4


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

* [PATCH v4 11/13] usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (9 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 10/13] usb: hcd: Adapt to OTG core Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 12/13] usb: gadget: udc: adapt to OTG core Roger Quadros
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

This is the a_set_b_hnp_enable flag in the OTG state machine
diagram and must be set when the A-Host has successfully set
the b_hnp_enable feature of the OTG-B-Peripheral attached to it.

When this bit changes we kick our OTG FSM to make note of the
change and act accordingly.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/core/hub.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 431839b..3993168 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2271,6 +2271,9 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
 						"can't set HNP mode: %d\n",
 						err);
 					bus->b_hnp_enable = 0;
+				} else {
+					/* notify OTG fsm about a_set_b_hnp_enable */
+					usb_otg_kick_fsm(udev->bus->controller);
 				}
 			}
 		}
@@ -4238,8 +4241,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	 */
 	if (!hdev->parent) {
 		delay = HUB_ROOT_RESET_TIME;
-		if (port1 == hdev->bus->otg_port)
+		if (port1 == hdev->bus->otg_port) {
 			hdev->bus->b_hnp_enable = 0;
+#ifdef CONFIG_USB_OTG
+			/* notify OTG fsm about a_set_b_hnp_enable change */
+			usb_otg_kick_fsm(hdev->bus->controller);
+#endif
+		}
 	}
 
 	/* Some low speed devices have problems with the quick delay, so */
-- 
2.1.4


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

* [PATCH v4 12/13] usb: gadget: udc: adapt to OTG core
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (10 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 11/13] usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-08-24 13:21 ` [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

The OTG state machine needs a mechanism to start and
stop the gadget controller. Add usb_gadget_start()
and usb_gadget_stop().

Register with OTG core when gadget function driver
is available and unregister when function driver is unbound.

We need to unlock the usb_lock mutexbefore calling
usb_otg_register_gadget() in udc_bind_to_driver() and
usb_gadget_remove_driver() else it will cause a circular
locking dependency.

Ignore softconnect sysfs control when we're in OTG
mode as OTG FSM takes care of gadget softconnect using
the b_bus_req mechanism.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/gadget/udc/udc-core.c | 124 +++++++++++++++++++++++++++++++++++---
 1 file changed, 114 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index f660afb..e961668 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -28,6 +28,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
 
 /**
  * struct usb_udc - describes one usb device controller
@@ -37,6 +38,7 @@
  * @list - for use by the udc class driver
  * @vbus - for udcs who care about vbus status, this value is real vbus status;
  * for udcs who do not care about vbus status, this value is always true
+ * @is_otg - we're registered with OTG core and it takes care of UDC start/stop
  *
  * This represents the internal data structure which is used by the UDC-class
  * to hold information about udc driver and gadget together.
@@ -47,6 +49,7 @@ struct usb_udc {
 	struct device			dev;
 	struct list_head		list;
 	bool				vbus;
+	bool				is_otg;
 };
 
 static struct class *udc_class;
@@ -300,6 +303,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
  */
 static inline int usb_gadget_udc_start(struct usb_udc *udc)
 {
+	dev_dbg(&udc->dev, "%s\n", __func__);
 	return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
 }
 
@@ -317,10 +321,81 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
  */
 static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 {
+	dev_dbg(&udc->dev, "%s\n", __func__);
 	udc->gadget->ops->udc_stop(udc->gadget);
 }
 
 /**
+ * usb_gadget_start - start the usb gadget controller and connect to bus
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller and connect to bus (enable pull).
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc = NULL;
+
+	dev_dbg(&gadget->dev, "%s\n", __func__);
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			goto found;
+
+	dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+		__func__);
+	mutex_unlock(&udc_lock);
+	return -EINVAL;
+
+found:
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+	else
+		usb_udc_connect_control(udc);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - disconnect from bus and stop the usb gadget
+ * @gadget: The gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Disconnect from the bus (disable pull) and stop the
+ * gadget controller.
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc = NULL;
+
+	dev_dbg(&gadget->dev, "%s\n", __func__);
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			goto found;
+
+	dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+		__func__);
+	mutex_unlock(&udc_lock);
+	return -EINVAL;
+
+found:
+	usb_gadget_disconnect(udc->gadget);
+	udc->driver->disconnect(udc->gadget);
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -438,6 +513,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/* udc_lock must be held */
 static void usb_gadget_remove_driver(struct usb_udc *udc)
 {
 	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
@@ -445,10 +521,18 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-	usb_gadget_disconnect(udc->gadget);
-	udc->driver->disconnect(udc->gadget);
+	/* If OTG, the otg core ensures UDC is stopped on unregister */
+	if (udc->is_otg) {
+		mutex_unlock(&udc_lock);
+		usb_otg_unregister_gadget(udc->gadget);
+		mutex_lock(&udc_lock);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+		usb_gadget_udc_stop(udc);
+	}
+
 	udc->driver->unbind(udc->gadget);
-	usb_gadget_udc_stop(udc);
 
 	udc->driver = NULL;
 	udc->dev.driver = NULL;
@@ -473,11 +557,12 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 
 	mutex_lock(&udc_lock);
 	list_del(&udc->list);
-	mutex_unlock(&udc_lock);
 
 	if (udc->driver)
 		usb_gadget_remove_driver(udc);
 
+	mutex_unlock(&udc_lock);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -487,6 +572,12 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+};
+
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -501,12 +592,19 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 	ret = driver->bind(udc->gadget, driver);
 	if (ret)
 		goto err1;
-	ret = usb_gadget_udc_start(udc);
-	if (ret) {
-		driver->unbind(udc->gadget);
-		goto err1;
+
+	/* If OTG, the otg core starts the UDC when needed */
+	mutex_unlock(&udc_lock);
+	udc->is_otg = !usb_otg_register_gadget(udc->gadget, &otg_gadget_intf);
+	mutex_lock(&udc_lock);
+	if (!udc->is_otg) {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_udc_connect_control(udc);
 	}
-	usb_udc_connect_control(udc);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 	return 0;
@@ -618,9 +716,15 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG mode we don't support softconnect, but b_bus_req */
+	if (udc->is_otg) {
+		dev_err(dev, "soft-connect not supported in OTG mode\n");
+		return -EOPNOTSUPP;
+	}
+
 	if (sysfs_streq(buf, "connect")) {
 		usb_gadget_udc_start(udc);
-		usb_gadget_connect(udc->gadget);
+		usb_udc_connect_control(udc);
 	} else if (sysfs_streq(buf, "disconnect")) {
 		usb_gadget_disconnect(udc->gadget);
 		udc->driver->disconnect(udc->gadget);
-- 
2.1.4


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

* [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (11 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 12/13] usb: gadget: udc: adapt to OTG core Roger Quadros
@ 2015-08-24 13:21 ` Roger Quadros
  2015-09-07  7:53   ` Li Jun
  2015-08-26  6:19 ` [PATCH v4 00/13] USB: OTG/DRD Core functionality Peter Chen
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-08-24 13:21 UTC (permalink / raw)
  To: stern, balbi, gregkh, peter.chen
  Cc: dan.j.williams, jun.li, mathias.nyman, tony, Joao.Pinto,
	abrestic, linux-usb, linux-kernel, linux-omap, Roger Quadros

DRD mode is a reduced functionality OTG mode. In this mode
we don't support SRP, HNP and dynamic role-swap.

In DRD operation, the controller mode (Host or Peripheral)
is decided based on the ID pin status. Once a cable plug (Type-A
or Type-B) is attached the controller selects the state
and doesn't change till the cable in unplugged and a different
cable type is inserted.

As we don't need most of the complex OTG states and OTG timers
we implement a lean DRD state machine in usb-otg.c.
The DRD state machine is only interested in 2 hardware inputs
'id' and 'b_sess_vld'.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/common/usb-otg.c | 178 +++++++++++++++++++++++++++++++++++++++++--
 include/linux/usb/otg-fsm.h  |   5 ++
 include/linux/usb/otg.h      |   2 +
 3 files changed, 177 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 930c2fe..44b5577 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -519,14 +519,165 @@ int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
 }
 EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
 
+/* Change USB protocol when there is a protocol change */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otgd->dev, "otg: changing role fsm->protocol= %d; new protocol= %d\n",
+			fsm->protocol, protocol);
+		/* stop old protocol */
+		if (fsm->protocol == PROTO_HOST)
+			ret = otg_start_host(fsm, 0);
+		else if (fsm->protocol == PROTO_GADGET)
+			ret = otg_start_gadget(fsm, 0);
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST)
+			ret = otg_start_host(fsm, 1);
+		else if (protocol == PROTO_GADGET)
+			ret = otg_start_gadget(fsm, 1);
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Called when entering a DRD state */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+
+	if (fsm->otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otgd->dev, "otg: set state: %s\n",
+		usb_otg_state_string(new_state));
+	switch (new_state) {
+	case OTG_STATE_B_IDLE:
+		drd_set_protocol(fsm, PROTO_UNDEF);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		break;
+	case OTG_STATE_UNDEFINED:
+	case OTG_STATE_B_SRP_INIT:
+	case OTG_STATE_B_WAIT_ACON:
+	case OTG_STATE_B_HOST:
+	case OTG_STATE_A_IDLE:
+	case OTG_STATE_A_WAIT_VRISE:
+	case OTG_STATE_A_WAIT_BCON:
+	case OTG_STATE_A_SUSPEND:
+	case OTG_STATE_A_PERIPHERAL:
+	case OTG_STATE_A_WAIT_VFALL:
+	case OTG_STATE_A_VBUS_ERR:
+	default:
+		dev_warn(otgd->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	fsm->otg->state = new_state;
+}
+
 /**
- * OTG FSM work function
+ * DRD state change judgement
+ *
+ * For DRD we're only interested in some of the OTG states
+ * i.e. OTG_STATE_B_IDLE: both peripheral and host are stopped
+ *	OTG_STATE_B_PERIPHERAL: peripheral active
+ *	OTG_STATE_A_HOST: host active
+ * we're only interested in the following inputs
+ *	fsm->id, fsm->b_sess_vld
+ */
+static int drd_statemachine(struct otg_fsm *fsm)
+{
+	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
+	enum usb_otg_state state;
+
+	mutex_lock(&fsm->lock);
+
+	state = fsm->otg->state;
+
+	switch (state) {
+	case OTG_STATE_UNDEFINED:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (fsm->id && fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		else
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (!fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+	case OTG_STATE_A_HOST:
+		if (fsm->id && fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		else if (fsm->id && !fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+
+	/* invalid states for DRD */
+	case OTG_STATE_B_SRP_INIT:
+	case OTG_STATE_B_WAIT_ACON:
+	case OTG_STATE_B_HOST:
+	case OTG_STATE_A_IDLE:
+	case OTG_STATE_A_WAIT_VRISE:
+	case OTG_STATE_A_WAIT_BCON:
+	case OTG_STATE_A_SUSPEND:
+	case OTG_STATE_A_PERIPHERAL:
+	case OTG_STATE_A_WAIT_VFALL:
+	case OTG_STATE_A_VBUS_ERR:
+		dev_err(otgd->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		drd_set_state(fsm, OTG_STATE_UNDEFINED);
+	break;
+	}
+
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otgd->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return fsm->state_changed;
+}
+
+/**
+ * OTG FSM/DRD work function
  */
 static void usb_otg_work(struct work_struct *work)
 {
 	struct usb_otg *otgd = container_of(work, struct usb_otg, work);
 
-	otg_statemachine(&otgd->fsm);
+	/* OTG state machine */
+	if (!otgd->drd_only) {
+		otg_statemachine(&otgd->fsm);
+		return;
+	}
+
+	/* DRD state machine */
+	drd_statemachine(&otgd->fsm);
 }
 
 /**
@@ -584,13 +735,22 @@ struct otg_fsm *usb_otg_register(struct device *dev,
 		goto err_wq;
 	}
 
-	usb_otg_init_timers(otgd, config->otg_timeouts);
+	if (!(otgd->caps->hnp_support || otgd->caps->srp_support ||
+	      otgd->caps->adp_support))
+		otgd->drd_only = true;
 
 	/* create copy of original ops */
 	otgd->fsm_ops = *config->fsm_ops;
-	/* FIXME: we ignore caller's timer ops */
-	otgd->fsm_ops.add_timer = usb_otg_add_timer;
-	otgd->fsm_ops.del_timer = usb_otg_del_timer;
+
+	/* For DRD mode we don't need OTG timers */
+	if (!otgd->drd_only) {
+		usb_otg_init_timers(otgd, config->otg_timeouts);
+
+		/* FIXME: we ignore caller's timer ops */
+		otgd->fsm_ops.add_timer = usb_otg_add_timer;
+		otgd->fsm_ops.del_timer = usb_otg_del_timer;
+	}
+
 	/* set otg ops */
 	otgd->fsm.ops = &otgd->fsm_ops;
 	otgd->fsm.otg = otgd;
@@ -703,8 +863,10 @@ static void usb_otg_stop_fsm(struct otg_fsm *fsm)
 	otgd->fsm_running = false;
 
 	/* Stop state machine / timers */
-	for (i = 0; i < ARRAY_SIZE(otgd->timers); i++)
-		hrtimer_cancel(&otgd->timers[i].timer);
+	if (!otgd->drd_only) {
+		for (i = 0; i < ARRAY_SIZE(otgd->timers); i++)
+			hrtimer_cancel(&otgd->timers[i].timer);
+	}
 
 	flush_workqueue(otgd->wq);
 	fsm->otg->state = OTG_STATE_UNDEFINED;
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 75e82cc..48a6aea 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -48,6 +48,11 @@ enum otg_fsm_timer {
 /**
  * struct otg_fsm - OTG state machine according to the OTG spec
  *
+ * DRD mode hardware Inputs
+ *
+ * @id:		TRUE for B-device, FALSE for A-device.
+ * @b_sess_vld:	VBUS voltage in regulation.
+ *
  * OTG hardware Inputs
  *
  *	Common inputs for A and B device
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 38cabe0..18de812 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -74,6 +74,7 @@ struct otg_timer {
  * @work: otg state machine work
  * @wq: otg state machine work queue
  * @fsm_running: state machine running/stopped indicator
+ * @drd_only: dual-role mode. no otg features.
  */
 struct usb_otg {
 	u8			default_a;
@@ -102,6 +103,7 @@ struct usb_otg {
 	struct workqueue_struct *wq;
 	bool fsm_running;
 	/* use otg->fsm.lock for serializing access */
+	bool drd_only;
 
 /*------------- deprecated interface -----------------------------*/
 	/* bind/unbind the host controller */
-- 
2.1.4


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

* Re: [PATCH v4 00/13]  USB: OTG/DRD Core functionality
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (12 preceding siblings ...)
  2015-08-24 13:21 ` [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros
@ 2015-08-26  6:19 ` Peter Chen
  2015-09-06  7:06 ` Peter Chen
  2015-12-03  8:19 ` Peter Chen
  15 siblings, 0 replies; 49+ messages in thread
From: Peter Chen @ 2015-08-26  6:19 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:11PM +0300, Roger Quadros wrote:
> Hi,
> 
> This series centralizes OTG/Dual-role functionality in the kernel.
> As of now I've got Dual-role functionality working pretty reliably on
> dra7-evm and am437x-gp-evm.
> 
> DWC3 controller and platform related patches will be sent separately.
> 

I will review this patch set after you send the above, it will be
more clear if there are users for code.

Peter
> Series is based on Greg's usb-next tree.
> 
> Changelog:
> ---------
> v4:
> - Added DT support for tying otg-controller to host and gadget
>  controllers. For DT we no longer have the constraint that
>  OTG controller needs to be parent of host and gadget. They can be
>  tied together using the "otg-controller" property.
> - Relax the requirement for DT case that otg controller must register before
>  host/gadget. We maintain a wait list of host/gadget devices
>  waiting on the otg controller.
> - Use a single struct usb_otg for otg data.
> - Don't override host/gadget start/stop APIs. Let the controller
>  drivers do what they want as they know best. Helper API is provided
>  for controller start/stop that controller driver can use.
> - Introduce struct usb_otg_config to pass the otg capabilities,
>  otg ops and otg timer timeouts during otg controller registration.
> - rebased on Greg's usb.git/usb-next
> 
> v3:
> - all otg related definations now in otg.h
> - single kernel config USB_OTG to enable OTG core and FSM.
> - resolved symbol dependency issues.
> - use dev_vdbg instead of VDBG() in usb-otg-fsm.c
> - rebased on v4.2-rc1
> 
> v2:
> - Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
>  the host controller
> - added dual-role-device (DRD) state machine which is a much simpler
>  mode of operation when compared to OTG. Here we don't support fancy
>  OTG features like HNP, SRP, on the fly role-swap. The mode of operation
>  is determined based on ID pin (cable type) and the role doesn't change
>  till the cable type changes.
> 
> Why?:
> ----
> 
> Most of the OTG drivers have been dealing with the OTG state machine
> themselves and there is a scope for code re-use. This has been
> partly addressed by the usb/common/usb-otg-fsm.c but it still
> leaves the instantiation of the state machine and OTG timers
> to the controller drivers. We re-use usb-otg-fsm.c but
> go one step further by instantiating the state machine and timers
> thus making it easier for drivers to implement OTG functionality.
> 
> Newer OTG cores support standard host interface (e.g. xHCI) so
> host and gadget functionality are no longer closely knit like older
> cores. There needs to be a way to co-ordinate the operation of the
> host and gadget in OTG mode. i.e. to stop and start them from a
> central location. This central location should be the USB OTG core.
> 
> Host and gadget controllers might be sharing resources and can't
> be always running. One has to be stopped for the other to run.
> This can't be done as of now and can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG core instantiates the OTG/DRD Finite State Machine
> per OTG controller and manages starting/stopping the
> host and gadget controllers based on the bus state.
>     
> It provides APIs for the following
>     
> - Registering an OTG capable controller
> struct otg_fsm *usb_otg_register(struct device *dev,
>                                  struct usb_otg_config *config);
> 
> int usb_otg_unregister(struct device *dev);
> 
> - Registering Host controllers to OTG core (used by hcd-core)
> int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>                          unsigned long irqflags, struct otg_hcd_ops *ops);
> int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> 
> 
> - Registering Gadget controllers to OTG core (used by udc-core)
> int usb_otg_register_gadget(struct usb_gadget *gadget,
>                             struct otg_gadget_ops *ops);
> int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> 
> 
> - Providing inputs to and kicking the OTG state machine
> void usb_otg_sync_inputs(struct otg_fsm *fsm);
> int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> 
> - Getting controller device structure from OTG state machine instance
> struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> 
> 'struct otg_fsm' is the interface to the OTG state machine.
> It contains inputs to the fsm, status of the fsm and operations
> for the OTG controller driver.
> 
> - Helper APIs for starting/stopping host/gadget controllers
> int usb_otg_start_host(struct otg_fsm *fsm, int on);
> int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> 
> Usage model:
> -----------
> 
> - The OTG core needs to know what host and gadget controllers are
> linked to the OTG controller. For DT boots we can provide that
> information by adding "otg-controller" property to the host and
> gadget controller nodes that points to the right otg controller.
> For legacy boot we assume that OTG controller is the parent
> of the host and gadget controllers. For DT if "otg-controller"
> property is not present then parent child relationship constraint
> applies.
> 
> - The OTG controller driver must call usb_otg_register() to register
> itself with the OTG core. It must also provide the required
> OTG configuration, fsm operations and timer timeouts (optional)
> via struct usb_otg_config. The fsm operations will be called
> depending on the OTG bus state.
> 
> - The host/gadget core stacks are modified to inform the OTG core
> whenever a new host/gadget device is added. The OTG core then
> checks if the host/gadget is part of the OTG controller and if yes
> then prevents the host/gadget from starting till both host and
> gadget are registered, OTG state machine is running and the
> USB bus state is appropriate to start host/gadget.
> For this, APIs have been added to host/gadget stacks to start/stop
> the controllers from the OTG core.
> For DT boots, If the OTG controller hasn't yet been registered
> while the host/gadget are added, the OTG core will hold it in a wait list
> and register them when the OTG controller registers.
> 
> - No modification is needed for the host/gadget controller drivers.
> They must ensure that their start/stop methods can be called repeatedly
> and any shared resources between host & gadget are properly managed.
> The OTG core ensures that both are not started simultaneously.
> 
> - The OTG core instantiates one OTG state machine per OTG controller
> and the necessary OTG timers to manage OTG state timeouts.
> If none of the otg features are set during usb_otg_register() then it
> instanciates a DRD (dual-role device) state machine instead.
> The state machine is started when both host & gadget register and
> stopped when either of them unregisters. The controllers are started
> and stopped depending on bus state.
> 
> - During the lifetime of the OTG state machine, inputs can be
> provided to it by modifying the appropriate members of 'struct otg_fsm'
> and calling usb_otg_sync_inputs(). This is typically done by the
> OTG controller driver that called usb_otg_register().
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: otg-fsm: Add documentation for struct otg_fsm
>   usb: otg-fsm: support multiple instances
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   otg-fsm: move usb_bus_start_enum into otg-fsm->ops
>   usb: hcd.h: Add OTG to HCD interface
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: add OTG core
>   usb: doc: dt-binding: Add otg-controller property
>   usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
>   usb: hcd: Adapt to OTG core
>   usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
>   usb: gadget: udc: adapt to OTG core
>   usb: otg: Add dual-role device (DRD) support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |    5 +
>  Documentation/usb/chipidea.txt                    |    2 +-
>  MAINTAINERS                                       |    4 +-
>  drivers/usb/Kconfig                               |    2 +-
>  drivers/usb/Makefile                              |    1 +
>  drivers/usb/chipidea/Makefile                     |    2 +-
>  drivers/usb/chipidea/ci.h                         |    2 +-
>  drivers/usb/chipidea/otg_fsm.c                    |    1 +
>  drivers/usb/chipidea/otg_fsm.h                    |    2 +-
>  drivers/usb/common/Makefile                       |    3 +-
>  drivers/usb/common/usb-otg-fsm.c                  |   26 +-
>  drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
>  drivers/usb/common/usb-otg.h                      |   71 ++
>  drivers/usb/core/Kconfig                          |   11 +-
>  drivers/usb/core/hcd.c                            |   55 +-
>  drivers/usb/core/hub.c                            |   10 +-
>  drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
>  drivers/usb/phy/Kconfig                           |    2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     |    3 +
>  include/linux/usb/gadget.h                        |   14 +
>  include/linux/usb/hcd.h                           |   14 +
>  include/linux/usb/otg-fsm.h                       |  116 +-
>  include/linux/usb/otg.h                           |  191 +++-
>  23 files changed, 1808 insertions(+), 76 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>  create mode 100644 drivers/usb/common/usb-otg.h
> 
> -- 
> 2.1.4
> 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 02/13] usb: otg-fsm: support multiple instances
  2015-08-24 13:21 ` [PATCH v4 02/13] usb: otg-fsm: support multiple instances Roger Quadros
@ 2015-09-06  5:52   ` Peter Chen
  0 siblings, 0 replies; 49+ messages in thread
From: Peter Chen @ 2015-09-06  5:52 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:13PM +0300, Roger Quadros wrote:
> Move the state_changed variable into struct otg_fsm
> so that we can support multiple instances.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/usb/common/usb-otg-fsm.c | 10 ++++------
>  include/linux/usb/otg-fsm.h      |  1 +
>  2 files changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
> index 61d538a..32862a4 100644
> --- a/drivers/usb/common/usb-otg-fsm.c
> +++ b/drivers/usb/common/usb-otg-fsm.c
> @@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
>  	return 0;
>  }
>  
> -static int state_changed;
> -
>  /* Called when leaving a state.  Do state clean up jobs here */
>  static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
>  {
> @@ -123,7 +121,6 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
>  /* Called when entering a state */
>  static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>  {
> -	state_changed = 1;
>  	if (fsm->otg->state == new_state)
>  		return 0;
>  	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
> @@ -237,6 +234,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>  	}
>  
>  	fsm->otg->state = new_state;
> +	fsm->state_changed = 1;
>  	return 0;
>  }
>  
> @@ -248,7 +246,7 @@ int otg_statemachine(struct otg_fsm *fsm)
>  	mutex_lock(&fsm->lock);
>  
>  	state = fsm->otg->state;
> -	state_changed = 0;
> +	fsm->state_changed = 0;
>  	/* State machine state change judgement */
>  
>  	switch (state) {
> @@ -361,7 +359,7 @@ int otg_statemachine(struct otg_fsm *fsm)
>  	}
>  	mutex_unlock(&fsm->lock);
>  
> -	VDBG("quit statemachine, changed = %d\n", state_changed);
> -	return state_changed;
> +	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
> +	return fsm->state_changed;
>  }
>  EXPORT_SYMBOL_GPL(otg_statemachine);
> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
> index fc5b4d9..20c8219 100644
> --- a/include/linux/usb/otg-fsm.h
> +++ b/include/linux/usb/otg-fsm.h
> @@ -195,6 +195,7 @@ struct otg_fsm {
>  	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
>  	int protocol;
>  	struct mutex lock;
> +	bool state_changed;
>  };
>  
>  struct otg_fsm_ops {
> -- 
> 2.1.4
> 

Acked-by: Peter Chen <peter.chen@freescale.com>

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 00/13]  USB: OTG/DRD Core functionality
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (13 preceding siblings ...)
  2015-08-26  6:19 ` [PATCH v4 00/13] USB: OTG/DRD Core functionality Peter Chen
@ 2015-09-06  7:06 ` Peter Chen
  2015-09-07 11:42   ` Roger Quadros
  2015-12-03  8:19 ` Peter Chen
  15 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-06  7:06 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:11PM +0300, Roger Quadros wrote:
> Hi,
> 
> This series centralizes OTG/Dual-role functionality in the kernel.
> As of now I've got Dual-role functionality working pretty reliably on
> dra7-evm and am437x-gp-evm.
> 
> DWC3 controller and platform related patches will be sent separately.
> 
> Series is based on Greg's usb-next tree.
> 
> Changelog:
> ---------
> v4:
> - Added DT support for tying otg-controller to host and gadget
>  controllers. For DT we no longer have the constraint that
>  OTG controller needs to be parent of host and gadget. They can be
>  tied together using the "otg-controller" property.
> - Relax the requirement for DT case that otg controller must register before
>  host/gadget. We maintain a wait list of host/gadget devices
>  waiting on the otg controller.
> - Use a single struct usb_otg for otg data.
> - Don't override host/gadget start/stop APIs. Let the controller
>  drivers do what they want as they know best. Helper API is provided
>  for controller start/stop that controller driver can use.
> - Introduce struct usb_otg_config to pass the otg capabilities,
>  otg ops and otg timer timeouts during otg controller registration.
> - rebased on Greg's usb.git/usb-next

Roger, thanks for your hard work. Since it is complicated, and can't
know its correctness and scalable well just reading code. I will run
it for chipidea driver, wait some time please.

Peter
> 
> v3:
> - all otg related definations now in otg.h
> - single kernel config USB_OTG to enable OTG core and FSM.
> - resolved symbol dependency issues.
> - use dev_vdbg instead of VDBG() in usb-otg-fsm.c
> - rebased on v4.2-rc1
> 
> v2:
> - Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
>  the host controller
> - added dual-role-device (DRD) state machine which is a much simpler
>  mode of operation when compared to OTG. Here we don't support fancy
>  OTG features like HNP, SRP, on the fly role-swap. The mode of operation
>  is determined based on ID pin (cable type) and the role doesn't change
>  till the cable type changes.
> 
> Why?:
> ----
> 
> Most of the OTG drivers have been dealing with the OTG state machine
> themselves and there is a scope for code re-use. This has been
> partly addressed by the usb/common/usb-otg-fsm.c but it still
> leaves the instantiation of the state machine and OTG timers
> to the controller drivers. We re-use usb-otg-fsm.c but
> go one step further by instantiating the state machine and timers
> thus making it easier for drivers to implement OTG functionality.
> 
> Newer OTG cores support standard host interface (e.g. xHCI) so
> host and gadget functionality are no longer closely knit like older
> cores. There needs to be a way to co-ordinate the operation of the
> host and gadget in OTG mode. i.e. to stop and start them from a
> central location. This central location should be the USB OTG core.
> 
> Host and gadget controllers might be sharing resources and can't
> be always running. One has to be stopped for the other to run.
> This can't be done as of now and can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG core instantiates the OTG/DRD Finite State Machine
> per OTG controller and manages starting/stopping the
> host and gadget controllers based on the bus state.
>     
> It provides APIs for the following
>     
> - Registering an OTG capable controller
> struct otg_fsm *usb_otg_register(struct device *dev,
>                                  struct usb_otg_config *config);
> 
> int usb_otg_unregister(struct device *dev);
> 
> - Registering Host controllers to OTG core (used by hcd-core)
> int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>                          unsigned long irqflags, struct otg_hcd_ops *ops);
> int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> 
> 
> - Registering Gadget controllers to OTG core (used by udc-core)
> int usb_otg_register_gadget(struct usb_gadget *gadget,
>                             struct otg_gadget_ops *ops);
> int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> 
> 
> - Providing inputs to and kicking the OTG state machine
> void usb_otg_sync_inputs(struct otg_fsm *fsm);
> int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> 
> - Getting controller device structure from OTG state machine instance
> struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> 
> 'struct otg_fsm' is the interface to the OTG state machine.
> It contains inputs to the fsm, status of the fsm and operations
> for the OTG controller driver.
> 
> - Helper APIs for starting/stopping host/gadget controllers
> int usb_otg_start_host(struct otg_fsm *fsm, int on);
> int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> 
> Usage model:
> -----------
> 
> - The OTG core needs to know what host and gadget controllers are
> linked to the OTG controller. For DT boots we can provide that
> information by adding "otg-controller" property to the host and
> gadget controller nodes that points to the right otg controller.
> For legacy boot we assume that OTG controller is the parent
> of the host and gadget controllers. For DT if "otg-controller"
> property is not present then parent child relationship constraint
> applies.
> 
> - The OTG controller driver must call usb_otg_register() to register
> itself with the OTG core. It must also provide the required
> OTG configuration, fsm operations and timer timeouts (optional)
> via struct usb_otg_config. The fsm operations will be called
> depending on the OTG bus state.
> 
> - The host/gadget core stacks are modified to inform the OTG core
> whenever a new host/gadget device is added. The OTG core then
> checks if the host/gadget is part of the OTG controller and if yes
> then prevents the host/gadget from starting till both host and
> gadget are registered, OTG state machine is running and the
> USB bus state is appropriate to start host/gadget.
> For this, APIs have been added to host/gadget stacks to start/stop
> the controllers from the OTG core.
> For DT boots, If the OTG controller hasn't yet been registered
> while the host/gadget are added, the OTG core will hold it in a wait list
> and register them when the OTG controller registers.
> 
> - No modification is needed for the host/gadget controller drivers.
> They must ensure that their start/stop methods can be called repeatedly
> and any shared resources between host & gadget are properly managed.
> The OTG core ensures that both are not started simultaneously.
> 
> - The OTG core instantiates one OTG state machine per OTG controller
> and the necessary OTG timers to manage OTG state timeouts.
> If none of the otg features are set during usb_otg_register() then it
> instanciates a DRD (dual-role device) state machine instead.
> The state machine is started when both host & gadget register and
> stopped when either of them unregisters. The controllers are started
> and stopped depending on bus state.
> 
> - During the lifetime of the OTG state machine, inputs can be
> provided to it by modifying the appropriate members of 'struct otg_fsm'
> and calling usb_otg_sync_inputs(). This is typically done by the
> OTG controller driver that called usb_otg_register().
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: otg-fsm: Add documentation for struct otg_fsm
>   usb: otg-fsm: support multiple instances
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   otg-fsm: move usb_bus_start_enum into otg-fsm->ops
>   usb: hcd.h: Add OTG to HCD interface
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: add OTG core
>   usb: doc: dt-binding: Add otg-controller property
>   usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
>   usb: hcd: Adapt to OTG core
>   usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
>   usb: gadget: udc: adapt to OTG core
>   usb: otg: Add dual-role device (DRD) support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |    5 +
>  Documentation/usb/chipidea.txt                    |    2 +-
>  MAINTAINERS                                       |    4 +-
>  drivers/usb/Kconfig                               |    2 +-
>  drivers/usb/Makefile                              |    1 +
>  drivers/usb/chipidea/Makefile                     |    2 +-
>  drivers/usb/chipidea/ci.h                         |    2 +-
>  drivers/usb/chipidea/otg_fsm.c                    |    1 +
>  drivers/usb/chipidea/otg_fsm.h                    |    2 +-
>  drivers/usb/common/Makefile                       |    3 +-
>  drivers/usb/common/usb-otg-fsm.c                  |   26 +-
>  drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
>  drivers/usb/common/usb-otg.h                      |   71 ++
>  drivers/usb/core/Kconfig                          |   11 +-
>  drivers/usb/core/hcd.c                            |   55 +-
>  drivers/usb/core/hub.c                            |   10 +-
>  drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
>  drivers/usb/phy/Kconfig                           |    2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     |    3 +
>  include/linux/usb/gadget.h                        |   14 +
>  include/linux/usb/hcd.h                           |   14 +
>  include/linux/usb/otg-fsm.h                       |  116 +-
>  include/linux/usb/otg.h                           |  191 +++-
>  23 files changed, 1808 insertions(+), 76 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>  create mode 100644 drivers/usb/common/usb-otg.h
> 
> -- 
> 2.1.4
> 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-08-24 13:21 ` [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros
@ 2015-09-07  1:23   ` Peter Chen
  2015-09-07 10:23     ` Roger Quadros
  2015-09-07  7:40   ` Li Jun
  1 sibling, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-07  1:23 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> + * This is used by the USB Host stack to register the Host controller
> + * to the OTG core. Host controller must not be started by the
> + * caller as it is left upto the OTG state machine to do so.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> +{
> +	struct usb_otg *otgd;
> +	struct device *hcd_dev = hcd->self.controller;
> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> +

One big problem here is: there are two designs for current (IP) driver
code, one creates dedicated hcd device as roothub's parent, like dwc3.
Another one doesn't do this, roothub's parent is core device (or otg device
in your patch), like chipidea and dwc2.

Then, otg_dev will be glue layer device for chipidea after that.

Peter

> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		dev_dbg(hcd_dev,
> +			"otg: controller not yet registered. waiting..\n");
> +		/*
> +		 * otg controller might register later. Put the hcd in
> +		 * wait list and call us back when ready
> +		 */
> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
> +			return -EINVAL;
> +		}
> +
> +		return 0;
> +	}
> +
> +	/* HCD will be started by OTG fsm when needed */
> +	mutex_lock(&otgd->fsm.lock);
> +	if (otgd->primary_hcd.hcd) {
> +		/* probably a shared HCD ? */
> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
> +			dev_err(otg_dev, "otg: primary host already registered\n");
> +			goto err;
> +		}
> +
> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
> +			if (otgd->shared_hcd.hcd) {
> +				dev_err(otg_dev, "otg: shared host already registered\n");
> +				goto err;
> +			}
> +
> +			otgd->shared_hcd.hcd = hcd;
> +			otgd->shared_hcd.irqnum = irqnum;
> +			otgd->shared_hcd.irqflags = irqflags;
> +			otgd->shared_hcd.ops = ops;
> +			dev_info(otg_dev, "otg: shared host %s registered\n",
> +				 dev_name(hcd->self.controller));
> +		} else {
> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
> +				dev_name(hcd->self.controller));
> +			goto err;
> +		}
> +	} else {
> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
> +			goto err;
> +		}
> +
> +		otgd->primary_hcd.hcd = hcd;
> +		otgd->primary_hcd.irqnum = irqnum;
> +		otgd->primary_hcd.irqflags = irqflags;
> +		otgd->primary_hcd.ops = ops;
> +		dev_info(otg_dev, "otg: primary host %s registered\n",
> +			 dev_name(hcd->self.controller));
> +	}
> +
> +	/*
> +	 * we're ready only if we have shared HCD
> +	 * or we don't need shared HCD.
> +	 */
> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
> +
> +		/* start FSM */
> +		usb_otg_start_fsm(&otgd->fsm);
> +	} else {
> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> +	}
> +
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +
> +err:
> +	mutex_unlock(&otgd->fsm.lock);
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> +
> +/**
> + * usb_otg_unregister_hcd - Unregister Host controller from OTG core
> + * @hcd:	Host controller device
> + *
> + * This is used by the USB Host stack to unregister the Host controller
> + * from the OTG core. Ensures that Host controller is not running
> + * on successful return.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> +{
> +	struct usb_otg *otgd;
> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		/* are we in wait list? */
> +		if (!usb_otg_hcd_wait_remove(hcd))
> +			return 0;
> +
> +		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (hcd == otgd->primary_hcd.hcd) {
> +		otgd->primary_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else if (hcd == otgd->shared_hcd.hcd) {
> +		otgd->shared_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else {
> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	/* stop FSM & Host */
> +	usb_otg_stop_fsm(&otgd->fsm);
> +	otgd->fsm.otg->host = NULL;
> +
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> +
> +/**
> + * usb_otg_register_gadget - Register Gadget controller to OTG core
> + * @gadget:	Gadget controller
> + *
> + * This is used by the USB Gadget stack to register the Gadget controller
> + * to the OTG core. Gadget controller must not be started by the
> + * caller as it is left upto the OTG state machine to do so.
> + *
> + * Gadget core must call this only when all resources required for
> + * gadget controller to run are available.
> + * i.e. gadget function driver is available.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops)
> +{
> +	struct usb_otg *otgd;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		dev_dbg(gadget_dev,
> +			"otg: controller not yet registered. waiting..\n");
> +		/*
> +		 * otg controller might register later. Put the gadget in
> +		 * wait list and call us back when ready
> +		 */
> +		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
> +			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
> +			return -EINVAL;
> +		}
> +
> +		return 0;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (otgd->fsm.otg->gadget) {
> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	otgd->fsm.otg->gadget = gadget;
> +	otgd->gadget_ops = ops;
> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> +		 dev_name(&gadget->dev));
> +
> +	/* start FSM */
> +	usb_otg_start_fsm(&otgd->fsm);
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> +
> +/**
> + * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
> + * @gadget:	Gadget controller
> + *
> + * This is used by the USB Gadget stack to unregister the Gadget controller
> + * from the OTG core. Ensures that Gadget controller is not running
> + * on successful return.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> +{
> +	struct usb_otg *otgd;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		/* are we in wait list? */
> +		if (!usb_otg_gadget_wait_remove(gadget))
> +			return 0;
> +
> +		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (otgd->fsm.otg->gadget != gadget) {
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	/* Stop FSM & gadget */
> +	usb_otg_stop_fsm(&otgd->fsm);
> +	otgd->fsm.otg->gadget = NULL;
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	dev_info(otg_dev, "otg: gadget %s unregistered\n",
> +		 dev_name(&gadget->dev));
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
> +
> +/**
> + * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
> + * @fsm:	otg_fsm data structure
> + *
> + * This is used by the OTG controller driver to get it's device node
> + * from any of the otg_fsm->ops.
> + */
> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +
> +	return otgd->dev;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
> diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
> new file mode 100644
> index 0000000..05331f0
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.h
> @@ -0,0 +1,71 @@
> +/**
> + * drivers/usb/common/usb-otg.h - USB OTG core local header
> + *
> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Roger Quadros <rogerq@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
> +#define __DRIVERS_USB_COMMON_USB_OTG_H
> +
> +/*
> + *  A-DEVICE timing constants
> + */
> +
> +/* Wait for VBUS Rise  */
> +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
> +					 * a_wait_vrise_tmr: section 7.4.5.1
> +					 * TA_VBUS_RISE <= 100ms, section 4.4
> +					 * Table 4-1: Electrical Characteristics
> +					 * ->DC Electrical Timing
> +					 */
> +/* Wait for VBUS Fall  */
> +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
> +					 * a_wait_vfall_tmr: section: 7.4.5.2
> +					 */
> +/* Wait for B-Connect */
> +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
> +					 * TA_WAIT_BCON: should be between 1100
> +					 * and 30000 ms, section 5.5, Table 5-1
> +					 */
> +/* A-Idle to B-Disconnect */
> +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
> +					 * TA_AIDL_BDIS: section 5.5, Table 5-1
> +					 */
> +/* B-Idle to A-Disconnect */
> +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
> +					 * 500ms is used for B switch to host
> +					 * for safe
> +					 */
> +
> +/*
> + * B-device timing constants
> + */
> +
> +/* Data-Line Pulse Time*/
> +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
> +					 * section:5.1.3
> +					 */
> +/* SRP Fail Time  */
> +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
> +					 * section:5.1.6
> +					 */
> +/* A-SE0 to B-Reset  */
> +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
> +/* SE0 Time Before SRP */
> +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
> +/* SSEND time before SRP */
> +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
> +
> +#define TB_SESS_VLD          (1000)
> +
> +#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
> index a99c89e..b468a9f 100644
> --- a/drivers/usb/core/Kconfig
> +++ b/drivers/usb/core/Kconfig
> @@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
>  	  If you are unsure about this, say N here.
>  
>  config USB_OTG
> -	bool "OTG support"
> +	bool "OTG/Dual-role support"
>  	depends on PM
>  	default n
>  	help
> @@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
>  	  and software costs by not supporting external hubs.  So
>  	  are "Embedded Hosts" that don't offer OTG support.
>  
> -config USB_OTG_FSM
> -	tristate "USB 2.0 OTG FSM implementation"
> -	depends on USB
> -	select USB_OTG
> -	select USB_PHY
> -	help
> -	  Implements OTG Finite State Machine as specified in On-The-Go
> -	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
> -
>  config USB_ULPI_BUS
>  	tristate "USB ULPI PHY interface support"
>  	depends on USB_SUPPORT
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index bd1dcf8..38cabe0 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -10,19 +10,100 @@
>  #define __LINUX_USB_OTG_H
>  
>  #include <linux/phy/phy.h>
> +#include <linux/device.h>
> +#include <linux/hrtimer.h>
> +#include <linux/ktime.h>
> +#include <linux/usb.h>
> +#include <linux/usb/hcd.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/usb/otg-fsm.h>
>  #include <linux/usb/phy.h>
>  
> +/**
> + * struct otg_hcd - host controller state and interface
> + *
> + * @hcd: host controller
> + * @irqnum: irq number
> + * @irqflags: irq flags
> + * @ops: otg to host controller interface
> + */
> +struct otg_hcd {
> +	struct usb_hcd *hcd;
> +	unsigned int irqnum;
> +	unsigned long irqflags;
> +	struct otg_hcd_ops *ops;
> +};
> +
> +struct usb_otg;
> +
> +/**
> + * struct otg_timer - otg timer data
> + *
> + * @timer: high resolution timer
> + * @timeout: timeout value
> + * @timetout_bit: pointer to variable that is set on timeout
> + * @otgd: usb otg data
> + */
> +struct otg_timer {
> +	struct hrtimer timer;
> +	ktime_t timeout;
> +	/* callback data */
> +	int *timeout_bit;
> +	struct usb_otg *otgd;
> +};
> +
> +/**
> + * struct usb_otg - usb otg controller state
> + *
> + * @default_a: Indicates we are an A device. i.e. Host.
> + * @phy: USB phy interface
> + * @usb_phy: old usb_phy interface
> + * @host: host controller bus
> + * @gadget: gadget device
> + * @state: current otg state
> + * @dev: otg controller device
> + * @caps: otg capabilities revision, hnp, srp, etc
> + * @fsm: otg finite state machine
> + * @fsm_ops: controller hooks for the state machine
> + * ------- internal use only -------
> + * @primary_hcd: primary host state and interface
> + * @shared_hcd: shared host state and interface
> + * @gadget_ops: gadget interface
> + * @timers: otg timers for state machine
> + * @list: list of otg controllers
> + * @work: otg state machine work
> + * @wq: otg state machine work queue
> + * @fsm_running: state machine running/stopped indicator
> + */
>  struct usb_otg {
>  	u8			default_a;
>  
>  	struct phy		*phy;
>  	/* old usb_phy interface */
>  	struct usb_phy		*usb_phy;
> +
>  	struct usb_bus		*host;
>  	struct usb_gadget	*gadget;
>  
>  	enum usb_otg_state	state;
>  
> +	struct device *dev;
> +	struct usb_otg_caps *caps;
> +	struct otg_fsm fsm;
> +	struct otg_fsm_ops fsm_ops;
> +
> +	/* internal use only */
> +	struct otg_hcd primary_hcd;
> +	struct otg_hcd shared_hcd;
> +	struct otg_gadget_ops *gadget_ops;
> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
> +	struct list_head list;
> +	struct work_struct work;
> +	struct workqueue_struct *wq;
> +	bool fsm_running;
> +	/* use otg->fsm.lock for serializing access */
> +
> +/*------------- deprecated interface -----------------------------*/
>  	/* bind/unbind the host controller */
>  	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
>  
> @@ -38,7 +119,7 @@ struct usb_otg {
>  
>  	/* start or continue HNP role switch */
>  	int	(*start_hnp)(struct usb_otg *otg);
> -
> +/*---------------------------------------------------------------*/
>  };
>  
>  /**
> @@ -56,8 +137,105 @@ struct usb_otg_caps {
>  	bool adp_support;
>  };
>  
> +/**
> + * struct usb_otg_config - otg controller configuration
> + * @caps: otg capabilities of the controller
> + * @ops: otg fsm operations
> + * @otg_timeouts: override default otg fsm timeouts
> + */
> +struct usb_otg_config {
> +	struct usb_otg_caps otg_caps;
> +	struct otg_fsm_ops *fsm_ops;
> +	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
> +};
> +
>  extern const char *usb_otg_state_string(enum usb_otg_state state);
>  
> +enum usb_dr_mode {
> +	USB_DR_MODE_UNKNOWN,
> +	USB_DR_MODE_HOST,
> +	USB_DR_MODE_PERIPHERAL,
> +	USB_DR_MODE_OTG,
> +};
> +
> +#if IS_ENABLED(CONFIG_USB_OTG)
> +struct otg_fsm *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config);
> +int usb_otg_unregister(struct device *dev);
> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +			 unsigned long irqflags, struct otg_hcd_ops *ops);
> +int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops);
> +int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> +void usb_otg_sync_inputs(struct otg_fsm *fsm);
> +int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> +int usb_otg_start_host(struct otg_fsm *fsm, int on);
> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> +
> +#else /* CONFIG_USB_OTG */
> +
> +static inline struct otg_fsm *usb_otg_register(struct device *dev,
> +					       struct usb_otg_config *config)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
> +static inline int usb_otg_unregister(struct device *dev)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +				       unsigned long irqflags,
> +				       struct otg_hcd_ops *ops)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
> +					  struct otg_gadget_ops *ops)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
> +{
> +}
> +
> +static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> +{
> +	return NULL;
> +}
> +
> +static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +#endif /* CONFIG_USB_OTG */
> +
> +/*------------- deprecated interface -----------------------------*/
>  /* Context: can sleep */
>  static inline int
>  otg_start_hnp(struct usb_otg *otg)
> @@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
>  	return -ENOTSUPP;
>  }
>  
> +/*---------------------------------------------------------------*/
> +
>  /* for OTG controller drivers (and maybe other stuff) */
>  extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
>  
> -enum usb_dr_mode {
> -	USB_DR_MODE_UNKNOWN,
> -	USB_DR_MODE_HOST,
> -	USB_DR_MODE_PERIPHERAL,
> -	USB_DR_MODE_OTG,
> -};
> -
>  #endif /* __LINUX_USB_OTG_H */
> -- 
> 2.1.4
> 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  2015-08-24 13:21 ` [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops Roger Quadros
@ 2015-09-07  1:24   ` Peter Chen
  2015-09-07  9:57     ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-07  1:24 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:15PM +0300, Roger Quadros wrote:
> This is to prevent missing symbol build error if OTG is
> enabled (built-in) and HCD core (CONFIG_USB) is module.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Peter Chen <peter.chen@freescale.com>
> ---
>  drivers/usb/common/usb-otg-fsm.c | 6 ++++--
>  drivers/usb/phy/phy-fsl-usb.c    | 2 ++
>  include/linux/usb/otg-fsm.h      | 1 +
>  3 files changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
> index a46f29a..6e56c8c 100644
> --- a/drivers/usb/common/usb-otg-fsm.c
> +++ b/drivers/usb/common/usb-otg-fsm.c
> @@ -165,8 +165,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>  		otg_loc_conn(fsm, 0);
>  		otg_loc_sof(fsm, 1);
>  		otg_set_protocol(fsm, PROTO_HOST);
> -		usb_bus_start_enum(fsm->otg->host,
> -				fsm->otg->host->otg_port);
> +		if (fsm->ops->start_enum) {
> +			fsm->ops->start_enum(fsm->otg->host,
> +					     fsm->otg->host->otg_port);
> +		}
>  		break;
>  	case OTG_STATE_A_IDLE:
>  		otg_drv_vbus(fsm, 0);
> diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
> index ee3f2c2..19541ed 100644
> --- a/drivers/usb/phy/phy-fsl-usb.c
> +++ b/drivers/usb/phy/phy-fsl-usb.c
> @@ -783,6 +783,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
>  
>  	.start_host = fsl_otg_start_host,
>  	.start_gadget = fsl_otg_start_gadget,
> +
> +	.start_enum = usb_bus_start_enum,
>  };
>  
>  /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
> index 672551c..75e82cc 100644
> --- a/include/linux/usb/otg-fsm.h
> +++ b/include/linux/usb/otg-fsm.h
> @@ -199,6 +199,7 @@ struct otg_fsm_ops {
>  	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
>  	int	(*start_host)(struct otg_fsm *fsm, int on);
>  	int	(*start_gadget)(struct otg_fsm *fsm, int on);
> +	int	(*start_enum)(struct usb_bus *bus, unsigned port_num);
>  };
>  
>  

Get one build warning:

In file included from /u/home/b29397/work/projects/usb/drivers/usb/chipidea/udc.c:23:0:
/u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: 'struct usb_bus' declared inside parameter list
  int (*start_enum)(struct usb_bus *bus, unsigned port_num);
                             ^
/u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: its scope is only this definition or declaration, which is probably not what you want

It probably dues to we should not have struct usb_bus* at udc driver

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-08-24 13:21 ` [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros
  2015-09-07  1:23   ` Peter Chen
@ 2015-09-07  7:40   ` Li Jun
  2015-09-07 10:53     ` Roger Quadros
  1 sibling, 1 reply; 49+ messages in thread
From: Li Jun @ 2015-09-07  7:40 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> The OTG core instantiates the OTG Finite State Machine
> per OTG controller and manages starting/stopping the
> host and gadget controllers based on the bus state.
> 
> It provides APIs for the following tasks
> 
> - Registering an OTG capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  MAINTAINERS                  |    4 +-
>  drivers/usb/Kconfig          |    2 +-
>  drivers/usb/Makefile         |    1 +
>  drivers/usb/common/Makefile  |    3 +-
>  drivers/usb/common/usb-otg.c | 1061 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/common/usb-otg.h |   71 +++
>  drivers/usb/core/Kconfig     |   11 +-
>  include/linux/usb/otg.h      |  189 +++++++-
>  8 files changed, 1321 insertions(+), 21 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>  create mode 100644 drivers/usb/common/usb-otg.h
> 

... ...

> +
> +/**
> + * Get OTG device from host or gadget device.
> + *
> + * For non device tree boot, the OTG controller is assumed to be
> + * the parent of the host/gadget device.

This assumption/restriction maybe a problem, as I pointed in your previous
version, usb_create_hcd() use the passed dev as its dev, but,
usb_add_gadget_udc() use the passed dev as its parent dev, so often the
host and gadget don't share the same parent device, at least it doesn't
apply to chipidea case.

> + * For device tree boot, the OTG controller is derived from the
> + * "otg-controller" property.
> + */
> +static struct device *usb_otg_get_device(struct device *hcd_gcd_dev)
> +{
> +	struct device *otg_dev;
> +
> +	if (!hcd_gcd_dev)
> +		return NULL;
> +
> +	if (hcd_gcd_dev->of_node) {
> +		struct device_node *np;
> +		struct platform_device *pdev;
> +
> +		np = of_parse_phandle(hcd_gcd_dev->of_node, "otg-controller",
> +				      0);
> +		if (!np)
> +			goto legacy;	/* continue legacy way */
> +
> +		pdev = of_find_device_by_node(np);
> +		of_node_put(np);
> +		if (!pdev) {
> +			dev_err(&pdev->dev, "couldn't get otg-controller device\n");
> +			return NULL;
> +		}
> +
> +		otg_dev = &pdev->dev;
> +		return otg_dev;
> +	}
> +
> +legacy:
> +	/* otg device is parent and must be registered */
> +	otg_dev = hcd_gcd_dev->parent;
> +	if (!usb_otg_get_data(otg_dev))
> +		return NULL;
> +
> +	return otg_dev;
> +}
> +

... ...

> +static void usb_otg_init_timers(struct usb_otg *otgd, unsigned *timeouts)
> +{
> +	struct otg_fsm *fsm = &otgd->fsm;
> +	unsigned long tmouts[NUM_OTG_FSM_TIMERS];
> +	int i;
> +
> +	/* set default timeouts */
> +	tmouts[A_WAIT_VRISE] = TA_WAIT_VRISE;
> +	tmouts[A_WAIT_VFALL] = TA_WAIT_VFALL;
> +	tmouts[A_WAIT_BCON] = TA_WAIT_BCON;
> +	tmouts[A_AIDL_BDIS] = TA_AIDL_BDIS;
> +	tmouts[A_BIDL_ADIS] = TA_BIDL_ADIS;
> +	tmouts[B_ASE0_BRST] = TB_ASE0_BRST;
> +	tmouts[B_SE0_SRP] = TB_SE0_SRP;
> +	tmouts[B_SRP_FAIL] = TB_SRP_FAIL;
> +
> +	/* set controller provided timeouts */
> +	if (timeouts) {
> +		for (i = 0; i < NUM_OTG_FSM_TIMERS; i++) {
> +			if (timeouts[i])
> +				tmouts[i] = timeouts[i];
> +		}
> +	}
> +
> +	otg_timer_init(A_WAIT_VRISE, otgd, set_tmout, TA_WAIT_VRISE,
> +		       &fsm->a_wait_vrise_tmout);
> +	otg_timer_init(A_WAIT_VFALL, otgd, set_tmout, TA_WAIT_VFALL,
> +		       &fsm->a_wait_vfall_tmout);
> +	otg_timer_init(A_WAIT_BCON, otgd, set_tmout, TA_WAIT_BCON,
> +		       &fsm->a_wait_bcon_tmout);
> +	otg_timer_init(A_AIDL_BDIS, otgd, set_tmout, TA_AIDL_BDIS,
> +		       &fsm->a_aidl_bdis_tmout);
> +	otg_timer_init(A_BIDL_ADIS, otgd, set_tmout, TA_BIDL_ADIS,
> +		       &fsm->a_bidl_adis_tmout);
> +	otg_timer_init(B_ASE0_BRST, otgd, set_tmout, TB_ASE0_BRST,
> +		       &fsm->b_ase0_brst_tmout);
> +
> +	otg_timer_init(B_SE0_SRP, otgd, set_tmout, TB_SE0_SRP,
> +		       &fsm->b_se0_srp);
> +	otg_timer_init(B_SRP_FAIL, otgd, set_tmout, TB_SRP_FAIL,
> +		       &fsm->b_srp_done);
> +
> +	/* FIXME: what about A_WAIT_ENUM? */

Either you init it as other timers, or you remove all of it, otherwise
there will be NULL pointer crash.

> +}
> +
> +/**
> + * OTG FSM ops function to add timer
> + */
> +static void usb_otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +	struct otg_timer *otgtimer = &otgd->timers[id];
> +	struct hrtimer *timer = &otgtimer->timer;
> +
> +	if (!otgd->fsm_running)
> +		return;
> +
> +	/* if timer is already active, exit */
> +	if (hrtimer_active(timer)) {
> +		dev_err(otgd->dev, "otg: timer %d is already running\n", id);
> +		return;
> +	}
> +
> +	hrtimer_start(timer, otgtimer->timeout, HRTIMER_MODE_REL);
> +}
> +
> +/**
> + * OTG FSM ops function to delete timer
> + */
> +static void usb_otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +	struct hrtimer *timer = &otgd->timers[id].timer;
> +
> +	hrtimer_cancel(timer);
> +}
> +
> +/**
> + * Helper function to start/stop otg host. For use by otg controller.
> + */
> +int usb_otg_start_host(struct otg_fsm *fsm, int on)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +	struct otg_hcd_ops *hcd_ops;
> +
> +	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
> +	if (!fsm->otg->host) {
> +		WARN_ONCE(1, "otg: fsm running without host\n");
> +		return 0;
> +	}
> +
> +	if (on) {
> +		/* start host */
> +		hcd_ops = otgd->primary_hcd.ops;
> +		hcd_ops->add(otgd->primary_hcd.hcd, otgd->primary_hcd.irqnum,
> +			     otgd->primary_hcd.irqflags);
> +		if (otgd->shared_hcd.hcd) {
> +			hcd_ops = otgd->shared_hcd.ops;
> +			hcd_ops->add(otgd->shared_hcd.hcd,
> +				     otgd->shared_hcd.irqnum,
> +				     otgd->shared_hcd.irqflags);
> +		}
> +	} else {
> +		/* stop host */
> +		if (otgd->shared_hcd.hcd) {
> +			hcd_ops = otgd->shared_hcd.ops;
> +			hcd_ops->remove(otgd->shared_hcd.hcd);
> +		}
> +		hcd_ops = otgd->primary_hcd.ops;
> +		hcd_ops->remove(otgd->primary_hcd.hcd);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
> +
> +/**
> + * Helper function to start/stop otg gadget. For use by otg controller.
> + */
> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +	struct usb_gadget *gadget = fsm->otg->gadget;
> +
> +	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
> +	if (!gadget) {
> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
> +		return 0;
> +	}
> +
> +	if (on)
> +		otgd->gadget_ops->start(fsm->otg->gadget);
> +	else
> +		otgd->gadget_ops->stop(fsm->otg->gadget);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
> +
> +/**
> + * OTG FSM work function
> + */
> +static void usb_otg_work(struct work_struct *work)
> +{
> +	struct usb_otg *otgd = container_of(work, struct usb_otg, work);
> +

Add runtime pm for it
	pm_runtime_get_sync(otgd->dev);
> +	otg_statemachine(&otgd->fsm);
	pm_runtime_put_sync(otgd->dev);

Also as I raised in your previous version, we need successive state machine
transition, how about:
	if (otg_statemachine(&otgd->fsm))
		usb_otg_sync_inputs(&otgd->fsm);
> +}
> +
> +/**
> + * usb_otg_register() - Register the OTG device to OTG core
> + * @dev: OTG controller device.
> + * @config: OTG configuration.
> + *
> + * Register the OTG controller device with the USB OTG core.
> + * The associated Host and Gadget controllers will be prevented from
> + * being started till both are available for use.
> + *
> + * For non device tree boots, the OTG controller device must be the
> + * parent node of the Host and Gadget controllers.
> + *
> + * For device tree case, the otg-controller property must be present
> + * in the Host and Gadget controller node and it must point to the
> + * same OTG controller node.
> + *
> + * Return: struct otg_fsm * if success, NULL if error.
> + */
> +struct otg_fsm *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config)

Why not return usb_otg? Since you create usb_otg which contains all stuff
for otg.

> +{
> +	struct usb_otg *otgd;
> +	struct otg_wait_data *wait;
> +	int ret = 0;
> +
> +	if (!dev || !config || !config->fsm_ops)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* already in list? */
> +	mutex_lock(&otg_list_mutex);
> +	if (usb_otg_get_data(dev)) {
> +		dev_err(dev, "otg: %s: device already in otg list\n",
> +			__func__);
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
> +
> +	/* allocate and add to list */
> +	otgd = kzalloc(sizeof(*otgd), GFP_KERNEL);
> +	if (!otgd) {
> +		ret = -ENOMEM;
> +		goto unlock;
> +	}
> +
> +	otgd->dev = dev;
> +	otgd->caps = &config->otg_caps;

How about define otgd->caps as a pointer, then don't need copy it.

> +	INIT_WORK(&otgd->work, usb_otg_work);
> +	otgd->wq = create_singlethread_workqueue("usb_otg");
> +	if (!otgd->wq) {
> +		dev_err(dev, "otg: %s: can't create workqueue\n",
> +			__func__);
> +		ret = -ENOMEM;
> +		goto err_wq;
> +	}
> +
> +	usb_otg_init_timers(otgd, config->otg_timeouts);
> +
> +	/* create copy of original ops */
> +	otgd->fsm_ops = *config->fsm_ops;

The same, use a pointer is enough?

> +	/* FIXME: we ignore caller's timer ops */
> +	otgd->fsm_ops.add_timer = usb_otg_add_timer;
> +	otgd->fsm_ops.del_timer = usb_otg_del_timer;
> +	/* set otg ops */
> +	otgd->fsm.ops = &otgd->fsm_ops;
> +	otgd->fsm.otg = otgd;
> +
> +	mutex_init(&otgd->fsm.lock);
> +
> +	list_add_tail(&otgd->list, &otg_list);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	/* were we in wait list? */
> +	mutex_lock(&wait_list_mutex);
> +	wait = usb_otg_get_wait(dev);
> +	mutex_unlock(&wait_list_mutex);
> +	if (wait) {
> +		/* register pending host/gadget and flush from list */
> +		usb_otg_flush_wait(dev);
> +	}
> +
> +	return &otgd->fsm;
> +
> +err_wq:
> +	kfree(otgd);
> +unlock:
> +	mutex_unlock(&otg_list_mutex);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register);
> +
> +/**
> + * usb_otg_unregister() - Unregister the OTG device from USB OTG core
> + * @dev: OTG controller device.
> + *
> + * Unregister OTG controller device from USB OTG core.
> + * Prevents unregistering till both the associated Host and Gadget controllers
> + * have unregistered from the OTG core.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_unregister(struct device *dev)
> +{
> +	struct usb_otg *otgd;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(dev);
> +	if (!otgd) {
> +		dev_err(dev, "otg: %s: device not in otg list\n",
> +			__func__);
> +		mutex_unlock(&otg_list_mutex);
> +		return -EINVAL;
> +	}
> +
> +	/* prevent unregister till both host & gadget have unregistered */
> +	if (otgd->fsm.otg->host || otgd->fsm.otg->gadget) {
> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
> +			__func__);
> +		return -EBUSY;
> +	}
> +
> +	/* OTG FSM is halted when host/gadget unregistered */
> +	destroy_workqueue(otgd->wq);
> +
> +	/* remove from otg list */
> +	list_del(&otgd->list);
> +	kfree(otgd);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
> +
> +/**
> + * start/kick the OTG FSM if we can
> + * fsm->lock must be held
> + */
> +static void usb_otg_start_fsm(struct otg_fsm *fsm)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +
> +	if (otgd->fsm_running)
> +		goto kick_fsm;
> +
> +	if (!fsm->otg->host) {
> +		dev_info(otgd->dev, "otg: can't start till host registers\n");
> +		return;

So we need register hcd(usb_otg_register_hcd) before start fsm, right?

> +	}
> +
> +	if (!fsm->otg->gadget) {
> +		dev_info(otgd->dev, "otg: can't start till gadget registers\n");
> +		return;
> +	}
> +
> +	otgd->fsm_running = true;
> +kick_fsm:
> +	queue_work(otgd->wq, &otgd->work);
> +}
> +
> +/**
> + * stop the OTG FSM. Stops Host & Gadget controllers as well.
> + * fsm->lock must be held
> + */
> +static void usb_otg_stop_fsm(struct otg_fsm *fsm)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +	int i;
> +
> +	if (!otgd->fsm_running)
> +		return;
> +
> +	/* no more new events queued */
> +	otgd->fsm_running = false;
> +
> +	/* Stop state machine / timers */
> +	for (i = 0; i < ARRAY_SIZE(otgd->timers); i++)
> +		hrtimer_cancel(&otgd->timers[i].timer);
> +
> +	flush_workqueue(otgd->wq);
> +	fsm->otg->state = OTG_STATE_UNDEFINED;
> +
> +	/* stop host/gadget immediately */
> +	if (fsm->protocol == PROTO_HOST)
> +		otg_start_host(fsm, 0);
> +	else if (fsm->protocol == PROTO_GADGET)
> +		otg_start_gadget(fsm, 0);
> +	fsm->protocol = PROTO_UNDEF;
> +}
> +
> +/**
> + * usb_otg_sync_inputs - Sync OTG inputs with the OTG state machine
> + * @fsm:	OTG FSM instance
> + *
> + * Used by the OTG driver to update the inputs to the OTG
> + * state machine.
> + *
> + * Can be called in IRQ context.
> + */
> +void usb_otg_sync_inputs(struct otg_fsm *fsm)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +
> +	/* Don't kick FSM till it has started */
> +	if (!otgd->fsm_running)
> +		return;
> +
> +	/* Kick FSM */
> +	queue_work(otgd->wq, &otgd->work);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
> +
> +/**
> + * usb_otg_kick_fsm - Kick the OTG state machine
> + * @hcd_gcd_device:	Host/Gadget controller device
> + *
> + * Used by USB host/device stack to sync OTG related
> + * events to the OTG state machine.
> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_kick_fsm(struct device *hcd_gcd_device)
> +{
> +	struct usb_otg *otgd;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(usb_otg_get_device(hcd_gcd_device));
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		dev_dbg(hcd_gcd_device, "otg: %s: invalid host/gadget device\n",
> +			__func__);
> +		return -ENODEV;
> +	}
> +
> +	usb_otg_sync_inputs(&otgd->fsm);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
> +
> +/**
> + * usb_otg_register_hcd - Register Host controller to OTG core
> + * @hcd:	Host controller device
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to add/remove the HCD
> + *
> + * This is used by the USB Host stack to register the Host controller
> + * to the OTG core. Host controller must not be started by the
> + * caller as it is left upto the OTG state machine to do so.

I am confused on how to use this function.
- This function should be called before start fsm per usb_otg_start_fsm().
- Called by usb_add_hcd(), so we need call usb_add_hcd() before start fsm.
- If I want to add hcd when switch to host role, and remove hcd when switch
  to peripheral, with this design, I cannot use this function?
- How about split it out of usb_add_hcd()?

> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> +{
> +	struct usb_otg *otgd;
> +	struct device *hcd_dev = hcd->self.controller;
> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		dev_dbg(hcd_dev,
> +			"otg: controller not yet registered. waiting..\n");
> +		/*
> +		 * otg controller might register later. Put the hcd in
> +		 * wait list and call us back when ready
> +		 */
> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
> +			return -EINVAL;
> +		}
> +
> +		return 0;
> +	}
> +
> +	/* HCD will be started by OTG fsm when needed */
> +	mutex_lock(&otgd->fsm.lock);

If call usb_add_hcd() when start host role, deadlock.

> +	if (otgd->primary_hcd.hcd) {
> +		/* probably a shared HCD ? */
> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
> +			dev_err(otg_dev, "otg: primary host already registered\n");
> +			goto err;
> +		}
> +
> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
> +			if (otgd->shared_hcd.hcd) {
> +				dev_err(otg_dev, "otg: shared host already registered\n");
> +				goto err;
> +			}
> +
> +			otgd->shared_hcd.hcd = hcd;
> +			otgd->shared_hcd.irqnum = irqnum;
> +			otgd->shared_hcd.irqflags = irqflags;
> +			otgd->shared_hcd.ops = ops;
> +			dev_info(otg_dev, "otg: shared host %s registered\n",
> +				 dev_name(hcd->self.controller));
> +		} else {
> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
> +				dev_name(hcd->self.controller));
> +			goto err;
> +		}
> +	} else {
> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
> +			goto err;
> +		}
> +
> +		otgd->primary_hcd.hcd = hcd;
> +		otgd->primary_hcd.irqnum = irqnum;
> +		otgd->primary_hcd.irqflags = irqflags;
> +		otgd->primary_hcd.ops = ops;
> +		dev_info(otg_dev, "otg: primary host %s registered\n",
> +			 dev_name(hcd->self.controller));
> +	}
> +
> +	/*
> +	 * we're ready only if we have shared HCD
> +	 * or we don't need shared HCD.
> +	 */
> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
> +		otgd->fsm.otg->host = hcd_to_bus(hcd);

otgd->host = hcd_to_bus(hcd);

> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
> +
> +		/* start FSM */
> +		usb_otg_start_fsm(&otgd->fsm);
> +	} else {
> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> +	}
> +
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +
> +err:
> +	mutex_unlock(&otgd->fsm.lock);
> +	return -EINVAL;

Return non-zero, then if err, do we need call usb_otg_add_hcd() after
usb_otg_register_hcd() fails?

> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> +
> +/**
> + * usb_otg_unregister_hcd - Unregister Host controller from OTG core
> + * @hcd:	Host controller device
> + *
> + * This is used by the USB Host stack to unregister the Host controller
> + * from the OTG core. Ensures that Host controller is not running
> + * on successful return.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> +{
> +	struct usb_otg *otgd;
> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		/* are we in wait list? */
> +		if (!usb_otg_hcd_wait_remove(hcd))
> +			return 0;
> +
> +		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (hcd == otgd->primary_hcd.hcd) {
> +		otgd->primary_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else if (hcd == otgd->shared_hcd.hcd) {
> +		otgd->shared_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else {
> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	/* stop FSM & Host */
> +	usb_otg_stop_fsm(&otgd->fsm);
> +	otgd->fsm.otg->host = NULL;
> +
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> +
> +/**
> + * usb_otg_register_gadget - Register Gadget controller to OTG core
> + * @gadget:	Gadget controller
> + *
> + * This is used by the USB Gadget stack to register the Gadget controller
> + * to the OTG core. Gadget controller must not be started by the
> + * caller as it is left upto the OTG state machine to do so.
> + *
> + * Gadget core must call this only when all resources required for
> + * gadget controller to run are available.
> + * i.e. gadget function driver is available.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops)
> +{
> +	struct usb_otg *otgd;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		dev_dbg(gadget_dev,
> +			"otg: controller not yet registered. waiting..\n");
> +		/*
> +		 * otg controller might register later. Put the gadget in
> +		 * wait list and call us back when ready
> +		 */
> +		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
> +			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
> +			return -EINVAL;
> +		}
> +
> +		return 0;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (otgd->fsm.otg->gadget) {
> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	otgd->fsm.otg->gadget = gadget;
> +	otgd->gadget_ops = ops;
> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> +		 dev_name(&gadget->dev));
> +
> +	/* start FSM */
> +	usb_otg_start_fsm(&otgd->fsm);
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> +
> +/**
> + * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
> + * @gadget:	Gadget controller
> + *
> + * This is used by the USB Gadget stack to unregister the Gadget controller
> + * from the OTG core. Ensures that Gadget controller is not running
> + * on successful return.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> +{
> +	struct usb_otg *otgd;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otgd = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otgd) {
> +		/* are we in wait list? */
> +		if (!usb_otg_gadget_wait_remove(gadget))
> +			return 0;
> +
> +		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otgd->fsm.lock);
> +	if (otgd->fsm.otg->gadget != gadget) {
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		mutex_unlock(&otgd->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	/* Stop FSM & gadget */
> +	usb_otg_stop_fsm(&otgd->fsm);
> +	otgd->fsm.otg->gadget = NULL;
> +	mutex_unlock(&otgd->fsm.lock);
> +
> +	dev_info(otg_dev, "otg: gadget %s unregistered\n",
> +		 dev_name(&gadget->dev));
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
> +
> +/**
> + * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
> + * @fsm:	otg_fsm data structure
> + *
> + * This is used by the OTG controller driver to get it's device node
> + * from any of the otg_fsm->ops.
> + */
> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +
> +	return otgd->dev;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
> diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
> new file mode 100644
> index 0000000..05331f0
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.h
> @@ -0,0 +1,71 @@
> +/**
> + * drivers/usb/common/usb-otg.h - USB OTG core local header
> + *
> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Roger Quadros <rogerq@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
> +#define __DRIVERS_USB_COMMON_USB_OTG_H
> +
> +/*
> + *  A-DEVICE timing constants
> + */
> +
> +/* Wait for VBUS Rise  */
> +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
> +					 * a_wait_vrise_tmr: section 7.4.5.1
> +					 * TA_VBUS_RISE <= 100ms, section 4.4
> +					 * Table 4-1: Electrical Characteristics
> +					 * ->DC Electrical Timing
> +					 */
> +/* Wait for VBUS Fall  */
> +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
> +					 * a_wait_vfall_tmr: section: 7.4.5.2
> +					 */
> +/* Wait for B-Connect */
> +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
> +					 * TA_WAIT_BCON: should be between 1100
> +					 * and 30000 ms, section 5.5, Table 5-1
> +					 */
> +/* A-Idle to B-Disconnect */
> +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
> +					 * TA_AIDL_BDIS: section 5.5, Table 5-1
> +					 */
> +/* B-Idle to A-Disconnect */
> +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
> +					 * 500ms is used for B switch to host
> +					 * for safe
> +					 */
> +
> +/*
> + * B-device timing constants
> + */
> +
> +/* Data-Line Pulse Time*/
> +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
> +					 * section:5.1.3
> +					 */
> +/* SRP Fail Time  */
> +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
> +					 * section:5.1.6
> +					 */
> +/* A-SE0 to B-Reset  */
> +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
> +/* SE0 Time Before SRP */
> +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
> +/* SSEND time before SRP */
> +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
> +
> +#define TB_SESS_VLD          (1000)
> +
> +#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
> index a99c89e..b468a9f 100644
> --- a/drivers/usb/core/Kconfig
> +++ b/drivers/usb/core/Kconfig
> @@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
>  	  If you are unsure about this, say N here.
>  
>  config USB_OTG
> -	bool "OTG support"
> +	bool "OTG/Dual-role support"
>  	depends on PM
>  	default n
>  	help
> @@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
>  	  and software costs by not supporting external hubs.  So
>  	  are "Embedded Hosts" that don't offer OTG support.
>  
> -config USB_OTG_FSM
> -	tristate "USB 2.0 OTG FSM implementation"
> -	depends on USB
> -	select USB_OTG
> -	select USB_PHY
> -	help
> -	  Implements OTG Finite State Machine as specified in On-The-Go
> -	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
> -
>  config USB_ULPI_BUS
>  	tristate "USB ULPI PHY interface support"
>  	depends on USB_SUPPORT
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index bd1dcf8..38cabe0 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -10,19 +10,100 @@
>  #define __LINUX_USB_OTG_H
>  
>  #include <linux/phy/phy.h>
> +#include <linux/device.h>
> +#include <linux/hrtimer.h>
> +#include <linux/ktime.h>
> +#include <linux/usb.h>
> +#include <linux/usb/hcd.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/usb/otg-fsm.h>
>  #include <linux/usb/phy.h>
>  
> +/**
> + * struct otg_hcd - host controller state and interface
> + *
> + * @hcd: host controller
> + * @irqnum: irq number
> + * @irqflags: irq flags
> + * @ops: otg to host controller interface
> + */
> +struct otg_hcd {
> +	struct usb_hcd *hcd;
> +	unsigned int irqnum;
> +	unsigned long irqflags;
> +	struct otg_hcd_ops *ops;
> +};
> +
> +struct usb_otg;
> +
> +/**
> + * struct otg_timer - otg timer data
> + *
> + * @timer: high resolution timer
> + * @timeout: timeout value
> + * @timetout_bit: pointer to variable that is set on timeout
> + * @otgd: usb otg data
> + */
> +struct otg_timer {
> +	struct hrtimer timer;
> +	ktime_t timeout;
> +	/* callback data */
> +	int *timeout_bit;
> +	struct usb_otg *otgd;
> +};
> +
> +/**
> + * struct usb_otg - usb otg controller state
> + *
> + * @default_a: Indicates we are an A device. i.e. Host.
> + * @phy: USB phy interface
> + * @usb_phy: old usb_phy interface
> + * @host: host controller bus
> + * @gadget: gadget device
> + * @state: current otg state
> + * @dev: otg controller device
> + * @caps: otg capabilities revision, hnp, srp, etc
> + * @fsm: otg finite state machine
> + * @fsm_ops: controller hooks for the state machine
> + * ------- internal use only -------
> + * @primary_hcd: primary host state and interface
> + * @shared_hcd: shared host state and interface
> + * @gadget_ops: gadget interface
> + * @timers: otg timers for state machine
> + * @list: list of otg controllers
> + * @work: otg state machine work
> + * @wq: otg state machine work queue
> + * @fsm_running: state machine running/stopped indicator
> + */
>  struct usb_otg {
>  	u8			default_a;
>  
>  	struct phy		*phy;
>  	/* old usb_phy interface */
>  	struct usb_phy		*usb_phy;
> +

add a blank line?

>  	struct usb_bus		*host;
>  	struct usb_gadget	*gadget;
>  
>  	enum usb_otg_state	state;
>  
> +	struct device *dev;
> +	struct usb_otg_caps *caps;
> +	struct otg_fsm fsm;
> +	struct otg_fsm_ops fsm_ops;
> +
> +	/* internal use only */
> +	struct otg_hcd primary_hcd;
> +	struct otg_hcd shared_hcd;
> +	struct otg_gadget_ops *gadget_ops;
> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
> +	struct list_head list;
> +	struct work_struct work;
> +	struct workqueue_struct *wq;
> +	bool fsm_running;

Should fsm_running be added in otg_fsm struct?

> +	/* use otg->fsm.lock for serializing access */
> +
> +/*------------- deprecated interface -----------------------------*/
>  	/* bind/unbind the host controller */
>  	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
>  
> @@ -38,7 +119,7 @@ struct usb_otg {
>  
>  	/* start or continue HNP role switch */
>  	int	(*start_hnp)(struct usb_otg *otg);
> -
> +/*---------------------------------------------------------------*/
>  };
>  
>  /**
> @@ -56,8 +137,105 @@ struct usb_otg_caps {
>  	bool adp_support;
>  };
>  
> +/**
> + * struct usb_otg_config - otg controller configuration
> + * @caps: otg capabilities of the controller
> + * @ops: otg fsm operations
> + * @otg_timeouts: override default otg fsm timeouts
> + */
> +struct usb_otg_config {
> +	struct usb_otg_caps otg_caps;
> +	struct otg_fsm_ops *fsm_ops;
> +	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
> +};
> +
>  extern const char *usb_otg_state_string(enum usb_otg_state state);
>  
> +enum usb_dr_mode {
> +	USB_DR_MODE_UNKNOWN,
> +	USB_DR_MODE_HOST,
> +	USB_DR_MODE_PERIPHERAL,
> +	USB_DR_MODE_OTG,
> +};
> +
> +#if IS_ENABLED(CONFIG_USB_OTG)
> +struct otg_fsm *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config);
> +int usb_otg_unregister(struct device *dev);
> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +			 unsigned long irqflags, struct otg_hcd_ops *ops);
> +int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops);
> +int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> +void usb_otg_sync_inputs(struct otg_fsm *fsm);
> +int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> +int usb_otg_start_host(struct otg_fsm *fsm, int on);
> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> +
> +#else /* CONFIG_USB_OTG */
> +
> +static inline struct otg_fsm *usb_otg_register(struct device *dev,
> +					       struct usb_otg_config *config)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
> +static inline int usb_otg_unregister(struct device *dev)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> +				       unsigned long irqflags,
> +				       struct otg_hcd_ops *ops)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
> +					  struct otg_gadget_ops *ops)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
> +{
> +}
> +
> +static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> +{
> +	return NULL;
> +}
> +
> +static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +#endif /* CONFIG_USB_OTG */
> +
> +/*------------- deprecated interface -----------------------------*/
>  /* Context: can sleep */
>  static inline int
>  otg_start_hnp(struct usb_otg *otg)
> @@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
>  	return -ENOTSUPP;
>  }
>  
> +/*---------------------------------------------------------------*/
> +
>  /* for OTG controller drivers (and maybe other stuff) */
>  extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
>  
> -enum usb_dr_mode {
> -	USB_DR_MODE_UNKNOWN,
> -	USB_DR_MODE_HOST,
> -	USB_DR_MODE_PERIPHERAL,
> -	USB_DR_MODE_OTG,
> -};
> -
>  #endif /* __LINUX_USB_OTG_H */
> -- 
> 2.1.4
> 

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

* Re: [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support
  2015-08-24 13:21 ` [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros
@ 2015-09-07  7:53   ` Li Jun
  2015-09-07  9:51     ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Li Jun @ 2015-09-07  7:53 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:24PM +0300, Roger Quadros wrote:
> DRD mode is a reduced functionality OTG mode. In this mode
> we don't support SRP, HNP and dynamic role-swap.
> 
> In DRD operation, the controller mode (Host or Peripheral)
> is decided based on the ID pin status. Once a cable plug (Type-A
> or Type-B) is attached the controller selects the state
> and doesn't change till the cable in unplugged and a different
> cable type is inserted.
> 
> As we don't need most of the complex OTG states and OTG timers
> we implement a lean DRD state machine in usb-otg.c.
> The DRD state machine is only interested in 2 hardware inputs
> 'id' and 'b_sess_vld'.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/usb/common/usb-otg.c | 178 +++++++++++++++++++++++++++++++++++++++++--
>  include/linux/usb/otg-fsm.h  |   5 ++
>  include/linux/usb/otg.h      |   2 +
>  3 files changed, 177 insertions(+), 8 deletions(-)
> 

... ...

> +/* Called when entering a DRD state */
> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> +{
> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> +
> +	if (fsm->otg->state == new_state)
> +		return;
> +
> +	fsm->state_changed = 1;
> +	dev_dbg(otgd->dev, "otg: set state: %s\n",
> +		usb_otg_state_string(new_state));
> +	switch (new_state) {
> +	case OTG_STATE_B_IDLE:
> +		drd_set_protocol(fsm, PROTO_UNDEF);

You didn't address this comment for your previous version.

otg_drv_vbus(fsm, 0);

> +		break;
> +	case OTG_STATE_B_PERIPHERAL:
> +		drd_set_protocol(fsm, PROTO_GADGET);

otg_drv_vbus(fsm, 0);

> +		break;
> +	case OTG_STATE_A_HOST:

otg_drv_vbus(fsm, 1);

> +		drd_set_protocol(fsm, PROTO_HOST);
> +		break;
> +	case OTG_STATE_UNDEFINED:
> +	case OTG_STATE_B_SRP_INIT:
> +	case OTG_STATE_B_WAIT_ACON:
> +	case OTG_STATE_B_HOST:
> +	case OTG_STATE_A_IDLE:
> +	case OTG_STATE_A_WAIT_VRISE:
> +	case OTG_STATE_A_WAIT_BCON:
> +	case OTG_STATE_A_SUSPEND:
> +	case OTG_STATE_A_PERIPHERAL:
> +	case OTG_STATE_A_WAIT_VFALL:
> +	case OTG_STATE_A_VBUS_ERR:
> +	default:
> +		dev_warn(otgd->dev, "%s: otg: invalid state: %s\n",
> +			 __func__, usb_otg_state_string(new_state));
> +		break;
> +	}
> +
> +	fsm->otg->state = new_state;
> +}
> +
... ...

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

* Re: [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support
  2015-09-07  7:53   ` Li Jun
@ 2015-09-07  9:51     ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-07  9:51 UTC (permalink / raw)
  To: Li Jun
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On 07/09/15 10:53, Li Jun wrote:
> On Mon, Aug 24, 2015 at 04:21:24PM +0300, Roger Quadros wrote:
>> DRD mode is a reduced functionality OTG mode. In this mode
>> we don't support SRP, HNP and dynamic role-swap.
>>
>> In DRD operation, the controller mode (Host or Peripheral)
>> is decided based on the ID pin status. Once a cable plug (Type-A
>> or Type-B) is attached the controller selects the state
>> and doesn't change till the cable in unplugged and a different
>> cable type is inserted.
>>
>> As we don't need most of the complex OTG states and OTG timers
>> we implement a lean DRD state machine in usb-otg.c.
>> The DRD state machine is only interested in 2 hardware inputs
>> 'id' and 'b_sess_vld'.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/usb/common/usb-otg.c | 178 +++++++++++++++++++++++++++++++++++++++++--
>>  include/linux/usb/otg-fsm.h  |   5 ++
>>  include/linux/usb/otg.h      |   2 +
>>  3 files changed, 177 insertions(+), 8 deletions(-)
>>
> 
> ... ...
> 
>> +/* Called when entering a DRD state */
>> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	if (fsm->otg->state == new_state)
>> +		return;
>> +
>> +	fsm->state_changed = 1;
>> +	dev_dbg(otgd->dev, "otg: set state: %s\n",
>> +		usb_otg_state_string(new_state));
>> +	switch (new_state) {
>> +	case OTG_STATE_B_IDLE:
>> +		drd_set_protocol(fsm, PROTO_UNDEF);
> 
> You didn't address this comment for your previous version.
> 
> otg_drv_vbus(fsm, 0);
> 
>> +		break;
>> +	case OTG_STATE_B_PERIPHERAL:
>> +		drd_set_protocol(fsm, PROTO_GADGET);
> 
> otg_drv_vbus(fsm, 0);
> 
>> +		break;
>> +	case OTG_STATE_A_HOST:
> 
> otg_drv_vbus(fsm, 1);
> 

Sorry, I missed it. Will add in next version.

--
cheers,
-roger

>> +		drd_set_protocol(fsm, PROTO_HOST);
>> +		break;
>> +	case OTG_STATE_UNDEFINED:
>> +	case OTG_STATE_B_SRP_INIT:
>> +	case OTG_STATE_B_WAIT_ACON:
>> +	case OTG_STATE_B_HOST:
>> +	case OTG_STATE_A_IDLE:
>> +	case OTG_STATE_A_WAIT_VRISE:
>> +	case OTG_STATE_A_WAIT_BCON:
>> +	case OTG_STATE_A_SUSPEND:
>> +	case OTG_STATE_A_PERIPHERAL:
>> +	case OTG_STATE_A_WAIT_VFALL:
>> +	case OTG_STATE_A_VBUS_ERR:
>> +	default:
>> +		dev_warn(otgd->dev, "%s: otg: invalid state: %s\n",
>> +			 __func__, usb_otg_state_string(new_state));
>> +		break;
>> +	}
>> +
>> +	fsm->otg->state = new_state;
>> +}
>> +
> ... ...
> 

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

* Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  2015-09-07  1:24   ` Peter Chen
@ 2015-09-07  9:57     ` Roger Quadros
  2015-09-08  6:54       ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-07  9:57 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 07/09/15 04:24, Peter Chen wrote:
> On Mon, Aug 24, 2015 at 04:21:15PM +0300, Roger Quadros wrote:
>> This is to prevent missing symbol build error if OTG is
>> enabled (built-in) and HCD core (CONFIG_USB) is module.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> Acked-by: Peter Chen <peter.chen@freescale.com>
>> ---
>>  drivers/usb/common/usb-otg-fsm.c | 6 ++++--
>>  drivers/usb/phy/phy-fsl-usb.c    | 2 ++
>>  include/linux/usb/otg-fsm.h      | 1 +
>>  3 files changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
>> index a46f29a..6e56c8c 100644
>> --- a/drivers/usb/common/usb-otg-fsm.c
>> +++ b/drivers/usb/common/usb-otg-fsm.c
>> @@ -165,8 +165,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>>  		otg_loc_conn(fsm, 0);
>>  		otg_loc_sof(fsm, 1);
>>  		otg_set_protocol(fsm, PROTO_HOST);
>> -		usb_bus_start_enum(fsm->otg->host,
>> -				fsm->otg->host->otg_port);usb_bus_start_enum
>> +		if (fsm->ops->start_enum) {
>> +			fsm->ops->start_enum(fsm->otg->host,
>> +					     fsm->otg->host->otg_port);
>> +		}
>>  		break;
>>  	case OTG_STATE_A_IDLE:
>>  		otg_drv_vbus(fsm, 0);
>> diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
>> index ee3f2c2..19541ed 100644
>> --- a/drivers/usb/phy/phy-fsl-usb.c
>> +++ b/drivers/usb/phy/phy-fsl-usb.c
>> @@ -783,6 +783,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
>>  
>>  	.start_host = fsl_otg_start_host,
>>  	.start_gadget = fsl_otg_start_gadget,
>> +
>> +	.start_enum = usb_bus_start_enum,
>>  };
>>  
>>  /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
>> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
>> index 672551c..75e82cc 100644
>> --- a/include/linux/usb/otg-fsm.h
>> +++ b/include/linux/usb/otg-fsm.h
>> @@ -199,6 +199,7 @@ struct otg_fsm_ops {
>>  	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
>>  	int	(*start_host)(struct otg_fsm *fsm, int on);
>>  	int	(*start_gadget)(struct otg_fsm *fsm, int on);
>> +	int	(*start_enum)(struct usb_bus *bus, unsigned port_num);
>>  };
>>  
>>  
> 
> Get one build warning:
> 
> In file included from /u/home/b29397/work/projects/usb/drivers/usb/chipidea/udc.c:23:0:
> /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: 'struct usb_bus' declared inside parameter list
>   int (*start_enum)(struct usb_bus *bus, unsigned port_num);
>                              ^
> /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: its scope is only this definition or declaration, which is probably not what you want
> 
> It probably dues to we should not have struct usb_bus* at udc driver
> 
How about changing it to struct otg_fsm instead like the other APIs?
And do we leave usb_bus_start_enum() as it is?

cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-07  1:23   ` Peter Chen
@ 2015-09-07 10:23     ` Roger Quadros
  2015-09-08  8:31       ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-07 10:23 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 07/09/15 04:23, Peter Chen wrote:
> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>> + * This is used by the USB Host stack to register the Host controller
>> + * to the OTG core. Host controller must not be started by the
>> + * caller as it is left upto the OTG state machine to do so.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *hcd_dev = hcd->self.controller;
>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>> +
> 
> One big problem here is: there are two designs for current (IP) driver
> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> Another one doesn't do this, roothub's parent is core device (or otg device
> in your patch), like chipidea and dwc2.
> 
> Then, otg_dev will be glue layer device for chipidea after that.

OK. Let's add a way for the otg controller driver to provide the host and gadget
information to the otg core for such devices like chipidea and dwc2.

This API must be called before the hcd/gadget-driver is added so that the otg
core knows it's linked to an OTG controller.

Any better idea?

cheers,
-roger

> 
> Peter
> 
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		dev_dbg(hcd_dev,
>> +			"otg: controller not yet registered. waiting..\n");
>> +		/*
>> +		 * otg controller might register later. Put the hcd in
>> +		 * wait list and call us back when ready
>> +		 */
>> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
>> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
>> +			return -EINVAL;
>> +		}
>> +
>> +		return 0;
>> +	}
>> +
>> +	/* HCD will be started by OTG fsm when needed */
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (otgd->primary_hcd.hcd) {
>> +		/* probably a shared HCD ? */
>> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
>> +			dev_err(otg_dev, "otg: primary host already registered\n");
>> +			goto err;
>> +		}
>> +
>> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
>> +			if (otgd->shared_hcd.hcd) {
>> +				dev_err(otg_dev, "otg: shared host already registered\n");
>> +				goto err;
>> +			}
>> +
>> +			otgd->shared_hcd.hcd = hcd;
>> +			otgd->shared_hcd.irqnum = irqnum;
>> +			otgd->shared_hcd.irqflags = irqflags;
>> +			otgd->shared_hcd.ops = ops;
>> +			dev_info(otg_dev, "otg: shared host %s registered\n",
>> +				 dev_name(hcd->self.controller));
>> +		} else {
>> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
>> +				dev_name(hcd->self.controller));
>> +			goto err;
>> +		}
>> +	} else {
>> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
>> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
>> +			goto err;
>> +		}
>> +
>> +		otgd->primary_hcd.hcd = hcd;
>> +		otgd->primary_hcd.irqnum = irqnum;
>> +		otgd->primary_hcd.irqflags = irqflags;
>> +		otgd->primary_hcd.ops = ops;
>> +		dev_info(otg_dev, "otg: primary host %s registered\n",
>> +			 dev_name(hcd->self.controller));
>> +	}
>> +
>> +	/*
>> +	 * we're ready only if we have shared HCD
>> +	 * or we don't need shared HCD.
>> +	 */
>> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
>> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
>> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
>> +
>> +		/* start FSM */
>> +		usb_otg_start_fsm(&otgd->fsm);
>> +	} else {
>> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
>> +	}
>> +
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +
>> +err:
>> +	mutex_unlock(&otgd->fsm.lock);
>> +	return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
>> +
>> +/**
>> + * usb_otg_unregister_hcd - Unregister Host controller from OTG core
>> + * @hcd:	Host controller device
>> + *
>> + * This is used by the USB Host stack to unregister the Host controller
>> + * from the OTG core. Ensures that Host controller is not running
>> + * on successful return.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_unregister_hcd(struct usb_hcd *hcd)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		/* are we in wait list? */
>> +		if (!usb_otg_hcd_wait_remove(hcd))
>> +			return 0;
>> +
>> +		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (hcd == otgd->primary_hcd.hcd) {
>> +		otgd->primary_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else if (hcd == otgd->shared_hcd.hcd) {
>> +		otgd->shared_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else {
>> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* stop FSM & Host */
>> +	usb_otg_stop_fsm(&otgd->fsm);
>> +	otgd->fsm.otg->host = NULL;
>> +
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
>> +
>> +/**
>> + * usb_otg_register_gadget - Register Gadget controller to OTG core
>> + * @gadget:	Gadget controller
>> + *
>> + * This is used by the USB Gadget stack to register the Gadget controller
>> + * to the OTG core. Gadget controller must not be started by the
>> + * caller as it is left upto the OTG state machine to do so.
>> + *
>> + * Gadget core must call this only when all resources required for
>> + * gadget controller to run are available.
>> + * i.e. gadget function driver is available.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		dev_dbg(gadget_dev,
>> +			"otg: controller not yet registered. waiting..\n");
>> +		/*
>> +		 * otg controller might register later. Put the gadget in
>> +		 * wait list and call us back when ready
>> +		 */
>> +		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
>> +			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
>> +			return -EINVAL;
>> +		}
>> +
>> +		return 0;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (otgd->fsm.otg->gadget) {
>> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	otgd->fsm.otg->gadget = gadget;
>> +	otgd->gadget_ops = ops;
>> +	dev_info(otg_dev, "otg: gadget %s registered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	/* start FSM */
>> +	usb_otg_start_fsm(&otgd->fsm);
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
>> +
>> +/**
>> + * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
>> + * @gadget:	Gadget controller
>> + *
>> + * This is used by the USB Gadget stack to unregister the Gadget controller
>> + * from the OTG core. Ensures that Gadget controller is not running
>> + * on successful return.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_unregister_gadget(struct usb_gadget *gadget)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		/* are we in wait list? */
>> +		if (!usb_otg_gadget_wait_remove(gadget))
>> +			return 0;
>> +
>> +		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (otgd->fsm.otg->gadget != gadget) {
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Stop FSM & gadget */
>> +	usb_otg_stop_fsm(&otgd->fsm);
>> +	otgd->fsm.otg->gadget = NULL;
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	dev_info(otg_dev, "otg: gadget %s unregistered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
>> +
>> +/**
>> + * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
>> + * @fsm:	otg_fsm data structure
>> + *
>> + * This is used by the OTG controller driver to get it's device node
>> + * from any of the otg_fsm->ops.
>> + */
>> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	return otgd->dev;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
>> diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
>> new file mode 100644
>> index 0000000..05331f0
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.h
>> @@ -0,0 +1,71 @@
>> +/**
>> + * drivers/usb/common/usb-otg.h - USB OTG core local header
>> + *
>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Roger Quadros <rogerq@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
>> +#define __DRIVERS_USB_COMMON_USB_OTG_H
>> +
>> +/*
>> + *  A-DEVICE timing constants
>> + */
>> +
>> +/* Wait for VBUS Rise  */
>> +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
>> +					 * a_wait_vrise_tmr: section 7.4.5.1
>> +					 * TA_VBUS_RISE <= 100ms, section 4.4
>> +					 * Table 4-1: Electrical Characteristics
>> +					 * ->DC Electrical Timing
>> +					 */
>> +/* Wait for VBUS Fall  */
>> +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
>> +					 * a_wait_vfall_tmr: section: 7.4.5.2
>> +					 */
>> +/* Wait for B-Connect */
>> +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
>> +					 * TA_WAIT_BCON: should be between 1100
>> +					 * and 30000 ms, section 5.5, Table 5-1
>> +					 */
>> +/* A-Idle to B-Disconnect */
>> +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
>> +					 * TA_AIDL_BDIS: section 5.5, Table 5-1
>> +					 */
>> +/* B-Idle to A-Disconnect */
>> +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
>> +					 * 500ms is used for B switch to host
>> +					 * for safe
>> +					 */
>> +
>> +/*
>> + * B-device timing constants
>> + */
>> +
>> +/* Data-Line Pulse Time*/
>> +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
>> +					 * section:5.1.3
>> +					 */
>> +/* SRP Fail Time  */
>> +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
>> +					 * section:5.1.6
>> +					 */
>> +/* A-SE0 to B-Reset  */
>> +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
>> +/* SE0 Time Before SRP */
>> +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
>> +/* SSEND time before SRP */
>> +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
>> +
>> +#define TB_SESS_VLD          (1000)
>> +
>> +#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
>> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
>> index a99c89e..b468a9f 100644
>> --- a/drivers/usb/core/Kconfig
>> +++ b/drivers/usb/core/Kconfig
>> @@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
>>  	  If you are unsure about this, say N here.
>>  
>>  config USB_OTG
>> -	bool "OTG support"
>> +	bool "OTG/Dual-role support"
>>  	depends on PM
>>  	default n
>>  	help
>> @@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
>>  	  and software costs by not supporting external hubs.  So
>>  	  are "Embedded Hosts" that don't offer OTG support.
>>  
>> -config USB_OTG_FSM
>> -	tristate "USB 2.0 OTG FSM implementation"
>> -	depends on USB
>> -	select USB_OTG
>> -	select USB_PHY
>> -	help
>> -	  Implements OTG Finite State Machine as specified in On-The-Go
>> -	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
>> -
>>  config USB_ULPI_BUS
>>  	tristate "USB ULPI PHY interface support"
>>  	depends on USB_SUPPORT
>> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
>> index bd1dcf8..38cabe0 100644
>> --- a/include/linux/usb/otg.h
>> +++ b/include/linux/usb/otg.h
>> @@ -10,19 +10,100 @@
>>  #define __LINUX_USB_OTG_H
>>  
>>  #include <linux/phy/phy.h>
>> +#include <linux/device.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/ktime.h>
>> +#include <linux/usb.h>
>> +#include <linux/usb/hcd.h>
>> +#include <linux/usb/gadget.h>
>> +#include <linux/usb/otg-fsm.h>
>>  #include <linux/usb/phy.h>
>>  
>> +/**
>> + * struct otg_hcd - host controller state and interface
>> + *
>> + * @hcd: host controller
>> + * @irqnum: irq number
>> + * @irqflags: irq flags
>> + * @ops: otg to host controller interface
>> + */
>> +struct otg_hcd {
>> +	struct usb_hcd *hcd;
>> +	unsigned int irqnum;
>> +	unsigned long irqflags;
>> +	struct otg_hcd_ops *ops;
>> +};
>> +
>> +struct usb_otg;
>> +
>> +/**
>> + * struct otg_timer - otg timer data
>> + *
>> + * @timer: high resolution timer
>> + * @timeout: timeout value
>> + * @timetout_bit: pointer to variable that is set on timeout
>> + * @otgd: usb otg data
>> + */
>> +struct otg_timer {
>> +	struct hrtimer timer;
>> +	ktime_t timeout;
>> +	/* callback data */
>> +	int *timeout_bit;
>> +	struct usb_otg *otgd;
>> +};
>> +
>> +/**
>> + * struct usb_otg - usb otg controller state
>> + *
>> + * @default_a: Indicates we are an A device. i.e. Host.
>> + * @phy: USB phy interface
>> + * @usb_phy: old usb_phy interface
>> + * @host: host controller bus
>> + * @gadget: gadget device
>> + * @state: current otg state
>> + * @dev: otg controller device
>> + * @caps: otg capabilities revision, hnp, srp, etc
>> + * @fsm: otg finite state machine
>> + * @fsm_ops: controller hooks for the state machine
>> + * ------- internal use only -------
>> + * @primary_hcd: primary host state and interface
>> + * @shared_hcd: shared host state and interface
>> + * @gadget_ops: gadget interface
>> + * @timers: otg timers for state machine
>> + * @list: list of otg controllers
>> + * @work: otg state machine work
>> + * @wq: otg state machine work queue
>> + * @fsm_running: state machine running/stopped indicator
>> + */
>>  struct usb_otg {
>>  	u8			default_a;
>>  
>>  	struct phy		*phy;
>>  	/* old usb_phy interface */
>>  	struct usb_phy		*usb_phy;
>> +
>>  	struct usb_bus		*host;
>>  	struct usb_gadget	*gadget;
>>  
>>  	enum usb_otg_state	state;
>>  
>> +	struct device *dev;
>> +	struct usb_otg_caps *caps;
>> +	struct otg_fsm fsm;
>> +	struct otg_fsm_ops fsm_ops;
>> +
>> +	/* internal use only */
>> +	struct otg_hcd primary_hcd;
>> +	struct otg_hcd shared_hcd;
>> +	struct otg_gadget_ops *gadget_ops;
>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
>> +	struct list_head list;
>> +	struct work_struct work;
>> +	struct workqueue_struct *wq;
>> +	bool fsm_running;
>> +	/* use otg->fsm.lock for serializing access */
>> +
>> +/*------------- deprecated interface -----------------------------*/
>>  	/* bind/unbind the host controller */
>>  	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
>>  
>> @@ -38,7 +119,7 @@ struct usb_otg {
>>  
>>  	/* start or continue HNP role switch */
>>  	int	(*start_hnp)(struct usb_otg *otg);
>> -
>> +/*---------------------------------------------------------------*/
>>  };
>>  
>>  /**
>> @@ -56,8 +137,105 @@ struct usb_otg_caps {
>>  	bool adp_support;
>>  };
>>  
>> +/**
>> + * struct usb_otg_config - otg controller configuration
>> + * @caps: otg capabilities of the controller
>> + * @ops: otg fsm operations
>> + * @otg_timeouts: override default otg fsm timeouts
>> + */
>> +struct usb_otg_config {
>> +	struct usb_otg_caps otg_caps;
>> +	struct otg_fsm_ops *fsm_ops;
>> +	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
>> +};
>> +
>>  extern const char *usb_otg_state_string(enum usb_otg_state state);
>>  
>> +enum usb_dr_mode {
>> +	USB_DR_MODE_UNKNOWN,
>> +	USB_DR_MODE_HOST,
>> +	USB_DR_MODE_PERIPHERAL,
>> +	USB_DR_MODE_OTG,
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_USB_OTG)
>> +struct otg_fsm *usb_otg_register(struct device *dev,
>> +				 struct usb_otg_config *config);
>> +int usb_otg_unregister(struct device *dev);
>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +			 unsigned long irqflags, struct otg_hcd_ops *ops);
>> +int usb_otg_unregister_hcd(struct usb_hcd *hcd);
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops);
>> +int usb_otg_unregister_gadget(struct usb_gadget *gadget);
>> +void usb_otg_sync_inputs(struct otg_fsm *fsm);
>> +int usb_otg_kick_fsm(struct device *hcd_gcd_device);
>> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
>> +int usb_otg_start_host(struct otg_fsm *fsm, int on);
>> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
>> +
>> +#else /* CONFIG_USB_OTG */
>> +
>> +static inline struct otg_fsm *usb_otg_register(struct device *dev,
>> +					       struct usb_otg_config *config)
>> +{
>> +	return ERR_PTR(-ENOTSUPP);
>> +}
>> +
>> +static inline int usb_otg_unregister(struct device *dev)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +				       unsigned long irqflags,
>> +				       struct otg_hcd_ops *ops)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +					  struct otg_gadget_ops *ops)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
>> +{
>> +}
>> +
>> +static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +#endif /* CONFIG_USB_OTG */
>> +
>> +/*------------- deprecated interface -----------------------------*/
>>  /* Context: can sleep */
>>  static inline int
>>  otg_start_hnp(struct usb_otg *otg)
>> @@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
>>  	return -ENOTSUPP;
>>  }
>>  
>> +/*---------------------------------------------------------------*/
>> +
>>  /* for OTG controller drivers (and maybe other stuff) */
>>  extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
>>  
>> -enum usb_dr_mode {
>> -	USB_DR_MODE_UNKNOWN,
>> -	USB_DR_MODE_HOST,
>> -	USB_DR_MODE_PERIPHERAL,
>> -	USB_DR_MODE_OTG,
>> -};
>> -
>>  #endif /* __LINUX_USB_OTG_H */
>> -- 
>> 2.1.4
>>
> 

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-07  7:40   ` Li Jun
@ 2015-09-07 10:53     ` Roger Quadros
  2015-09-09  6:20       ` Li Jun
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-07 10:53 UTC (permalink / raw)
  To: Li Jun
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On 07/09/15 10:40, Li Jun wrote:
> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>> The OTG core instantiates the OTG Finite State Machine
>> per OTG controller and manages starting/stopping the
>> host and gadget controllers based on the bus state.
>>
>> It provides APIs for the following tasks
>>
>> - Registering an OTG capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  MAINTAINERS                  |    4 +-
>>  drivers/usb/Kconfig          |    2 +-
>>  drivers/usb/Makefile         |    1 +
>>  drivers/usb/common/Makefile  |    3 +-
>>  drivers/usb/common/usb-otg.c | 1061 ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/usb/common/usb-otg.h |   71 +++
>>  drivers/usb/core/Kconfig     |   11 +-
>>  include/linux/usb/otg.h      |  189 +++++++-
>>  8 files changed, 1321 insertions(+), 21 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>  create mode 100644 drivers/usb/common/usb-otg.h
>>
> 
> ... ...
> 
>> +
>> +/**
>> + * Get OTG device from host or gadget device.
>> + *
>> + * For non device tree boot, the OTG controller is assumed to be
>> + * the parent of the host/gadget device.
> 
> This assumption/restriction maybe a problem, as I pointed in your previous
> version, usb_create_hcd() use the passed dev as its dev, but,
> usb_add_gadget_udc() use the passed dev as its parent dev, so often the
> host and gadget don't share the same parent device, at least it doesn't
> apply to chipidea case.

Let's provide a way for OTG driver to provide the OTG core exactly which is
the related host/gadget device.

> 
>> + * For device tree boot, the OTG controller is derived from the
>> + * "otg-controller" property.
>> + */
>> +static struct device *usb_otg_get_device(struct device *hcd_gcd_dev)
>> +{
>> +	struct device *otg_dev;
>> +
>> +	if (!hcd_gcd_dev)
>> +		return NULL;
>> +
>> +	if (hcd_gcd_dev->of_node) {
>> +		struct device_node *np;
>> +		struct platform_device *pdev;
>> +
>> +		np = of_parse_phandle(hcd_gcd_dev->of_node, "otg-controller",
>> +				      0);
>> +		if (!np)
>> +			goto legacy;	/* continue legacy way */
>> +
>> +		pdev = of_find_device_by_node(np);
>> +		of_node_put(np);
>> +		if (!pdev) {
>> +			dev_err(&pdev->dev, "couldn't get otg-controller device\n");
>> +			return NULL;
>> +		}
>> +
>> +		otg_dev = &pdev->dev;
>> +		return otg_dev;
>> +	}
>> +
>> +legacy:
>> +	/* otg device is parent and must be registered */
>> +	otg_dev = hcd_gcd_dev->parent;
>> +	if (!usb_otg_get_data(otg_dev))
>> +		return NULL;
>> +
>> +	return otg_dev;
>> +}
>> +
> 
> ... ...
> 
>> +static void usb_otg_init_timers(struct usb_otg *otgd, unsigned *timeouts)
>> +{
>> +	struct otg_fsm *fsm = &otgd->fsm;
>> +	unsigned long tmouts[NUM_OTG_FSM_TIMERS];
>> +	int i;
>> +
>> +	/* set default timeouts */
>> +	tmouts[A_WAIT_VRISE] = TA_WAIT_VRISE;
>> +	tmouts[A_WAIT_VFALL] = TA_WAIT_VFALL;
>> +	tmouts[A_WAIT_BCON] = TA_WAIT_BCON;
>> +	tmouts[A_AIDL_BDIS] = TA_AIDL_BDIS;
>> +	tmouts[A_BIDL_ADIS] = TA_BIDL_ADIS;
>> +	tmouts[B_ASE0_BRST] = TB_ASE0_BRST;
>> +	tmouts[B_SE0_SRP] = TB_SE0_SRP;
>> +	tmouts[B_SRP_FAIL] = TB_SRP_FAIL;
>> +
>> +	/* set controller provided timeouts */
>> +	if (timeouts) {
>> +		for (i = 0; i < NUM_OTG_FSM_TIMERS; i++) {
>> +			if (timeouts[i])
>> +				tmouts[i] = timeouts[i];
>> +		}
>> +	}
>> +
>> +	otg_timer_init(A_WAIT_VRISE, otgd, set_tmout, TA_WAIT_VRISE,
>> +		       &fsm->a_wait_vrise_tmout);
>> +	otg_timer_init(A_WAIT_VFALL, otgd, set_tmout, TA_WAIT_VFALL,
>> +		       &fsm->a_wait_vfall_tmout);
>> +	otg_timer_init(A_WAIT_BCON, otgd, set_tmout, TA_WAIT_BCON,
>> +		       &fsm->a_wait_bcon_tmout);
>> +	otg_timer_init(A_AIDL_BDIS, otgd, set_tmout, TA_AIDL_BDIS,
>> +		       &fsm->a_aidl_bdis_tmout);
>> +	otg_timer_init(A_BIDL_ADIS, otgd, set_tmout, TA_BIDL_ADIS,
>> +		       &fsm->a_bidl_adis_tmout);
>> +	otg_timer_init(B_ASE0_BRST, otgd, set_tmout, TB_ASE0_BRST,
>> +		       &fsm->b_ase0_brst_tmout);
>> +
>> +	otg_timer_init(B_SE0_SRP, otgd, set_tmout, TB_SE0_SRP,
>> +		       &fsm->b_se0_srp);
>> +	otg_timer_init(B_SRP_FAIL, otgd, set_tmout, TB_SRP_FAIL,
>> +		       &fsm->b_srp_done);
>> +
>> +	/* FIXME: what about A_WAIT_ENUM? */
> 
> Either you init it as other timers, or you remove all of it, otherwise
> there will be NULL pointer crash.

I want to initialize it but was not sure about the timeout value.
What timeout value I must use?

> 
>> +}
>> +
>> +/**
>> + * OTG FSM ops function to add timer
>> + */
>> +static void usb_otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +	struct otg_timer *otgtimer = &otgd->timers[id];
>> +	struct hrtimer *timer = &otgtimer->timer;
>> +
>> +	if (!otgd->fsm_running)
>> +		return;
>> +
>> +	/* if timer is already active, exit */
>> +	if (hrtimer_active(timer)) {
>> +		dev_err(otgd->dev, "otg: timer %d is already running\n", id);
>> +		return;
>> +	}
>> +
>> +	hrtimer_start(timer, otgtimer->timeout, HRTIMER_MODE_REL);
>> +}
>> +
>> +/**
>> + * OTG FSM ops function to delete timer
>> + */
>> +static void usb_otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +	struct hrtimer *timer = &otgd->timers[id].timer;
>> +
>> +	hrtimer_cancel(timer);
>> +}
>> +
>> +/**
>> + * Helper function to start/stop otg host. For use by otg controller.
>> + */
>> +int usb_otg_start_host(struct otg_fsm *fsm, int on)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +	struct otg_hcd_ops *hcd_ops;
>> +
>> +	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
>> +	if (!fsm->otg->host) {
>> +		WARN_ONCE(1, "otg: fsm running without host\n");
>> +		return 0;
>> +	}
>> +
>> +	if (on) {
>> +		/* start host */
>> +		hcd_ops = otgd->primary_hcd.ops;
>> +		hcd_ops->add(otgd->primary_hcd.hcd, otgd->primary_hcd.irqnum,
>> +			     otgd->primary_hcd.irqflags);
>> +		if (otgd->shared_hcd.hcd) {
>> +			hcd_ops = otgd->shared_hcd.ops;
>> +			hcd_ops->add(otgd->shared_hcd.hcd,
>> +				     otgd->shared_hcd.irqnum,
>> +				     otgd->shared_hcd.irqflags);
>> +		}
>> +	} else {
>> +		/* stop host */
>> +		if (otgd->shared_hcd.hcd) {
>> +			hcd_ops = otgd->shared_hcd.ops;
>> +			hcd_ops->remove(otgd->shared_hcd.hcd);
>> +		}
>> +		hcd_ops = otgd->primary_hcd.ops;
>> +		hcd_ops->remove(otgd->primary_hcd.hcd);
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
>> +
>> +/**
>> + * Helper function to start/stop otg gadget. For use by otg controller.
>> + */
>> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +	struct usb_gadget *gadget = fsm->otg->gadget;
>> +
>> +	dev_dbg(otgd->dev, "otg: %s %d\n", __func__, on);
>> +	if (!gadget) {
>> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
>> +		return 0;
>> +	}
>> +
>> +	if (on)
>> +		otgd->gadget_ops->start(fsm->otg->gadget);
>> +	else
>> +		otgd->gadget_ops->stop(fsm->otg->gadget);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
>> +
>> +/**
>> + * OTG FSM work function
>> + */
>> +static void usb_otg_work(struct work_struct *work)
>> +{
>> +	struct usb_otg *otgd = container_of(work, struct usb_otg, work);
>> +
> 
> Add runtime pm for it
> 	pm_runtime_get_sync(otgd->dev);
>> +	otg_statemachine(&otgd->fsm);
> 	pm_runtime_put_sync(otgd->dev);
> 

Sorry missed this one. Will add.

> Also as I raised in your previous version, we need successive state machine
> transition, how about:
> 	if (otg_statemachine(&otgd->fsm))
> 		usb_otg_sync_inputs(&otgd->fsm);

OK. will add this too.

>> +}
>> +
>> +/**
>> + * usb_otg_register() - Register the OTG device to OTG core
>> + * @dev: OTG controller device.
>> + * @config: OTG configuration.
>> + *
>> + * Register the OTG controller device with the USB OTG core.
>> + * The associated Host and Gadget controllers will be prevented from
>> + * being started till both are available for use.
>> + *
>> + * For non device tree boots, the OTG controller device must be the
>> + * parent node of the Host and Gadget controllers.
>> + *
>> + * For device tree case, the otg-controller property must be present
>> + * in the Host and Gadget controller node and it must point to the
>> + * same OTG controller node.
>> + *
>> + * Return: struct otg_fsm * if success, NULL if error.
>> + */
>> +struct otg_fsm *usb_otg_register(struct device *dev,
>> +				 struct usb_otg_config *config)
> 
> Why not return usb_otg? Since you create usb_otg which contains all stuff
> for otg.

yes, returning usb_otg makes more sense now.

> 
>> +{
>> +	struct usb_otg *otgd;
>> +	struct otg_wait_data *wait;
>> +	int ret = 0;
>> +
>> +	if (!dev || !config || !config->fsm_ops)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	/* already in list? */
>> +	mutex_lock(&otg_list_mutex);
>> +	if (usb_otg_get_data(dev)) {
>> +		dev_err(dev, "otg: %s: device already in otg list\n",
>> +			__func__);
>> +		ret = -EINVAL;
>> +		goto unlock;
>> +	}
>> +
>> +	/* allocate and add to list */
>> +	otgd = kzalloc(sizeof(*otgd), GFP_KERNEL);
>> +	if (!otgd) {
>> +		ret = -ENOMEM;
>> +		goto unlock;
>> +	}
>> +
>> +	otgd->dev = dev;
>> +	otgd->caps = &config->otg_caps;
> 
> How about define otgd->caps as a pointer, then don't need copy it.

otgd->caps is a pointer.

> 
>> +	INIT_WORK(&otgd->work, usb_otg_work);
>> +	otgd->wq = create_singlethread_workqueue("usb_otg");
>> +	if (!otgd->wq) {
>> +		dev_err(dev, "otg: %s: can't create workqueue\n",
>> +			__func__);
>> +		ret = -ENOMEM;
>> +		goto err_wq;
>> +	}
>> +
>> +	usb_otg_init_timers(otgd, config->otg_timeouts);
>> +
>> +	/* create copy of original ops */
>> +	otgd->fsm_ops = *config->fsm_ops;
> 
> The same, use a pointer is enough?

We are creating a copy because we are overriding timer ops.

> 
>> +	/* FIXME: we ignore caller's timer ops */
>> +	otgd->fsm_ops.add_timer = usb_otg_add_timer;
>> +	otgd->fsm_ops.del_timer = usb_otg_del_timer;
>> +	/* set otg ops */
>> +	otgd->fsm.ops = &otgd->fsm_ops;
>> +	otgd->fsm.otg = otgd;
>> +
>> +	mutex_init(&otgd->fsm.lock);
>> +
>> +	list_add_tail(&otgd->list, &otg_list);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	/* were we in wait list? */
>> +	mutex_lock(&wait_list_mutex);
>> +	wait = usb_otg_get_wait(dev);
>> +	mutex_unlock(&wait_list_mutex);
>> +	if (wait) {
>> +		/* register pending host/gadget and flush from list */
>> +		usb_otg_flush_wait(dev);
>> +	}
>> +
>> +	return &otgd->fsm;
>> +
>> +err_wq:
>> +	kfree(otgd);
>> +unlock:
>> +	mutex_unlock(&otg_list_mutex);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register);
>> +
>> +/**
>> + * usb_otg_unregister() - Unregister the OTG device from USB OTG core
>> + * @dev: OTG controller device.
>> + *
>> + * Unregister OTG controller device from USB OTG core.
>> + * Prevents unregistering till both the associated Host and Gadget controllers
>> + * have unregistered from the OTG core.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_unregister(struct device *dev)
>> +{
>> +	struct usb_otg *otgd;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(dev);
>> +	if (!otgd) {
>> +		dev_err(dev, "otg: %s: device not in otg list\n",
>> +			__func__);
>> +		mutex_unlock(&otg_list_mutex);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* prevent unregister till both host & gadget have unregistered */
>> +	if (otgd->fsm.otg->host || otgd->fsm.otg->gadget) {
>> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
>> +			__func__);
>> +		return -EBUSY;
>> +	}
>> +
>> +	/* OTG FSM is halted when host/gadget unregistered */
>> +	destroy_workqueue(otgd->wq);
>> +
>> +	/* remove from otg list */
>> +	list_del(&otgd->list);
>> +	kfree(otgd);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
>> +
>> +/**
>> + * start/kick the OTG FSM if we can
>> + * fsm->lock must be held
>> + */
>> +static void usb_otg_start_fsm(struct otg_fsm *fsm)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	if (otgd->fsm_running)
>> +		goto kick_fsm;
>> +
>> +	if (!fsm->otg->host) {
>> +		dev_info(otgd->dev, "otg: can't start till host registers\n");
>> +		return;
> 
> So we need register hcd(usb_otg_register_hcd) before start fsm, right?

Right. But you must use the plain old usb_add_hcd().

> 
>> +	}
>> +
>> +	if (!fsm->otg->gadget) {
>> +		dev_info(otgd->dev, "otg: can't start till gadget registers\n");
>> +		return;
>> +	}
>> +
>> +	otgd->fsm_running = true;
>> +kick_fsm:
>> +	queue_work(otgd->wq, &otgd->work);
>> +}
>> +
>> +/**
>> + * stop the OTG FSM. Stops Host & Gadget controllers as well.
>> + * fsm->lock must be held
>> + */
>> +static void usb_otg_stop_fsm(struct otg_fsm *fsm)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +	int i;
>> +
>> +	if (!otgd->fsm_running)
>> +		return;
>> +
>> +	/* no more new events queued */
>> +	otgd->fsm_running = false;
>> +
>> +	/* Stop state machine / timers */
>> +	for (i = 0; i < ARRAY_SIZE(otgd->timers); i++)
>> +		hrtimer_cancel(&otgd->timers[i].timer);
>> +
>> +	flush_workqueue(otgd->wq);
>> +	fsm->otg->state = OTG_STATE_UNDEFINED;
>> +
>> +	/* stop host/gadget immediately */
>> +	if (fsm->protocol == PROTO_HOST)
>> +		otg_start_host(fsm, 0);
>> +	else if (fsm->protocol == PROTO_GADGET)
>> +		otg_start_gadget(fsm, 0);
>> +	fsm->protocol = PROTO_UNDEF;
>> +}
>> +
>> +/**
>> + * usb_otg_sync_inputs - Sync OTG inputs with the OTG state machine
>> + * @fsm:	OTG FSM instance
>> + *
>> + * Used by the OTG driver to update the inputs to the OTG
>> + * state machine.
>> + *
>> + * Can be called in IRQ context.
>> + */
>> +void usb_otg_sync_inputs(struct otg_fsm *fsm)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	/* Don't kick FSM till it has started */
>> +	if (!otgd->fsm_running)
>> +		return;
>> +
>> +	/* Kick FSM */
>> +	queue_work(otgd->wq, &otgd->work);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
>> +
>> +/**
>> + * usb_otg_kick_fsm - Kick the OTG state machine
>> + * @hcd_gcd_device:	Host/Gadget controller device
>> + *
>> + * Used by USB host/device stack to sync OTG related
>> + * events to the OTG state machine.
>> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_kick_fsm(struct device *hcd_gcd_device)
>> +{
>> +	struct usb_otg *otgd;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(usb_otg_get_device(hcd_gcd_device));
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		dev_dbg(hcd_gcd_device, "otg: %s: invalid host/gadget device\n",
>> +			__func__);
>> +		return -ENODEV;
>> +	}
>> +
>> +	usb_otg_sync_inputs(&otgd->fsm);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
>> +
>> +/**
>> + * usb_otg_register_hcd - Register Host controller to OTG core
>> + * @hcd:	Host controller device
>> + * @irqnum:	interrupt number
>> + * @irqflags:	interrupt flags
>> + * @ops:	HCD ops to add/remove the HCD
>> + *
>> + * This is used by the USB Host stack to register the Host controller
>> + * to the OTG core. Host controller must not be started by the
>> + * caller as it is left upto the OTG state machine to do so.
> 
> I am confused on how to use this function.
> - This function should be called before start fsm per usb_otg_start_fsm().

yes.

> - Called by usb_add_hcd(), so we need call usb_add_hcd() before start fsm.

yes.

> - If I want to add hcd when switch to host role, and remove hcd when switch
>   to peripheral, with this design, I cannot use this function?

You add hcd only once during the life of the OTG device. If it is linked to the
OTG controller the OTG fsm manages the start/stop of hcd using the otg_hcd_ops.

"usb/core/hcd.c"
static struct otg_hcd_ops otg_hcd_intf = {
        .add = usb_otg_add_hcd,
        .remove = usb_otg_remove_hcd,
};

Your otg driver must use teh usb_otg_add/remove_hcd to start/stop the controller.
Using usb_remove_hcd() means the hcd resource is no longer available and the
otg fsm will be stopped.

> - How about split it out of usb_add_hcd()?

Adding the HCD and starting/stopping the hcd is split into
usb_add/remove_hcd() and usb_otg_add/remove_hcd() for OTG case.

> 
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *hcd_dev = hcd->self.controller;
>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		dev_dbg(hcd_dev,
>> +			"otg: controller not yet registered. waiting..\n");
>> +		/*
>> +		 * otg controller might register later. Put the hcd in
>> +		 * wait list and call us back when ready
>> +		 */
>> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
>> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
>> +			return -EINVAL;
>> +		}
>> +
>> +		return 0;
>> +	}
>> +
>> +	/* HCD will be started by OTG fsm when needed */
>> +	mutex_lock(&otgd->fsm.lock);
> 
> If call usb_add_hcd() when start host role, deadlock.

No. You must call usb_otg_add_hcd() to start host role.

> 
>> +	if (otgd->primary_hcd.hcd) {
>> +		/* probably a shared HCD ? */
>> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
>> +			dev_err(otg_dev, "otg: primary host already registered\n");
>> +			goto err;
>> +		}
>> +
>> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
>> +			if (otgd->shared_hcd.hcd) {
>> +				dev_err(otg_dev, "otg: shared host already registered\n");
>> +				goto err;
>> +			}
>> +
>> +			otgd->shared_hcd.hcd = hcd;
>> +			otgd->shared_hcd.irqnum = irqnum;
>> +			otgd->shared_hcd.irqflags = irqflags;
>> +			otgd->shared_hcd.ops = ops;
>> +			dev_info(otg_dev, "otg: shared host %s registered\n",
>> +				 dev_name(hcd->self.controller));
>> +		} else {
>> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
>> +				dev_name(hcd->self.controller));
>> +			goto err;
>> +		}
>> +	} else {
>> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
>> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
>> +			goto err;
>> +		}
>> +
>> +		otgd->primary_hcd.hcd = hcd;
>> +		otgd->primary_hcd.irqnum = irqnum;
>> +		otgd->primary_hcd.irqflags = irqflags;
>> +		otgd->primary_hcd.ops = ops;
>> +		dev_info(otg_dev, "otg: primary host %s registered\n",
>> +			 dev_name(hcd->self.controller));
>> +	}
>> +
>> +	/*
>> +	 * we're ready only if we have shared HCD
>> +	 * or we don't need shared HCD.
>> +	 */
>> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
>> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
> 
> otgd->host = hcd_to_bus(hcd);

ok. So we set host at both places. struct usb_otg in struct otg_fsm starts to
feel redundant now. I think we should get rid of it and get the usb_otg struct
using container_of() instead.

> 
>> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
>> +
>> +		/* start FSM */
>> +		usb_otg_start_fsm(&otgd->fsm);
>> +	} else {
>> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
>> +	}
>> +
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +
>> +err:
>> +	mutex_unlock(&otgd->fsm.lock);
>> +	return -EINVAL;
> 
> Return non-zero, then if err, do we need call usb_otg_add_hcd() after
> usb_otg_register_hcd() fails?

You should not call usb_otg_register_hcd() but usb_add_hcd().
If that fails then you fail as ususal.

> 
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
>> +
>> +/**
>> + * usb_otg_unregister_hcd - Unregister Host controller from OTG core
>> + * @hcd:	Host controller device
>> + *
>> + * This is used by the USB Host stack to unregister the Host controller
>> + * from the OTG core. Ensures that Host controller is not running
>> + * on successful return.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_unregister_hcd(struct usb_hcd *hcd)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		/* are we in wait list? */
>> +		if (!usb_otg_hcd_wait_remove(hcd))
>> +			return 0;
>> +
>> +		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (hcd == otgd->primary_hcd.hcd) {
>> +		otgd->primary_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else if (hcd == otgd->shared_hcd.hcd) {
>> +		otgd->shared_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else {
>> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* stop FSM & Host */
>> +	usb_otg_stop_fsm(&otgd->fsm);
>> +	otgd->fsm.otg->host = NULL;
>> +
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
>> +
>> +/**
>> + * usb_otg_register_gadget - Register Gadget controller to OTG core
>> + * @gadget:	Gadget controller
>> + *
>> + * This is used by the USB Gadget stack to register the Gadget controller
>> + * to the OTG core. Gadget controller must not be started by the
>> + * caller as it is left upto the OTG state machine to do so.
>> + *
>> + * Gadget core must call this only when all resources required for
>> + * gadget controller to run are available.
>> + * i.e. gadget function driver is available.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		dev_dbg(gadget_dev,
>> +			"otg: controller not yet registered. waiting..\n");
>> +		/*
>> +		 * otg controller might register later. Put the gadget in
>> +		 * wait list and call us back when ready
>> +		 */
>> +		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
>> +			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
>> +			return -EINVAL;
>> +		}
>> +
>> +		return 0;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (otgd->fsm.otg->gadget) {
>> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	otgd->fsm.otg->gadget = gadget;
>> +	otgd->gadget_ops = ops;
>> +	dev_info(otg_dev, "otg: gadget %s registered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	/* start FSM */
>> +	usb_otg_start_fsm(&otgd->fsm);
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
>> +
>> +/**
>> + * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
>> + * @gadget:	Gadget controller
>> + *
>> + * This is used by the USB Gadget stack to unregister the Gadget controller
>> + * from the OTG core. Ensures that Gadget controller is not running
>> + * on successful return.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_unregister_gadget(struct usb_gadget *gadget)
>> +{
>> +	struct usb_otg *otgd;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otgd = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otgd) {
>> +		/* are we in wait list? */
>> +		if (!usb_otg_gadget_wait_remove(gadget))
>> +			return 0;
>> +
>> +		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otgd->fsm.lock);
>> +	if (otgd->fsm.otg->gadget != gadget) {
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		mutex_unlock(&otgd->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Stop FSM & gadget */
>> +	usb_otg_stop_fsm(&otgd->fsm);
>> +	otgd->fsm.otg->gadget = NULL;
>> +	mutex_unlock(&otgd->fsm.lock);
>> +
>> +	dev_info(otg_dev, "otg: gadget %s unregistered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
>> +
>> +/**
>> + * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
>> + * @fsm:	otg_fsm data structure
>> + *
>> + * This is used by the OTG controller driver to get it's device node
>> + * from any of the otg_fsm->ops.
>> + */
>> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
>> +{
>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	return otgd->dev;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
>> diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
>> new file mode 100644
>> index 0000000..05331f0
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.h
>> @@ -0,0 +1,71 @@
>> +/**
>> + * drivers/usb/common/usb-otg.h - USB OTG core local header
>> + *
>> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Roger Quadros <rogerq@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
>> +#define __DRIVERS_USB_COMMON_USB_OTG_H
>> +
>> +/*
>> + *  A-DEVICE timing constants
>> + */
>> +
>> +/* Wait for VBUS Rise  */
>> +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
>> +					 * a_wait_vrise_tmr: section 7.4.5.1
>> +					 * TA_VBUS_RISE <= 100ms, section 4.4
>> +					 * Table 4-1: Electrical Characteristics
>> +					 * ->DC Electrical Timing
>> +					 */
>> +/* Wait for VBUS Fall  */
>> +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
>> +					 * a_wait_vfall_tmr: section: 7.4.5.2
>> +					 */
>> +/* Wait for B-Connect */
>> +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
>> +					 * TA_WAIT_BCON: should be between 1100
>> +					 * and 30000 ms, section 5.5, Table 5-1
>> +					 */
>> +/* A-Idle to B-Disconnect */
>> +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
>> +					 * TA_AIDL_BDIS: section 5.5, Table 5-1
>> +					 */
>> +/* B-Idle to A-Disconnect */
>> +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
>> +					 * 500ms is used for B switch to host
>> +					 * for safe
>> +					 */
>> +
>> +/*
>> + * B-device timing constants
>> + */
>> +
>> +/* Data-Line Pulse Time*/
>> +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
>> +					 * section:5.1.3
>> +					 */
>> +/* SRP Fail Time  */
>> +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
>> +					 * section:5.1.6
>> +					 */
>> +/* A-SE0 to B-Reset  */
>> +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
>> +/* SE0 Time Before SRP */
>> +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
>> +/* SSEND time before SRP */
>> +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
>> +
>> +#define TB_SESS_VLD          (1000)
>> +
>> +#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
>> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
>> index a99c89e..b468a9f 100644
>> --- a/drivers/usb/core/Kconfig
>> +++ b/drivers/usb/core/Kconfig
>> @@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
>>  	  If you are unsure about this, say N here.
>>  
>>  config USB_OTG
>> -	bool "OTG support"
>> +	bool "OTG/Dual-role support"
>>  	depends on PM
>>  	default n
>>  	help
>> @@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
>>  	  and software costs by not supporting external hubs.  So
>>  	  are "Embedded Hosts" that don't offer OTG support.
>>  
>> -config USB_OTG_FSM
>> -	tristate "USB 2.0 OTG FSM implementation"
>> -	depends on USB
>> -	select USB_OTG
>> -	select USB_PHY
>> -	help
>> -	  Implements OTG Finite State Machine as specified in On-The-Go
>> -	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
>> -
>>  config USB_ULPI_BUS
>>  	tristate "USB ULPI PHY interface support"
>>  	depends on USB_SUPPORT
>> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
>> index bd1dcf8..38cabe0 100644
>> --- a/include/linux/usb/otg.h
>> +++ b/include/linux/usb/otg.h
>> @@ -10,19 +10,100 @@
>>  #define __LINUX_USB_OTG_H
>>  
>>  #include <linux/phy/phy.h>
>> +#include <linux/device.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/ktime.h>
>> +#include <linux/usb.h>
>> +#include <linux/usb/hcd.h>
>> +#include <linux/usb/gadget.h>
>> +#include <linux/usb/otg-fsm.h>
>>  #include <linux/usb/phy.h>
>>  
>> +/**
>> + * struct otg_hcd - host controller state and interface
>> + *
>> + * @hcd: host controller
>> + * @irqnum: irq number
>> + * @irqflags: irq flags
>> + * @ops: otg to host controller interface
>> + */
>> +struct otg_hcd {
>> +	struct usb_hcd *hcd;
>> +	unsigned int irqnum;
>> +	unsigned long irqflags;
>> +	struct otg_hcd_ops *ops;
>> +};
>> +
>> +struct usb_otg;
>> +
>> +/**
>> + * struct otg_timer - otg timer data
>> + *
>> + * @timer: high resolution timer
>> + * @timeout: timeout value
>> + * @timetout_bit: pointer to variable that is set on timeout
>> + * @otgd: usb otg data
>> + */
>> +struct otg_timer {
>> +	struct hrtimer timer;
>> +	ktime_t timeout;
>> +	/* callback data */
>> +	int *timeout_bit;
>> +	struct usb_otg *otgd;
>> +};
>> +
>> +/**
>> + * struct usb_otg - usb otg controller state
>> + *
>> + * @default_a: Indicates we are an A device. i.e. Host.
>> + * @phy: USB phy interface
>> + * @usb_phy: old usb_phy interface
>> + * @host: host controller bus
>> + * @gadget: gadget device
>> + * @state: current otg state
>> + * @dev: otg controller device
>> + * @caps: otg capabilities revision, hnp, srp, etc
>> + * @fsm: otg finite state machine
>> + * @fsm_ops: controller hooks for the state machine
>> + * ------- internal use only -------
>> + * @primary_hcd: primary host state and interface
>> + * @shared_hcd: shared host state and interface
>> + * @gadget_ops: gadget interface
>> + * @timers: otg timers for state machine
>> + * @list: list of otg controllers
>> + * @work: otg state machine work
>> + * @wq: otg state machine work queue
>> + * @fsm_running: state machine running/stopped indicator
>> + */
>>  struct usb_otg {
>>  	u8			default_a;
>>  
>>  	struct phy		*phy;
>>  	/* old usb_phy interface */
>>  	struct usb_phy		*usb_phy;
>> +
> 
> add a blank line?
> 
>>  	struct usb_bus		*host;
>>  	struct usb_gadget	*gadget;
>>  
>>  	enum usb_otg_state	state;
>>  
>> +	struct device *dev;
>> +	struct usb_otg_caps *caps;
>> +	struct otg_fsm fsm;
>> +	struct otg_fsm_ops fsm_ops;
>> +
>> +	/* internal use only */
>> +	struct otg_hcd primary_hcd;
>> +	struct otg_hcd shared_hcd;
>> +	struct otg_gadget_ops *gadget_ops;
>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
>> +	struct list_head list;
>> +	struct work_struct work;
>> +	struct workqueue_struct *wq;
>> +	bool fsm_running;
> 
> Should fsm_running be added in otg_fsm struct?

Yes, can be moved there.

> 
>> +	/* use otg->fsm.lock for serializing access */
>> +
>> +/*------------- deprecated interface -----------------------------*/
>>  	/* bind/unbind the host controller */
>>  	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
>>  
>> @@ -38,7 +119,7 @@ struct usb_otg {
>>  
>>  	/* start or continue HNP role switch */
>>  	int	(*start_hnp)(struct usb_otg *otg);
>> -
>> +/*---------------------------------------------------------------*/
>>  };
>>  
>>  /**
>> @@ -56,8 +137,105 @@ struct usb_otg_caps {
>>  	bool adp_support;
>>  };
>>  
>> +/**
>> + * struct usb_otg_config - otg controller configuration
>> + * @caps: otg capabilities of the controller
>> + * @ops: otg fsm operations
>> + * @otg_timeouts: override default otg fsm timeouts
>> + */
>> +struct usb_otg_config {
>> +	struct usb_otg_caps otg_caps;
>> +	struct otg_fsm_ops *fsm_ops;
>> +	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
>> +};
>> +
>>  extern const char *usb_otg_state_string(enum usb_otg_state state);
>>  
>> +enum usb_dr_mode {
>> +	USB_DR_MODE_UNKNOWN,
>> +	USB_DR_MODE_HOST,
>> +	USB_DR_MODE_PERIPHERAL,
>> +	USB_DR_MODE_OTG,
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_USB_OTG)
>> +struct otg_fsm *usb_otg_register(struct device *dev,
>> +				 struct usb_otg_config *config);
>> +int usb_otg_unregister(struct device *dev);
>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +			 unsigned long irqflags, struct otg_hcd_ops *ops);
>> +int usb_otg_unregister_hcd(struct usb_hcd *hcd);
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops);
>> +int usb_otg_unregister_gadget(struct usb_gadget *gadget);
>> +void usb_otg_sync_inputs(struct otg_fsm *fsm);
>> +int usb_otg_kick_fsm(struct device *hcd_gcd_device);
>> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
>> +int usb_otg_start_host(struct otg_fsm *fsm, int on);
>> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
>> +
>> +#else /* CONFIG_USB_OTG */
>> +
>> +static inline struct otg_fsm *usb_otg_register(struct device *dev,
>> +					       struct usb_otg_config *config)
>> +{
>> +	return ERR_PTR(-ENOTSUPP);
>> +}
>> +
>> +static inline int usb_otg_unregister(struct device *dev)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>> +				       unsigned long irqflags,
>> +				       struct otg_hcd_ops *ops)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +					  struct otg_gadget_ops *ops)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
>> +{
>> +}
>> +
>> +static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +
>> +static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
>> +{
>> +	return -ENOTSUPP;
>> +}
>> +#endif /* CONFIG_USB_OTG */
>> +
>> +/*------------- deprecated interface -----------------------------*/
>>  /* Context: can sleep */
>>  static inline int
>>  otg_start_hnp(struct usb_otg *otg)
>> @@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
>>  	return -ENOTSUPP;
>>  }
>>  
>> +/*---------------------------------------------------------------*/
>> +
>>  /* for OTG controller drivers (and maybe other stuff) */
>>  extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
>>  
>> -enum usb_dr_mode {
>> -	USB_DR_MODE_UNKNOWN,
>> -	USB_DR_MODE_HOST,
>> -	USB_DR_MODE_PERIPHERAL,
>> -	USB_DR_MODE_OTG,
>> -};
>> -
>>  #endif /* __LINUX_USB_OTG_H */
>> -- 
>> 2.1.4
>>

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

* Re: [PATCH v4 00/13] USB: OTG/DRD Core functionality
  2015-09-06  7:06 ` Peter Chen
@ 2015-09-07 11:42   ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-07 11:42 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 06/09/15 10:06, Peter Chen wrote:
> On Mon, Aug 24, 2015 at 04:21:11PM +0300, Roger Quadros wrote:
>> Hi,
>>
>> This series centralizes OTG/Dual-role functionality in the kernel.
>> As of now I've got Dual-role functionality working pretty reliably on
>> dra7-evm and am437x-gp-evm.
>>
>> DWC3 controller and platform related patches will be sent separately.
>>
>> Series is based on Greg's usb-next tree.
>>
>> Changelog:
>> ---------
>> v4:
>> - Added DT support for tying otg-controller to host and gadget
>>  controllers. For DT we no longer have the constraint that
>>  OTG controller needs to be parent of host and gadget. They can be
>>  tied together using the "otg-controller" property.
>> - Relax the requirement for DT case that otg controller must register before
>>  host/gadget. We maintain a wait list of host/gadget devices
>>  waiting on the otg controller.
>> - Use a single struct usb_otg for otg data.
>> - Don't override host/gadget start/stop APIs. Let the controller
>>  drivers do what they want as they know best. Helper API is provided
>>  for controller start/stop that controller driver can use.
>> - Introduce struct usb_otg_config to pass the otg capabilities,
>>  otg ops and otg timer timeouts during otg controller registration.
>> - rebased on Greg's usb.git/usb-next
> 
> Roger, thanks for your hard work. Since it is complicated, and can't
> know its correctness and scalable well just reading code. I will run
> it for chipidea driver, wait some time please.

No problem and thanks for the tests.

cheers,
-roger

> 
> Peter
>>
>> v3:
>> - all otg related definations now in otg.h
>> - single kernel config USB_OTG to enable OTG core and FSM.
>> - resolved symbol dependency issues.
>> - use dev_vdbg instead of VDBG() in usb-otg-fsm.c
>> - rebased on v4.2-rc1
>>
>> v2:
>> - Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
>>  the host controller
>> - added dual-role-device (DRD) state machine which is a much simpler
>>  mode of operation when compared to OTG. Here we don't support fancy
>>  OTG features like HNP, SRP, on the fly role-swap. The mode of operation
>>  is determined based on ID pin (cable type) and the role doesn't change
>>  till the cable type changes.
>>
>> Why?:
>> ----
>>
>> Most of the OTG drivers have been dealing with the OTG state machine
>> themselves and there is a scope for code re-use. This has been
>> partly addressed by the usb/common/usb-otg-fsm.c but it still
>> leaves the instantiation of the state machine and OTG timers
>> to the controller drivers. We re-use usb-otg-fsm.c but
>> go one step further by instantiating the state machine and timers
>> thus making it easier for drivers to implement OTG functionality.
>>
>> Newer OTG cores support standard host interface (e.g. xHCI) so
>> host and gadget functionality are no longer closely knit like older
>> cores. There needs to be a way to co-ordinate the operation of the
>> host and gadget in OTG mode. i.e. to stop and start them from a
>> central location. This central location should be the USB OTG core.
>>
>> Host and gadget controllers might be sharing resources and can't
>> be always running. One has to be stopped for the other to run.
>> This can't be done as of now and can be done from the OTG core.
>>
>> What?:
>> -----
>>
>> The OTG core instantiates the OTG/DRD Finite State Machine
>> per OTG controller and manages starting/stopping the
>> host and gadget controllers based on the bus state.
>>     
>> It provides APIs for the following
>>     
>> - Registering an OTG capable controller
>> struct otg_fsm *usb_otg_register(struct device *dev,
>>                                  struct usb_otg_config *config);
>>
>> int usb_otg_unregister(struct device *dev);
>>
>> - Registering Host controllers to OTG core (used by hcd-core)
>> int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>                          unsigned long irqflags, struct otg_hcd_ops *ops);
>> int usb_otg_unregister_hcd(struct usb_hcd *hcd);
>>
>>
>> - Registering Gadget controllers to OTG core (used by udc-core)
>> int usb_otg_register_gadget(struct usb_gadget *gadget,
>>                             struct otg_gadget_ops *ops);
>> int usb_otg_unregister_gadget(struct usb_gadget *gadget);
>>
>>
>> - Providing inputs to and kicking the OTG state machine
>> void usb_otg_sync_inputs(struct otg_fsm *fsm);
>> int usb_otg_kick_fsm(struct device *hcd_gcd_device);
>>
>> - Getting controller device structure from OTG state machine instance
>> struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
>>
>> 'struct otg_fsm' is the interface to the OTG state machine.
>> It contains inputs to the fsm, status of the fsm and operations
>> for the OTG controller driver.
>>
>> - Helper APIs for starting/stopping host/gadget controllers
>> int usb_otg_start_host(struct otg_fsm *fsm, int on);
>> int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
>>
>> Usage model:
>> -----------
>>
>> - The OTG core needs to know what host and gadget controllers are
>> linked to the OTG controller. For DT boots we can provide that
>> information by adding "otg-controller" property to the host and
>> gadget controller nodes that points to the right otg controller.
>> For legacy boot we assume that OTG controller is the parent
>> of the host and gadget controllers. For DT if "otg-controller"
>> property is not present then parent child relationship constraint
>> applies.
>>
>> - The OTG controller driver must call usb_otg_register() to register
>> itself with the OTG core. It must also provide the required
>> OTG configuration, fsm operations and timer timeouts (optional)
>> via struct usb_otg_config. The fsm operations will be called
>> depending on the OTG bus state.
>>
>> - The host/gadget core stacks are modified to inform the OTG core
>> whenever a new host/gadget device is added. The OTG core then
>> checks if the host/gadget is part of the OTG controller and if yes
>> then prevents the host/gadget from starting till both host and
>> gadget are registered, OTG state machine is running and the
>> USB bus state is appropriate to start host/gadget.
>> For this, APIs have been added to host/gadget stacks to start/stop
>> the controllers from the OTG core.
>> For DT boots, If the OTG controller hasn't yet been registered
>> while the host/gadget are added, the OTG core will hold it in a wait list
>> and register them when the OTG controller registers.
>>
>> - No modification is needed for the host/gadget controller drivers.
>> They must ensure that their start/stop methods can be called repeatedly
>> and any shared resources between host & gadget are properly managed.
>> The OTG core ensures that both are not started simultaneously.
>>
>> - The OTG core instantiates one OTG state machine per OTG controller
>> and the necessary OTG timers to manage OTG state timeouts.
>> If none of the otg features are set during usb_otg_register() then it
>> instanciates a DRD (dual-role device) state machine instead.
>> The state machine is started when both host & gadget register and
>> stopped when either of them unregisters. The controllers are started
>> and stopped depending on bus state.
>>
>> - During the lifetime of the OTG state machine, inputs can be
>> provided to it by modifying the appropriate members of 'struct otg_fsm'
>> and calling usb_otg_sync_inputs(). This is typically done by the
>> OTG controller driver that called usb_otg_register().
>>
>> --
>> cheers,
>> -roger
>>
>> Roger Quadros (13):
>>   usb: otg-fsm: Add documentation for struct otg_fsm
>>   usb: otg-fsm: support multiple instances
>>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>>   otg-fsm: move usb_bus_start_enum into otg-fsm->ops
>>   usb: hcd.h: Add OTG to HCD interface
>>   usb: gadget.h: Add OTG to gadget interface
>>   usb: otg: add OTG core
>>   usb: doc: dt-binding: Add otg-controller property
>>   usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
>>   usb: hcd: Adapt to OTG core
>>   usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
>>   usb: gadget: udc: adapt to OTG core
>>   usb: otg: Add dual-role device (DRD) support
>>
>>  Documentation/devicetree/bindings/usb/generic.txt |    5 +
>>  Documentation/usb/chipidea.txt                    |    2 +-
>>  MAINTAINERS                                       |    4 +-
>>  drivers/usb/Kconfig                               |    2 +-
>>  drivers/usb/Makefile                              |    1 +
>>  drivers/usb/chipidea/Makefile                     |    2 +-
>>  drivers/usb/chipidea/ci.h                         |    2 +-
>>  drivers/usb/chipidea/otg_fsm.c                    |    1 +
>>  drivers/usb/chipidea/otg_fsm.h                    |    2 +-
>>  drivers/usb/common/Makefile                       |    3 +-
>>  drivers/usb/common/usb-otg-fsm.c                  |   26 +-
>>  drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
>>  drivers/usb/common/usb-otg.h                      |   71 ++
>>  drivers/usb/core/Kconfig                          |   11 +-
>>  drivers/usb/core/hcd.c                            |   55 +-
>>  drivers/usb/core/hub.c                            |   10 +-
>>  drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
>>  drivers/usb/phy/Kconfig                           |    2 +-
>>  drivers/usb/phy/phy-fsl-usb.c                     |    3 +
>>  include/linux/usb/gadget.h                        |   14 +
>>  include/linux/usb/hcd.h                           |   14 +
>>  include/linux/usb/otg-fsm.h                       |  116 +-
>>  include/linux/usb/otg.h                           |  191 +++-
>>  23 files changed, 1808 insertions(+), 76 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>  create mode 100644 drivers/usb/common/usb-otg.h
>>
>> -- 
>> 2.1.4
>>
> 

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

* Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  2015-09-07  9:57     ` Roger Quadros
@ 2015-09-08  6:54       ` Peter Chen
  2015-09-08  8:24         ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-08  6:54 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Sep 07, 2015 at 12:57:21PM +0300, Roger Quadros wrote:
> On 07/09/15 04:24, Peter Chen wrote:
> > On Mon, Aug 24, 2015 at 04:21:15PM +0300, Roger Quadros wrote:
> >> This is to prevent missing symbol build error if OTG is
> >> enabled (built-in) and HCD core (CONFIG_USB) is module.
> >>
> >> Signed-off-by: Roger Quadros <rogerq@ti.com>
> >> Acked-by: Peter Chen <peter.chen@freescale.com>
> >> ---
> >>  drivers/usb/common/usb-otg-fsm.c | 6 ++++--
> >>  drivers/usb/phy/phy-fsl-usb.c    | 2 ++
> >>  include/linux/usb/otg-fsm.h      | 1 +
> >>  3 files changed, 7 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
> >> index a46f29a..6e56c8c 100644
> >> --- a/drivers/usb/common/usb-otg-fsm.c
> >> +++ b/drivers/usb/common/usb-otg-fsm.c
> >> @@ -165,8 +165,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> >>  		otg_loc_conn(fsm, 0);
> >>  		otg_loc_sof(fsm, 1);
> >>  		otg_set_protocol(fsm, PROTO_HOST);
> >> -		usb_bus_start_enum(fsm->otg->host,
> >> -				fsm->otg->host->otg_port);usb_bus_start_enum
> >> +		if (fsm->ops->start_enum) {
> >> +			fsm->ops->start_enum(fsm->otg->host,
> >> +					     fsm->otg->host->otg_port);
> >> +		}
> >>  		break;
> >>  	case OTG_STATE_A_IDLE:
> >>  		otg_drv_vbus(fsm, 0);
> >> diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
> >> index ee3f2c2..19541ed 100644
> >> --- a/drivers/usb/phy/phy-fsl-usb.c
> >> +++ b/drivers/usb/phy/phy-fsl-usb.c
> >> @@ -783,6 +783,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
> >>  
> >>  	.start_host = fsl_otg_start_host,
> >>  	.start_gadget = fsl_otg_start_gadget,
> >> +
> >> +	.start_enum = usb_bus_start_enum,
> >>  };
> >>  
> >>  /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
> >> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
> >> index 672551c..75e82cc 100644
> >> --- a/include/linux/usb/otg-fsm.h
> >> +++ b/include/linux/usb/otg-fsm.h
> >> @@ -199,6 +199,7 @@ struct otg_fsm_ops {
> >>  	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
> >>  	int	(*start_host)(struct otg_fsm *fsm, int on);
> >>  	int	(*start_gadget)(struct otg_fsm *fsm, int on);
> >> +	int	(*start_enum)(struct usb_bus *bus, unsigned port_num);
> >>  };
> >>  
> >>  
> > 
> > Get one build warning:
> > 
> > In file included from /u/home/b29397/work/projects/usb/drivers/usb/chipidea/udc.c:23:0:
> > /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: 'struct usb_bus' declared inside parameter list
> >   int (*start_enum)(struct usb_bus *bus, unsigned port_num);
> >                              ^
> > /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: its scope is only this definition or declaration, which is probably not what you want
> > 
> > It probably dues to we should not have struct usb_bus* at udc driver
> > 
> How about changing it to struct otg_fsm instead like the other APIs?
> And do we leave usb_bus_start_enum() as it is?
> 

You have defined struct otg_hcd_ops to let otg visit hcd stuff, how
about move this to otg_hcd_ops?

> cheers,
> -roger

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
  2015-09-08  6:54       ` Peter Chen
@ 2015-09-08  8:24         ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-08  8:24 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 08/09/15 09:54, Peter Chen wrote:
> On Mon, Sep 07, 2015 at 12:57:21PM +0300, Roger Quadros wrote:
>> On 07/09/15 04:24, Peter Chen wrote:
>>> On Mon, Aug 24, 2015 at 04:21:15PM +0300, Roger Quadros wrote:
>>>> This is to prevent missing symbol build error if OTG is
>>>> enabled (built-in) and HCD core (CONFIG_USB) is module.
>>>>
>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>> Acked-by: Peter Chen <peter.chen@freescale.com>
>>>> ---
>>>>  drivers/usb/common/usb-otg-fsm.c | 6 ++++--
>>>>  drivers/usb/phy/phy-fsl-usb.c    | 2 ++
>>>>  include/linux/usb/otg-fsm.h      | 1 +
>>>>  3 files changed, 7 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
>>>> index a46f29a..6e56c8c 100644
>>>> --- a/drivers/usb/common/usb-otg-fsm.c
>>>> +++ b/drivers/usb/common/usb-otg-fsm.c
>>>> @@ -165,8 +165,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>>>>  		otg_loc_conn(fsm, 0);
>>>>  		otg_loc_sof(fsm, 1);
>>>>  		otg_set_protocol(fsm, PROTO_HOST);
>>>> -		usb_bus_start_enum(fsm->otg->host,
>>>> -				fsm->otg->host->otg_port);usb_bus_start_enum
>>>> +		if (fsm->ops->start_enum) {
>>>> +			fsm->ops->start_enum(fsm->otg->host,
>>>> +					     fsm->otg->host->otg_port);
>>>> +		}
>>>>  		break;
>>>>  	case OTG_STATE_A_IDLE:
>>>>  		otg_drv_vbus(fsm, 0);
>>>> diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
>>>> index ee3f2c2..19541ed 100644
>>>> --- a/drivers/usb/phy/phy-fsl-usb.c
>>>> +++ b/drivers/usb/phy/phy-fsl-usb.c
>>>> @@ -783,6 +783,8 @@ static struct otg_fsm_ops fsl_otg_ops = {
>>>>  
>>>>  	.start_host = fsl_otg_start_host,
>>>>  	.start_gadget = fsl_otg_start_gadget,
>>>> +
>>>> +	.start_enum = usb_bus_start_enum,
>>>>  };
>>>>  
>>>>  /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
>>>> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
>>>> index 672551c..75e82cc 100644
>>>> --- a/include/linux/usb/otg-fsm.h
>>>> +++ b/include/linux/usb/otg-fsm.h
>>>> @@ -199,6 +199,7 @@ struct otg_fsm_ops {
>>>>  	void	(*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
>>>>  	int	(*start_host)(struct otg_fsm *fsm, int on);
>>>>  	int	(*start_gadget)(struct otg_fsm *fsm, int on);
>>>> +	int	(*start_enum)(struct usb_bus *bus, unsigned port_num);
>>>>  };
>>>>  
>>>>  
>>>
>>> Get one build warning:
>>>
>>> In file included from /u/home/b29397/work/projects/usb/drivers/usb/chipidea/udc.c:23:0:
>>> /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: 'struct usb_bus' declared inside parameter list
>>>   int (*start_enum)(struct usb_bus *bus, unsigned port_num);
>>>                              ^
>>> /u/home/b29397/work/projects/usb/include/linux/usb/otg-fsm.h:207:27: warning: its scope is only this definition or declaration, which is probably not what you want
>>>
>>> It probably dues to we should not have struct usb_bus* at udc driver
>>>
>> How about changing it to struct otg_fsm instead like the other APIs?
>> And do we leave usb_bus_start_enum() as it is?
>>
> 
> You have defined struct otg_hcd_ops to let otg visit hcd stuff, how
> about move this to otg_hcd_ops?

Yes, this is a better idea. Thanks.

cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-07 10:23     ` Roger Quadros
@ 2015-09-08  8:31       ` Peter Chen
  2015-09-08 12:25         ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-08  8:31 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> On 07/09/15 04:23, Peter Chen wrote:
> > On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >> + * This is used by the USB Host stack to register the Host controller
> >> + * to the OTG core. Host controller must not be started by the
> >> + * caller as it is left upto the OTG state machine to do so.
> >> + *
> >> + * Returns: 0 on success, error value otherwise.
> >> + */
> >> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >> +{
> >> +	struct usb_otg *otgd;
> >> +	struct device *hcd_dev = hcd->self.controller;
> >> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >> +
> > 
> > One big problem here is: there are two designs for current (IP) driver
> > code, one creates dedicated hcd device as roothub's parent, like dwc3.
> > Another one doesn't do this, roothub's parent is core device (or otg device
> > in your patch), like chipidea and dwc2.
> > 
> > Then, otg_dev will be glue layer device for chipidea after that.
> 
> OK. Let's add a way for the otg controller driver to provide the host and gadget
> information to the otg core for such devices like chipidea and dwc2.
> 

Roger, not only chipidea and dwc2, I think the musb uses the same
hierarchy. If the host, device, and otg share the same register
region, host part can't be a platform driver since we don't want
to remap the same register region again.

So, in the design, we may need to consider both situations, one
is otg/host/device has its own register region, and host is a
separate platform device (A), the other is three parts share the
same register region, there is only one platform driver (B).

A:

			IP core device 
			    |
			    |
		      |-----|-----|
		      gadget   host platform device	
		      		|
				roothub

B:

			IP core device
			    |
			    |
		      |-----|-----|
		      gadget   	 roothub
		      		

> This API must be called before the hcd/gadget-driver is added so that the otg
> core knows it's linked to an OTG controller.
> 
> Any better idea?
> 

A flag stands for this hcd controller is the same with otg controller
can be used, this flag can be stored at struct usb_otg_config.

Peter

P.S: I still read your code, I find not all APIs in this file are used
in your dwc3 example. 
> > 
> >> +	if (!otg_dev)
> >> +		return -EINVAL;	/* we're definitely not OTG */
> >> +
> >> +	/* we're otg but otg controller might not yet be registered */
> >> +	mutex_lock(&otg_list_mutex);
> >> +	otgd = usb_otg_get_data(otg_dev);
> >> +	mutex_unlock(&otg_list_mutex);
> >> +	if (!otgd) {
> >> +		dev_dbg(hcd_dev,
> >> +			"otg: controller not yet registered. waiting..\n");
> >> +		/*
> >> +		 * otg controller might register later. Put the hcd in
> >> +		 * wait list and call us back when ready
> >> +		 */
> >> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
> >> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
> >> +			return -EINVAL;
> >> +		}
> >> +
> >> +		return 0;
> >> +	}
> >> +
> >> +	/* HCD will be started by OTG fsm when needed */
> >> +	mutex_lock(&otgd->fsm.lock);
> >> +	if (otgd->primary_hcd.hcd) {
> >> +		/* probably a shared HCD ? */
> >> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
> >> +			dev_err(otg_dev, "otg: primary host already registered\n");
> >> +			goto err;
> >> +		}
> >> +
> >> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
> >> +			if (otgd->shared_hcd.hcd) {
> >> +				dev_err(otg_dev, "otg: shared host already registered\n");
> >> +				goto err;
> >> +			}
> >> +
> >> +			otgd->shared_hcd.hcd = hcd;
> >> +			otgd->shared_hcd.irqnum = irqnum;
> >> +			otgd->shared_hcd.irqflags = irqflags;
> >> +			otgd->shared_hcd.ops = ops;
> >> +			dev_info(otg_dev, "otg: shared host %s registered\n",
> >> +				 dev_name(hcd->self.controller));
> >> +		} else {
> >> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
> >> +				dev_name(hcd->self.controller));
> >> +			goto err;
> >> +		}
> >> +	} else {
> >> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
> >> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
> >> +			goto err;
> >> +		}
> >> +
> >> +		otgd->primary_hcd.hcd = hcd;
> >> +		otgd->primary_hcd.irqnum = irqnum;
> >> +		otgd->primary_hcd.irqflags = irqflags;
> >> +		otgd->primary_hcd.ops = ops;
> >> +		dev_info(otg_dev, "otg: primary host %s registered\n",
> >> +			 dev_name(hcd->self.controller));
> >> +	}
> >> +
> >> +	/*
> >> +	 * we're ready only if we have shared HCD
> >> +	 * or we don't need shared HCD.
> >> +	 */
> >> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
> >> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
> >> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
> >> +
> >> +		/* start FSM */
> >> +		usb_otg_start_fsm(&otgd->fsm);
> >> +	} else {
> >> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> >> +	}
> >> +
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +
> >> +	return 0;
> >> +
> >> +err:
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +	return -EINVAL;
> >> +}
> >> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> >> +
> >> +/**
> >> + * usb_otg_unregister_hcd - Unregister Host controller from OTG core
> >> + * @hcd:	Host controller device
> >> + *
> >> + * This is used by the USB Host stack to unregister the Host controller
> >> + * from the OTG core. Ensures that Host controller is not running
> >> + * on successful return.
> >> + *
> >> + * Returns: 0 on success, error value otherwise.
> >> + */
> >> +int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> >> +{
> >> +	struct usb_otg *otgd;
> >> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> >> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >> +
> >> +	if (!otg_dev)
> >> +		return -EINVAL;	/* we're definitely not OTG */
> >> +
> >> +	mutex_lock(&otg_list_mutex);
> >> +	otgd = usb_otg_get_data(otg_dev);
> >> +	mutex_unlock(&otg_list_mutex);
> >> +	if (!otgd) {
> >> +		/* are we in wait list? */
> >> +		if (!usb_otg_hcd_wait_remove(hcd))
> >> +			return 0;
> >> +
> >> +		dev_dbg(hcd_dev, "otg: host wasn't registered with otg\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	mutex_lock(&otgd->fsm.lock);
> >> +	if (hcd == otgd->primary_hcd.hcd) {
> >> +		otgd->primary_hcd.hcd = NULL;
> >> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> >> +			 dev_name(hcd_dev));
> >> +	} else if (hcd == otgd->shared_hcd.hcd) {
> >> +		otgd->shared_hcd.hcd = NULL;
> >> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> >> +			 dev_name(hcd_dev));
> >> +	} else {
> >> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> >> +			dev_name(hcd_dev));
> >> +		mutex_unlock(&otgd->fsm.lock);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	/* stop FSM & Host */
> >> +	usb_otg_stop_fsm(&otgd->fsm);
> >> +	otgd->fsm.otg->host = NULL;
> >> +
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> >> +
> >> +/**
> >> + * usb_otg_register_gadget - Register Gadget controller to OTG core
> >> + * @gadget:	Gadget controller
> >> + *
> >> + * This is used by the USB Gadget stack to register the Gadget controller
> >> + * to the OTG core. Gadget controller must not be started by the
> >> + * caller as it is left upto the OTG state machine to do so.
> >> + *
> >> + * Gadget core must call this only when all resources required for
> >> + * gadget controller to run are available.
> >> + * i.e. gadget function driver is available.
> >> + *
> >> + * Returns: 0 on success, error value otherwise.
> >> + */
> >> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> >> +			    struct otg_gadget_ops *ops)
> >> +{
> >> +	struct usb_otg *otgd;
> >> +	struct device *gadget_dev = &gadget->dev;
> >> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> >> +
> >> +	if (!otg_dev)
> >> +		return -EINVAL;	/* we're definitely not OTG */
> >> +
> >> +	/* we're otg but otg controller might not yet be registered */
> >> +	mutex_lock(&otg_list_mutex);
> >> +	otgd = usb_otg_get_data(otg_dev);
> >> +	mutex_unlock(&otg_list_mutex);
> >> +	if (!otgd) {
> >> +		dev_dbg(gadget_dev,
> >> +			"otg: controller not yet registered. waiting..\n");
> >> +		/*
> >> +		 * otg controller might register later. Put the gadget in
> >> +		 * wait list and call us back when ready
> >> +		 */
> >> +		if (usb_otg_gadget_wait_add(otg_dev, gadget, ops)) {
> >> +			dev_dbg(gadget_dev, "otg: failed to add to wait list\n");
> >> +			return -EINVAL;
> >> +		}
> >> +
> >> +		return 0;
> >> +	}
> >> +
> >> +	mutex_lock(&otgd->fsm.lock);
> >> +	if (otgd->fsm.otg->gadget) {
> >> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> >> +		mutex_unlock(&otgd->fsm.lock);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	otgd->fsm.otg->gadget = gadget;
> >> +	otgd->gadget_ops = ops;
> >> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> >> +		 dev_name(&gadget->dev));
> >> +
> >> +	/* start FSM */
> >> +	usb_otg_start_fsm(&otgd->fsm);
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> >> +
> >> +/**
> >> + * usb_otg_unregister_gadget - Unregister Gadget controller from OTG core
> >> + * @gadget:	Gadget controller
> >> + *
> >> + * This is used by the USB Gadget stack to unregister the Gadget controller
> >> + * from the OTG core. Ensures that Gadget controller is not running
> >> + * on successful return.
> >> + *
> >> + * Returns: 0 on success, error value otherwise.
> >> + */
> >> +int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> >> +{
> >> +	struct usb_otg *otgd;
> >> +	struct device *gadget_dev = &gadget->dev;
> >> +	struct device *otg_dev = usb_otg_get_device(gadget_dev);
> >> +
> >> +	if (!otg_dev)
> >> +		return -EINVAL;
> >> +
> >> +	mutex_lock(&otg_list_mutex);
> >> +	otgd = usb_otg_get_data(otg_dev);
> >> +	mutex_unlock(&otg_list_mutex);
> >> +	if (!otgd) {
> >> +		/* are we in wait list? */
> >> +		if (!usb_otg_gadget_wait_remove(gadget))
> >> +			return 0;
> >> +
> >> +		dev_dbg(gadget_dev, "otg: gadget wasn't registered with otg\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	mutex_lock(&otgd->fsm.lock);
> >> +	if (otgd->fsm.otg->gadget != gadget) {
> >> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> >> +			dev_name(&gadget->dev));
> >> +		mutex_unlock(&otgd->fsm.lock);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	/* Stop FSM & gadget */
> >> +	usb_otg_stop_fsm(&otgd->fsm);
> >> +	otgd->fsm.otg->gadget = NULL;
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +
> >> +	dev_info(otg_dev, "otg: gadget %s unregistered\n",
> >> +		 dev_name(&gadget->dev));
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
> >> +
> >> +/**
> >> + * usb_otg_fsm_to_dev - Get OTG controller device from struct otg_fsm
> >> + * @fsm:	otg_fsm data structure
> >> + *
> >> + * This is used by the OTG controller driver to get it's device node
> >> + * from any of the otg_fsm->ops.
> >> + */
> >> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> >> +{
> >> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> >> +
> >> +	return otgd->dev;
> >> +}
> >> +EXPORT_SYMBOL_GPL(usb_otg_fsm_to_dev);
> >> diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
> >> new file mode 100644
> >> index 0000000..05331f0
> >> --- /dev/null
> >> +++ b/drivers/usb/common/usb-otg.h
> >> @@ -0,0 +1,71 @@
> >> +/**
> >> + * drivers/usb/common/usb-otg.h - USB OTG core local header
> >> + *
> >> + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
> >> + * Author: Roger Quadros <rogerq@ti.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + */
> >> +
> >> +#ifndef __DRIVERS_USB_COMMON_USB_OTG_H
> >> +#define __DRIVERS_USB_COMMON_USB_OTG_H
> >> +
> >> +/*
> >> + *  A-DEVICE timing constants
> >> + */
> >> +
> >> +/* Wait for VBUS Rise  */
> >> +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2
> >> +					 * a_wait_vrise_tmr: section 7.4.5.1
> >> +					 * TA_VBUS_RISE <= 100ms, section 4.4
> >> +					 * Table 4-1: Electrical Characteristics
> >> +					 * ->DC Electrical Timing
> >> +					 */
> >> +/* Wait for VBUS Fall  */
> >> +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7
> >> +					 * a_wait_vfall_tmr: section: 7.4.5.2
> >> +					 */
> >> +/* Wait for B-Connect */
> >> +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3
> >> +					 * TA_WAIT_BCON: should be between 1100
> >> +					 * and 30000 ms, section 5.5, Table 5-1
> >> +					 */
> >> +/* A-Idle to B-Disconnect */
> >> +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1
> >> +					 * TA_AIDL_BDIS: section 5.5, Table 5-1
> >> +					 */
> >> +/* B-Idle to A-Disconnect */
> >> +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1
> >> +					 * 500ms is used for B switch to host
> >> +					 * for safe
> >> +					 */
> >> +
> >> +/*
> >> + * B-device timing constants
> >> + */
> >> +
> >> +/* Data-Line Pulse Time*/
> >> +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms
> >> +					 * section:5.1.3
> >> +					 */
> >> +/* SRP Fail Time  */
> >> +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s
> >> +					 * section:5.1.6
> >> +					 */
> >> +/* A-SE0 to B-Reset  */
> >> +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */
> >> +/* SE0 Time Before SRP */
> >> +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */
> >> +/* SSEND time before SRP */
> >> +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */
> >> +
> >> +#define TB_SESS_VLD          (1000)
> >> +
> >> +#endif /* __DRIVERS_USB_COMMON_USB_OTG_H */
> >> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
> >> index a99c89e..b468a9f 100644
> >> --- a/drivers/usb/core/Kconfig
> >> +++ b/drivers/usb/core/Kconfig
> >> @@ -42,7 +42,7 @@ config USB_DYNAMIC_MINORS
> >>  	  If you are unsure about this, say N here.
> >>  
> >>  config USB_OTG
> >> -	bool "OTG support"
> >> +	bool "OTG/Dual-role support"
> >>  	depends on PM
> >>  	default n
> >>  	help
> >> @@ -75,15 +75,6 @@ config USB_OTG_BLACKLIST_HUB
> >>  	  and software costs by not supporting external hubs.  So
> >>  	  are "Embedded Hosts" that don't offer OTG support.
> >>  
> >> -config USB_OTG_FSM
> >> -	tristate "USB 2.0 OTG FSM implementation"
> >> -	depends on USB
> >> -	select USB_OTG
> >> -	select USB_PHY
> >> -	help
> >> -	  Implements OTG Finite State Machine as specified in On-The-Go
> >> -	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
> >> -
> >>  config USB_ULPI_BUS
> >>  	tristate "USB ULPI PHY interface support"
> >>  	depends on USB_SUPPORT
> >> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> >> index bd1dcf8..38cabe0 100644
> >> --- a/include/linux/usb/otg.h
> >> +++ b/include/linux/usb/otg.h
> >> @@ -10,19 +10,100 @@
> >>  #define __LINUX_USB_OTG_H
> >>  
> >>  #include <linux/phy/phy.h>
> >> +#include <linux/device.h>
> >> +#include <linux/hrtimer.h>
> >> +#include <linux/ktime.h>
> >> +#include <linux/usb.h>
> >> +#include <linux/usb/hcd.h>
> >> +#include <linux/usb/gadget.h>
> >> +#include <linux/usb/otg-fsm.h>
> >>  #include <linux/usb/phy.h>
> >>  
> >> +/**
> >> + * struct otg_hcd - host controller state and interface
> >> + *
> >> + * @hcd: host controller
> >> + * @irqnum: irq number
> >> + * @irqflags: irq flags
> >> + * @ops: otg to host controller interface
> >> + */
> >> +struct otg_hcd {
> >> +	struct usb_hcd *hcd;
> >> +	unsigned int irqnum;
> >> +	unsigned long irqflags;
> >> +	struct otg_hcd_ops *ops;
> >> +};
> >> +
> >> +struct usb_otg;
> >> +
> >> +/**
> >> + * struct otg_timer - otg timer data
> >> + *
> >> + * @timer: high resolution timer
> >> + * @timeout: timeout value
> >> + * @timetout_bit: pointer to variable that is set on timeout
> >> + * @otgd: usb otg data
> >> + */
> >> +struct otg_timer {
> >> +	struct hrtimer timer;
> >> +	ktime_t timeout;
> >> +	/* callback data */
> >> +	int *timeout_bit;
> >> +	struct usb_otg *otgd;
> >> +};
> >> +
> >> +/**
> >> + * struct usb_otg - usb otg controller state
> >> + *
> >> + * @default_a: Indicates we are an A device. i.e. Host.
> >> + * @phy: USB phy interface
> >> + * @usb_phy: old usb_phy interface
> >> + * @host: host controller bus
> >> + * @gadget: gadget device
> >> + * @state: current otg state
> >> + * @dev: otg controller device
> >> + * @caps: otg capabilities revision, hnp, srp, etc
> >> + * @fsm: otg finite state machine
> >> + * @fsm_ops: controller hooks for the state machine
> >> + * ------- internal use only -------
> >> + * @primary_hcd: primary host state and interface
> >> + * @shared_hcd: shared host state and interface
> >> + * @gadget_ops: gadget interface
> >> + * @timers: otg timers for state machine
> >> + * @list: list of otg controllers
> >> + * @work: otg state machine work
> >> + * @wq: otg state machine work queue
> >> + * @fsm_running: state machine running/stopped indicator
> >> + */
> >>  struct usb_otg {
> >>  	u8			default_a;
> >>  
> >>  	struct phy		*phy;
> >>  	/* old usb_phy interface */
> >>  	struct usb_phy		*usb_phy;
> >> +
> >>  	struct usb_bus		*host;
> >>  	struct usb_gadget	*gadget;
> >>  
> >>  	enum usb_otg_state	state;
> >>  
> >> +	struct device *dev;
> >> +	struct usb_otg_caps *caps;
> >> +	struct otg_fsm fsm;
> >> +	struct otg_fsm_ops fsm_ops;
> >> +
> >> +	/* internal use only */
> >> +	struct otg_hcd primary_hcd;
> >> +	struct otg_hcd shared_hcd;
> >> +	struct otg_gadget_ops *gadget_ops;
> >> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
> >> +	struct list_head list;
> >> +	struct work_struct work;
> >> +	struct workqueue_struct *wq;
> >> +	bool fsm_running;
> >> +	/* use otg->fsm.lock for serializing access */
> >> +
> >> +/*------------- deprecated interface -----------------------------*/
> >>  	/* bind/unbind the host controller */
> >>  	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
> >>  
> >> @@ -38,7 +119,7 @@ struct usb_otg {
> >>  
> >>  	/* start or continue HNP role switch */
> >>  	int	(*start_hnp)(struct usb_otg *otg);
> >> -
> >> +/*---------------------------------------------------------------*/
> >>  };
> >>  
> >>  /**
> >> @@ -56,8 +137,105 @@ struct usb_otg_caps {
> >>  	bool adp_support;
> >>  };
> >>  
> >> +/**
> >> + * struct usb_otg_config - otg controller configuration
> >> + * @caps: otg capabilities of the controller
> >> + * @ops: otg fsm operations
> >> + * @otg_timeouts: override default otg fsm timeouts
> >> + */
> >> +struct usb_otg_config {
> >> +	struct usb_otg_caps otg_caps;
> >> +	struct otg_fsm_ops *fsm_ops;
> >> +	unsigned otg_timeouts[NUM_OTG_FSM_TIMERS];
> >> +};
> >> +
> >>  extern const char *usb_otg_state_string(enum usb_otg_state state);
> >>  
> >> +enum usb_dr_mode {
> >> +	USB_DR_MODE_UNKNOWN,
> >> +	USB_DR_MODE_HOST,
> >> +	USB_DR_MODE_PERIPHERAL,
> >> +	USB_DR_MODE_OTG,
> >> +};
> >> +
> >> +#if IS_ENABLED(CONFIG_USB_OTG)
> >> +struct otg_fsm *usb_otg_register(struct device *dev,
> >> +				 struct usb_otg_config *config);
> >> +int usb_otg_unregister(struct device *dev);
> >> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >> +			 unsigned long irqflags, struct otg_hcd_ops *ops);
> >> +int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> >> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> >> +			    struct otg_gadget_ops *ops);
> >> +int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> >> +void usb_otg_sync_inputs(struct otg_fsm *fsm);
> >> +int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> >> +struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> >> +int usb_otg_start_host(struct otg_fsm *fsm, int on);
> >> +int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> >> +
> >> +#else /* CONFIG_USB_OTG */
> >> +
> >> +static inline struct otg_fsm *usb_otg_register(struct device *dev,
> >> +					       struct usb_otg_config *config)
> >> +{
> >> +	return ERR_PTR(-ENOTSUPP);
> >> +}
> >> +
> >> +static inline int usb_otg_unregister(struct device *dev)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >> +				       unsigned long irqflags,
> >> +				       struct otg_hcd_ops *ops)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
> >> +					  struct otg_gadget_ops *ops)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline void usb_otg_sync_inputs(struct otg_fsm *fsm)
> >> +{
> >> +}
> >> +
> >> +static inline int usb_otg_kick_fsm(struct device *hcd_gcd_device)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline int usb_otg_start_host(struct otg_fsm *fsm, int on)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +
> >> +static inline int usb_otg_start_gadget(struct otg_fsm *fsm, int on)
> >> +{
> >> +	return -ENOTSUPP;
> >> +}
> >> +#endif /* CONFIG_USB_OTG */
> >> +
> >> +/*------------- deprecated interface -----------------------------*/
> >>  /* Context: can sleep */
> >>  static inline int
> >>  otg_start_hnp(struct usb_otg *otg)
> >> @@ -109,14 +287,9 @@ otg_start_srp(struct usb_otg *otg)
> >>  	return -ENOTSUPP;
> >>  }
> >>  
> >> +/*---------------------------------------------------------------*/
> >> +
> >>  /* for OTG controller drivers (and maybe other stuff) */
> >>  extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
> >>  
> >> -enum usb_dr_mode {
> >> -	USB_DR_MODE_UNKNOWN,
> >> -	USB_DR_MODE_HOST,
> >> -	USB_DR_MODE_PERIPHERAL,
> >> -	USB_DR_MODE_OTG,
> >> -};
> >> -
> >>  #endif /* __LINUX_USB_OTG_H */
> >> -- 
> >> 2.1.4
> >>
> > 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-08  8:31       ` Peter Chen
@ 2015-09-08 12:25         ` Roger Quadros
  2015-09-08 14:34           ` Alan Stern
  2015-09-09  2:21           ` Peter Chen
  0 siblings, 2 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-08 12:25 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap



On 08/09/15 11:31, Peter Chen wrote:
> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>> On 07/09/15 04:23, Peter Chen wrote:
>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>> + * This is used by the USB Host stack to register the Host controller
>>>> + * to the OTG core. Host controller must not be started by the
>>>> + * caller as it is left upto the OTG state machine to do so.
>>>> + *
>>>> + * Returns: 0 on success, error value otherwise.
>>>> + */
>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>> +{
>>>> +	struct usb_otg *otgd;
>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>> +
>>>
>>> One big problem here is: there are two designs for current (IP) driver
>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>> in your patch), like chipidea and dwc2.
>>>
>>> Then, otg_dev will be glue layer device for chipidea after that.
>>
>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>> information to the otg core for such devices like chipidea and dwc2.
>>
> 
> Roger, not only chipidea and dwc2, I think the musb uses the same
> hierarchy. If the host, device, and otg share the same register
> region, host part can't be a platform driver since we don't want
> to remap the same register region again.
> 
> So, in the design, we may need to consider both situations, one
> is otg/host/device has its own register region, and host is a
> separate platform device (A), the other is three parts share the
> same register region, there is only one platform driver (B).
> 
> A:
> 
> 			IP core device 
> 			    |
> 			    |
> 		      |-----|-----|
> 		      gadget   host platform device	
> 		      		|
> 				roothub
> 
> B:
> 
> 			IP core device
> 			    |
> 			    |
> 		      |-----|-----|
> 		      gadget   	 roothub
> 		      		
> 
>> This API must be called before the hcd/gadget-driver is added so that the otg
>> core knows it's linked to an OTG controller.
>>
>> Any better idea?
>>
> 
> A flag stands for this hcd controller is the same with otg controller
> can be used, this flag can be stored at struct usb_otg_config.

What if there is another architecture like so?

C:
			[Parent]
			   |
			   |
		|------------------|--------------|
	[OTG core]		[gadget]	[host]

We need a more flexible mechanism to link the gadget and
host device to the otg core for non DT case.

How about adding struct usb_otg parameter to usb_otg_register_hcd()?

e.g.
int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)

If otg is NULL it will try DT otg-controller property or parent to
get the otg controller.

> 
> Peter
> 
> P.S: I still read your code, I find not all APIs in this file are used
> in your dwc3 example. 

Which ones? The ones for registering/unregistered host/gadget are used
by hcd/udc core as part of usb_add/remove_hcd() and
udc_bind_to_driver()/usb_gadget_remove_driver()

cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-08 12:25         ` Roger Quadros
@ 2015-09-08 14:34           ` Alan Stern
  2015-09-08 17:29             ` Roger Quadros
  2015-09-09  2:21           ` Peter Chen
  1 sibling, 1 reply; 49+ messages in thread
From: Alan Stern @ 2015-09-08 14:34 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Peter Chen, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Tue, 8 Sep 2015, Roger Quadros wrote:

> On 08/09/15 11:31, Peter Chen wrote:
> > On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >> On 07/09/15 04:23, Peter Chen wrote:
> >>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>> + * This is used by the USB Host stack to register the Host controller
> >>>> + * to the OTG core. Host controller must not be started by the
> >>>> + * caller as it is left upto the OTG state machine to do so.
> >>>> + *
> >>>> + * Returns: 0 on success, error value otherwise.
> >>>> + */
> >>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>> +{
> >>>> +	struct usb_otg *otgd;
> >>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>> +
> >>>
> >>> One big problem here is: there are two designs for current (IP) driver
> >>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>> in your patch), like chipidea and dwc2.
> >>>
> >>> Then, otg_dev will be glue layer device for chipidea after that.
> >>
> >> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >> information to the otg core for such devices like chipidea and dwc2.
> >>
> > 
> > Roger, not only chipidea and dwc2, I think the musb uses the same
> > hierarchy. If the host, device, and otg share the same register
> > region, host part can't be a platform driver since we don't want
> > to remap the same register region again.
> > 
> > So, in the design, we may need to consider both situations, one
> > is otg/host/device has its own register region, and host is a
> > separate platform device (A), the other is three parts share the
> > same register region, there is only one platform driver (B).
> > 
> > A:
> > 
> > 			IP core device 
> > 			    |
> > 			    |
> > 		      |-----|-----|
> > 		      gadget   host platform device	
> > 		      		|
> > 				roothub
> > 
> > B:
> > 
> > 			IP core device
> > 			    |
> > 			    |
> > 		      |-----|-----|
> > 		      gadget   	 roothub
> > 		      		
> > 
> >> This API must be called before the hcd/gadget-driver is added so that the otg
> >> core knows it's linked to an OTG controller.
> >>
> >> Any better idea?
> >>
> > 
> > A flag stands for this hcd controller is the same with otg controller
> > can be used, this flag can be stored at struct usb_otg_config.
> 
> What if there is another architecture like so?
> 
> C:
> 			[Parent]
> 			   |
> 			   |
> 		|------------------|--------------|
> 	[OTG core]		[gadget]	[host]
> 
> We need a more flexible mechanism to link the gadget and
> host device to the otg core for non DT case.
> 
> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> 
> e.g.
> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> 
> If otg is NULL it will try DT otg-controller property or parent to
> get the otg controller.

This seems a lot like something Peter and I discussed recently.  See

	http://marc.info/?l=linux-usb&m=143977568021328&w=2

and the following messages in that thread.

Alan Stern



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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-08 14:34           ` Alan Stern
@ 2015-09-08 17:29             ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-08 17:29 UTC (permalink / raw)
  To: Alan Stern
  Cc: Peter Chen, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

Alan,

On 08/09/15 17:34, Alan Stern wrote:
> On Tue, 8 Sep 2015, Roger Quadros wrote:
> 
>> On 08/09/15 11:31, Peter Chen wrote:
>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>>>> On 07/09/15 04:23, Peter Chen wrote:
>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>>>> + * This is used by the USB Host stack to register the Host controller
>>>>>> + * to the OTG core. Host controller must not be started by the
>>>>>> + * caller as it is left upto the OTG state machine to do so.
>>>>>> + *
>>>>>> + * Returns: 0 on success, error value otherwise.
>>>>>> + */
>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>>>> +{
>>>>>> +	struct usb_otg *otgd;
>>>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>>>> +
>>>>>
>>>>> One big problem here is: there are two designs for current (IP) driver
>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>>>> in your patch), like chipidea and dwc2.
>>>>>
>>>>> Then, otg_dev will be glue layer device for chipidea after that.
>>>>
>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>>>> information to the otg core for such devices like chipidea and dwc2.
>>>>
>>>
>>> Roger, not only chipidea and dwc2, I think the musb uses the same
>>> hierarchy. If the host, device, and otg share the same register
>>> region, host part can't be a platform driver since we don't want
>>> to remap the same register region again.
>>>
>>> So, in the design, we may need to consider both situations, one
>>> is otg/host/device has its own register region, and host is a
>>> separate platform device (A), the other is three parts share the
>>> same register region, there is only one platform driver (B).
>>>
>>> A:
>>>
>>> 			IP core device 
>>> 			    |
>>> 			    |
>>> 		      |-----|-----|
>>> 		      gadget   host platform device	
>>> 		      		|
>>> 				roothub
>>>
>>> B:
>>>
>>> 			IP core device
>>> 			    |
>>> 			    |
>>> 		      |-----|-----|
>>> 		      gadget   	 roothub
>>> 		      		
>>>
>>>> This API must be called before the hcd/gadget-driver is added so that the otg
>>>> core knows it's linked to an OTG controller.
>>>>
>>>> Any better idea?
>>>>
>>>
>>> A flag stands for this hcd controller is the same with otg controller
>>> can be used, this flag can be stored at struct usb_otg_config.
>>
>> What if there is another architecture like so?
>>
>> C:
>> 			[Parent]
>> 			   |
>> 			   |
>> 		|------------------|--------------|
>> 	[OTG core]		[gadget]	[host]
>>
>> We need a more flexible mechanism to link the gadget and
>> host device to the otg core for non DT case.
>>
>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
>>
>> e.g.
>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
>>
>> If otg is NULL it will try DT otg-controller property or parent to
>> get the otg controller.
> 
> This seems a lot like something Peter and I discussed recently.  See
> 
> 	http://marc.info/?l=linux-usb&m=143977568021328&w=2
> 
> and the following messages in that thread.
> 

If I understood right, your proposal was to add a usb_pointers data
struct to the device's drvdata?

This is fine only if the otg/gadget/host share the same device.
It does not solve the problem where each have different platform devices.

cheers,
-roger


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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-08 12:25         ` Roger Quadros
  2015-09-08 14:34           ` Alan Stern
@ 2015-09-09  2:21           ` Peter Chen
  2015-09-09  9:08             ` Roger Quadros
  1 sibling, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-09  2:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
> 
> 
> On 08/09/15 11:31, Peter Chen wrote:
> > On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >> On 07/09/15 04:23, Peter Chen wrote:
> >>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>> + * This is used by the USB Host stack to register the Host controller
> >>>> + * to the OTG core. Host controller must not be started by the
> >>>> + * caller as it is left upto the OTG state machine to do so.
> >>>> + *
> >>>> + * Returns: 0 on success, error value otherwise.
> >>>> + */
> >>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>> +{
> >>>> +	struct usb_otg *otgd;
> >>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>> +
> >>>
> >>> One big problem here is: there are two designs for current (IP) driver
> >>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>> in your patch), like chipidea and dwc2.
> >>>
> >>> Then, otg_dev will be glue layer device for chipidea after that.
> >>
> >> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >> information to the otg core for such devices like chipidea and dwc2.
> >>
> > 
> > Roger, not only chipidea and dwc2, I think the musb uses the same
> > hierarchy. If the host, device, and otg share the same register
> > region, host part can't be a platform driver since we don't want
> > to remap the same register region again.
> > 
> > So, in the design, we may need to consider both situations, one
> > is otg/host/device has its own register region, and host is a
> > separate platform device (A), the other is three parts share the
> > same register region, there is only one platform driver (B).
> > 
> > A:
> > 
> > 			IP core device 
> > 			    |
> > 			    |
> > 		      |-----|-----|
> > 		      gadget   host platform device	
> > 		      		|
> > 				roothub
> > 
> > B:
> > 
> > 			IP core device
> > 			    |
> > 			    |
> > 		      |-----|-----|
> > 		      gadget   	 roothub
> > 		      		
> > 
> >> This API must be called before the hcd/gadget-driver is added so that the otg
> >> core knows it's linked to an OTG controller.
> >>
> >> Any better idea?
> >>
> > 
> > A flag stands for this hcd controller is the same with otg controller
> > can be used, this flag can be stored at struct usb_otg_config.
> 
> What if there is another architecture like so?
> 
> C:
> 			[Parent]
> 			   |
> 			   |
> 		|------------------|--------------|
> 	[OTG core]		[gadget]	[host]
> 
> We need a more flexible mechanism to link the gadget and
> host device to the otg core for non DT case.
> 
> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> 
> e.g.
> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> 
> If otg is NULL it will try DT otg-controller property or parent to
> get the otg controller.

How usb_otg_register_hcd get struct usb_otg, from where?

> 
> > 
> > Peter
> > 
> > P.S: I still read your code, I find not all APIs in this file are used
> > in your dwc3 example. 
> 
> Which ones? The ones for registering/unregistered host/gadget are used
> by hcd/udc core as part of usb_add/remove_hcd() and
> udc_bind_to_driver()/usb_gadget_remove_driver()
> 

Ok, now I understand your design, usb_create_hcd must be called before
the fsm kicks off. The call flow like below:

usb_otg_register->usb_create_hcd->usb_add_hcd->usb_otg_register_hcd->
usb_otg_start_host->usb_otg_add_hcd

We need to make some changes to let chipidea work since usb_create_hcd
is included at host->start.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 10/13] usb: hcd: Adapt to OTG core
  2015-08-24 13:21 ` [PATCH v4 10/13] usb: hcd: Adapt to OTG core Roger Quadros
@ 2015-09-09  2:23   ` Peter Chen
  2015-09-09  9:39     ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-09  2:23 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:21PM +0300, Roger Quadros wrote:
> The existing usb_add/remove_hcd() functionality
> remains unchanged for non-OTG devices. For OTG
> devices they only register the HCD with the OTG core.
> 
> Introduce usb_otg_add/remove_hcd() for use by OTG core.
> These functions actually add/remove the HCD.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/usb/core/hcd.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 50 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index c0fd1f6..4851682 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -46,6 +46,7 @@
>  #include <linux/usb.h>
>  #include <linux/usb/hcd.h>
>  #include <linux/usb/phy.h>
> +#include <linux/usb/otg.h>
>  
>  #include "usb.h"
>  
> @@ -2625,8 +2626,8 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
>   * buffers of consistent memory, register the bus, request the IRQ line,
>   * and call the driver's reset() and start() routines.
>   */
> -int usb_add_hcd(struct usb_hcd *hcd,
> -		unsigned int irqnum, unsigned long irqflags)
> +static int usb_otg_add_hcd(struct usb_hcd *hcd,
> +			   unsigned int irqnum, unsigned long irqflags)

You may change the kernel doc to this name too.

>  {
>  	int retval;
>  	struct usb_device *rhdev;
> @@ -2839,17 +2840,16 @@ err_phy:
>  	}
>  	return retval;
>  }
> -EXPORT_SYMBOL_GPL(usb_add_hcd);
>  
>  /**
> - * usb_remove_hcd - shutdown processing for generic HCDs
> + * usb_otg_remove_hcd - shutdown processing for generic HCDs
>   * @hcd: the usb_hcd structure to remove
>   * Context: !in_interrupt()
>   *
>   * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
>   * invoking the HCD's stop() method.
>   */
> -void usb_remove_hcd(struct usb_hcd *hcd)
> +static void usb_otg_remove_hcd(struct usb_hcd *hcd)
>  {
>  	struct usb_device *rhdev = hcd->self.root_hub;
>  
> @@ -2923,6 +2923,51 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  
>  	usb_put_invalidate_rhdev(hcd);
>  }
> +
> +static struct otg_hcd_ops otg_hcd_intf = {
> +	.add = usb_otg_add_hcd,
> +	.remove = usb_otg_remove_hcd,
> +};
> +
> +/**
> + * usb_add_hcd - finish generic HCD structure initialization and register
> + * @hcd: the usb_hcd structure to initialize
> + * @irqnum: Interrupt line to allocate
> + * @irqflags: Interrupt type flags
> + *
> + * Finish the remaining parts of generic HCD initialization: allocate the
> + * buffers of consistent memory, register the bus, request the IRQ line,
> + * and call the driver's reset() and start() routines.
> + * If it is an OTG device then it only registers the HCD with OTG core.
> + *
> + */
> +int usb_add_hcd(struct usb_hcd *hcd,
> +		unsigned int irqnum, unsigned long irqflags)
> +{
> +	/* If OTG device, OTG core takes care of adding HCD */
> +	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
> +		return usb_otg_add_hcd(hcd, irqnum, irqflags);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_add_hcd);
> +
> +/**
> + * usb_remove_hcd - shutdown processing for generic HCDs
> + * @hcd: the usb_hcd structure to remove
> + * Context: !in_interrupt()
> + *
> + * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
> + * invoking the HCD's stop() method.
> + * If it is an OTG device then it unregisters the HCD from OTG core
> + * as well.
> + */
> +void usb_remove_hcd(struct usb_hcd *hcd)
> +{
> +	/* If OTG device, OTG core takes care of stopping HCD */
> +	if (usb_otg_unregister_hcd(hcd))
> +		usb_otg_remove_hcd(hcd);
> +}
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
>  void
> -- 
> 2.1.4
> 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-07 10:53     ` Roger Quadros
@ 2015-09-09  6:20       ` Li Jun
  2015-09-09 10:01         ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Li Jun @ 2015-09-09  6:20 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On Mon, Sep 07, 2015 at 01:53:19PM +0300, Roger Quadros wrote:
> On 07/09/15 10:40, Li Jun wrote:
> > On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >> The OTG core instantiates the OTG Finite State Machine
> >> per OTG controller and manages starting/stopping the
> >> host and gadget controllers based on the bus state.
> >>
> >> It provides APIs for the following tasks
> >>
> >> - Registering an OTG capable controller
> >> - Registering Host and Gadget controllers to OTG core
> >> - Providing inputs to and kicking the OTG state machine
> >>
> >> Signed-off-by: Roger Quadros <rogerq@ti.com>
> >> ---
> >>  MAINTAINERS                  |    4 +-
> >>  drivers/usb/Kconfig          |    2 +-
> >>  drivers/usb/Makefile         |    1 +
> >>  drivers/usb/common/Makefile  |    3 +-
> >>  drivers/usb/common/usb-otg.c | 1061 ++++++++++++++++++++++++++++++++++++++++++
> >>  drivers/usb/common/usb-otg.h |   71 +++
> >>  drivers/usb/core/Kconfig     |   11 +-
> >>  include/linux/usb/otg.h      |  189 +++++++-
> >>  8 files changed, 1321 insertions(+), 21 deletions(-)
> >>  create mode 100644 drivers/usb/common/usb-otg.c
> >>  create mode 100644 drivers/usb/common/usb-otg.h
> >>
> > 
> > ... ...
> > 
> >> +
> >> +/**
> >> + * Get OTG device from host or gadget device.
> >> + *
> >> + * For non device tree boot, the OTG controller is assumed to be
> >> + * the parent of the host/gadget device.
> > 
> > This assumption/restriction maybe a problem, as I pointed in your previous
> > version, usb_create_hcd() use the passed dev as its dev, but,
> > usb_add_gadget_udc() use the passed dev as its parent dev, so often the
> > host and gadget don't share the same parent device, at least it doesn't
> > apply to chipidea case.
> 
> Let's provide a way for OTG driver to provide the OTG core exactly which is
> the related host/gadget device.
> 
> > 
> >> + * For device tree boot, the OTG controller is derived from the
> >> + * "otg-controller" property.
> >> + */
> >> +static struct device *usb_otg_get_device(struct device *hcd_gcd_dev)
> >> +{
> >> +	struct device *otg_dev;
> >> +
> >> +	if (!hcd_gcd_dev)
> >> +		return NULL;
> >> +
> >> +	if (hcd_gcd_dev->of_node) {
> >> +		struct device_node *np;
> >> +		struct platform_device *pdev;
> >> +
> >> +		np = of_parse_phandle(hcd_gcd_dev->of_node, "otg-controller",
> >> +				      0);
> >> +		if (!np)
> >> +			goto legacy;	/* continue legacy way */
> >> +
> >> +		pdev = of_find_device_by_node(np);
> >> +		of_node_put(np);
> >> +		if (!pdev) {
> >> +			dev_err(&pdev->dev, "couldn't get otg-controller device\n");
> >> +			return NULL;
> >> +		}
> >> +
> >> +		otg_dev = &pdev->dev;
> >> +		return otg_dev;
> >> +	}
> >> +
> >> +legacy:
> >> +	/* otg device is parent and must be registered */
> >> +	otg_dev = hcd_gcd_dev->parent;
> >> +	if (!usb_otg_get_data(otg_dev))
> >> +		return NULL;
> >> +
> >> +	return otg_dev;
> >> +}
> >> +
> > 
> > ... ...
> > 
> >> +static void usb_otg_init_timers(struct usb_otg *otgd, unsigned *timeouts)
> >> +{
> >> +	struct otg_fsm *fsm = &otgd->fsm;
> >> +	unsigned long tmouts[NUM_OTG_FSM_TIMERS];
> >> +	int i;
> >> +
> >> +	/* set default timeouts */
> >> +	tmouts[A_WAIT_VRISE] = TA_WAIT_VRISE;
> >> +	tmouts[A_WAIT_VFALL] = TA_WAIT_VFALL;
> >> +	tmouts[A_WAIT_BCON] = TA_WAIT_BCON;
> >> +	tmouts[A_AIDL_BDIS] = TA_AIDL_BDIS;
> >> +	tmouts[A_BIDL_ADIS] = TA_BIDL_ADIS;
> >> +	tmouts[B_ASE0_BRST] = TB_ASE0_BRST;
> >> +	tmouts[B_SE0_SRP] = TB_SE0_SRP;
> >> +	tmouts[B_SRP_FAIL] = TB_SRP_FAIL;
> >> +
> >> +	/* set controller provided timeouts */
> >> +	if (timeouts) {
> >> +		for (i = 0; i < NUM_OTG_FSM_TIMERS; i++) {
> >> +			if (timeouts[i])
> >> +				tmouts[i] = timeouts[i];
> >> +		}
> >> +	}
> >> +
> >> +	otg_timer_init(A_WAIT_VRISE, otgd, set_tmout, TA_WAIT_VRISE,
> >> +		       &fsm->a_wait_vrise_tmout);
> >> +	otg_timer_init(A_WAIT_VFALL, otgd, set_tmout, TA_WAIT_VFALL,
> >> +		       &fsm->a_wait_vfall_tmout);
> >> +	otg_timer_init(A_WAIT_BCON, otgd, set_tmout, TA_WAIT_BCON,
> >> +		       &fsm->a_wait_bcon_tmout);
> >> +	otg_timer_init(A_AIDL_BDIS, otgd, set_tmout, TA_AIDL_BDIS,
> >> +		       &fsm->a_aidl_bdis_tmout);
> >> +	otg_timer_init(A_BIDL_ADIS, otgd, set_tmout, TA_BIDL_ADIS,
> >> +		       &fsm->a_bidl_adis_tmout);
> >> +	otg_timer_init(B_ASE0_BRST, otgd, set_tmout, TB_ASE0_BRST,
> >> +		       &fsm->b_ase0_brst_tmout);
> >> +
> >> +	otg_timer_init(B_SE0_SRP, otgd, set_tmout, TB_SE0_SRP,
> >> +		       &fsm->b_se0_srp);
> >> +	otg_timer_init(B_SRP_FAIL, otgd, set_tmout, TB_SRP_FAIL,
> >> +		       &fsm->b_srp_done);
> >> +
> >> +	/* FIXME: what about A_WAIT_ENUM? */
> > 
> > Either you init it as other timers, or you remove all of it, otherwise
> > there will be NULL pointer crash.
> 
> I want to initialize it but was not sure about the timeout value.
> What timeout value I must use?
> 

It's not defined in OTG spec, I don't know either.
or you filter it out when add/del timer in below 2 functions.
	if (id == A_WAIT_ENUM)
		return;

> > 
> >> +}
> >> +
> >> +/**
> >> + * OTG FSM ops function to add timer
> >> + */
> >> +static void usb_otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
> >> +{
> >> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> >> +	struct otg_timer *otgtimer = &otgd->timers[id];
> >> +	struct hrtimer *timer = &otgtimer->timer;
> >> +
> >> +	if (!otgd->fsm_running)
> >> +		return;
> >> +
> >> +	/* if timer is already active, exit */
> >> +	if (hrtimer_active(timer)) {
> >> +		dev_err(otgd->dev, "otg: timer %d is already running\n", id);
> >> +		return;
> >> +	}
> >> +
> >> +	hrtimer_start(timer, otgtimer->timeout, HRTIMER_MODE_REL);
> >> +}
> >> +
> >> +/**
> >> + * OTG FSM ops function to delete timer
> >> + */
> >> +static void usb_otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
> >> +{
> >> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
> >> +	struct hrtimer *timer = &otgd->timers[id].timer;
> >> +
> >> +	hrtimer_cancel(timer);
> >> +}
> >> +

... ...

> >> +	}
> >> +
> >> +	otgd->dev = dev;
> >> +	otgd->caps = &config->otg_caps;
> > 
> > How about define otgd->caps as a pointer, then don't need copy it.
> 
> otgd->caps is a pointer.
> 

okay, you are right.

> > 
> >> +	INIT_WORK(&otgd->work, usb_otg_work);
> >> +	otgd->wq = create_singlethread_workqueue("usb_otg");
> >> +	if (!otgd->wq) {
> >> +		dev_err(dev, "otg: %s: can't create workqueue\n",
> >> +			__func__);
> >> +		ret = -ENOMEM;
> >> +		goto err_wq;
> >> +	}
> >> +
> >> +	usb_otg_init_timers(otgd, config->otg_timeouts);
> >> +
> >> +	/* create copy of original ops */
> >> +	otgd->fsm_ops = *config->fsm_ops;
> > 
> > The same, use a pointer is enough?
> 
> We are creating a copy because we are overriding timer ops.
> 

okay.

> > 
> >> +	/* FIXME: we ignore caller's timer ops */
> >> +	otgd->fsm_ops.add_timer = usb_otg_add_timer;
> >> +	otgd->fsm_ops.del_timer = usb_otg_del_timer;
> >> +	/* set otg ops */
> >> +	otgd->fsm.ops = &otgd->fsm_ops;
> >> +	otgd->fsm.otg = otgd;
> >> + *

... ...

> >> + * This is used by the USB Host stack to register the Host controller
> >> + * to the OTG core. Host controller must not be started by the
> >> + * caller as it is left upto the OTG state machine to do so.
> > 
> > I am confused on how to use this function.
> > - This function should be called before start fsm per usb_otg_start_fsm().
> 
> yes.
> 
> > - Called by usb_add_hcd(), so we need call usb_add_hcd() before start fsm.
> 
> yes.
> 
> > - If I want to add hcd when switch to host role, and remove hcd when switch
> >   to peripheral, with this design, I cannot use this function?
> 
> You add hcd only once during the life of the OTG device. If it is linked to the
> OTG controller the OTG fsm manages the start/stop of hcd using the otg_hcd_ops.
> 
> "usb/core/hcd.c"
> static struct otg_hcd_ops otg_hcd_intf = {
>         .add = usb_otg_add_hcd,
>         .remove = usb_otg_remove_hcd,
> };
> 
> Your otg driver must use teh usb_otg_add/remove_hcd to start/stop the controller.
> Using usb_remove_hcd() means the hcd resource is no longer available and the
> otg fsm will be stopped.
> 
> > - How about split it out of usb_add_hcd()?
> 
> Adding the HCD and starting/stopping the hcd is split into
> usb_add/remove_hcd() and usb_otg_add/remove_hcd() for OTG case.
> 

Catch your point now.
Do usb_add_hcd to register hcd before start fsm, and use usb_otg_start_host()
to start/stop host role for otg fsm.

> > 
> >> + *
> >> + * Returns: 0 on success, error value otherwise.
> >> + */
> >> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >> +{
> >> +	struct usb_otg *otgd;
> >> +	struct device *hcd_dev = hcd->self.controller;
> >> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >> +
> >> +	if (!otg_dev)
> >> +		return -EINVAL;	/* we're definitely not OTG */
> >> +
> >> +	/* we're otg but otg controller might not yet be registered */
> >> +	mutex_lock(&otg_list_mutex);
> >> +	otgd = usb_otg_get_data(otg_dev);
> >> +	mutex_unlock(&otg_list_mutex);
> >> +	if (!otgd) {
> >> +		dev_dbg(hcd_dev,
> >> +			"otg: controller not yet registered. waiting..\n");
> >> +		/*
> >> +		 * otg controller might register later. Put the hcd in
> >> +		 * wait list and call us back when ready
> >> +		 */
> >> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
> >> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
> >> +			return -EINVAL;
> >> +		}
> >> +
> >> +		return 0;
> >> +	}
> >> +
> >> +	/* HCD will be started by OTG fsm when needed */
> >> +	mutex_lock(&otgd->fsm.lock);
> > 
> > If call usb_add_hcd() when start host role, deadlock.
> 
> No. You must call usb_otg_add_hcd() to start host role.
> 
> > 
> >> +	if (otgd->primary_hcd.hcd) {
> >> +		/* probably a shared HCD ? */
> >> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
> >> +			dev_err(otg_dev, "otg: primary host already registered\n");
> >> +			goto err;
> >> +		}
> >> +
> >> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
> >> +			if (otgd->shared_hcd.hcd) {
> >> +				dev_err(otg_dev, "otg: shared host already registered\n");
> >> +				goto err;
> >> +			}
> >> +
> >> +			otgd->shared_hcd.hcd = hcd;
> >> +			otgd->shared_hcd.irqnum = irqnum;
> >> +			otgd->shared_hcd.irqflags = irqflags;
> >> +			otgd->shared_hcd.ops = ops;
> >> +			dev_info(otg_dev, "otg: shared host %s registered\n",
> >> +				 dev_name(hcd->self.controller));
> >> +		} else {
> >> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
> >> +				dev_name(hcd->self.controller));
> >> +			goto err;
> >> +		}
> >> +	} else {
> >> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
> >> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
> >> +			goto err;
> >> +		}
> >> +
> >> +		otgd->primary_hcd.hcd = hcd;
> >> +		otgd->primary_hcd.irqnum = irqnum;
> >> +		otgd->primary_hcd.irqflags = irqflags;
> >> +		otgd->primary_hcd.ops = ops;
> >> +		dev_info(otg_dev, "otg: primary host %s registered\n",
> >> +			 dev_name(hcd->self.controller));
> >> +	}
> >> +
> >> +	/*
> >> +	 * we're ready only if we have shared HCD
> >> +	 * or we don't need shared HCD.
> >> +	 */
> >> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
> >> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
> > 
> > otgd->host = hcd_to_bus(hcd);
> 
> ok. So we set host at both places. struct usb_otg in struct otg_fsm starts to
> feel redundant now. I think we should get rid of it and get the usb_otg struct
> using container_of() instead.
> 

Then you may come to force existing otg fsm code to use your OTG core.

> > 
> >> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
> >> +
> >> +		/* start FSM */
> >> +		usb_otg_start_fsm(&otgd->fsm);
> >> +	} else {
> >> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> >> +	}
> >> +
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +
> >> +	return 0;
> >> +
> >> +err:
> >> +	mutex_unlock(&otgd->fsm.lock);
> >> +	return -EINVAL;
> > 
> > Return non-zero, then if err, do we need call usb_otg_add_hcd() after
> > usb_otg_register_hcd() fails?
> 
> You should not call usb_otg_register_hcd() but usb_add_hcd().
> If that fails then you fail as ususal.

My point is if we use usb_add_hcd(), but failed in usb_otg_register_hcd(),
then usb_otg_add_hcd() will be called in *all* error case, is this your
expectation?
	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
		return usb_otg_add_hcd(hcd, irqnum, irqflags);

> >> + * @fsm_running: state machine running/stopped indicator
> >> + */
> >>  struct usb_otg {
> >>  	u8			default_a;
> >>  
> >>  	struct phy		*phy;
> >>  	/* old usb_phy interface */
> >>  	struct usb_phy		*usb_phy;
> >> +
> > 
> > add a blank line?
> > 

You missed this.

> >>  	struct usb_bus		*host;
> >>  	struct usb_gadget	*gadget;
> >>  
> >>  	enum usb_otg_state	state;
> >>  
> >> +	struct device *dev;
> >> +	struct usb_otg_caps *caps;
> >> +	struct otg_fsm fsm;
> >> +	struct otg_fsm_ops fsm_ops;
> >> +
> >> +	/* internal use only */
> >> +	struct otg_hcd primary_hcd;
> >> +	struct otg_hcd shared_hcd;
> >> +	struct otg_gadget_ops *gadget_ops;
> >> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
> >> +	struct list_head list;
> >> +	struct work_struct work;
> >> -- 
> >> 2.1.4


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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  9:08             ` Roger Quadros
@ 2015-09-09  8:13               ` Peter Chen
  2015-09-09  9:33                 ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-09  8:13 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
> On 09/09/15 05:21, Peter Chen wrote:
> > On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
> >>
> >>
> >> On 08/09/15 11:31, Peter Chen wrote:
> >>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >>>> On 07/09/15 04:23, Peter Chen wrote:
> >>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>>>> + * This is used by the USB Host stack to register the Host controller
> >>>>>> + * to the OTG core. Host controller must not be started by the
> >>>>>> + * caller as it is left upto the OTG state machine to do so.
> >>>>>> + *
> >>>>>> + * Returns: 0 on success, error value otherwise.
> >>>>>> + */
> >>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>>>> +{
> >>>>>> +	struct usb_otg *otgd;
> >>>>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>>>> +
> >>>>>
> >>>>> One big problem here is: there are two designs for current (IP) driver
> >>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>>>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>>>> in your patch), like chipidea and dwc2.
> >>>>>
> >>>>> Then, otg_dev will be glue layer device for chipidea after that.
> >>>>
> >>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >>>> information to the otg core for such devices like chipidea and dwc2.
> >>>>
> >>>
> >>> Roger, not only chipidea and dwc2, I think the musb uses the same
> >>> hierarchy. If the host, device, and otg share the same register
> >>> region, host part can't be a platform driver since we don't want
> >>> to remap the same register region again.
> >>>
> >>> So, in the design, we may need to consider both situations, one
> >>> is otg/host/device has its own register region, and host is a
> >>> separate platform device (A), the other is three parts share the
> >>> same register region, there is only one platform driver (B).
> >>>
> >>> A:
> >>>
> >>> 			IP core device 
> >>> 			    |
> >>> 			    |
> >>> 		      |-----|-----|
> >>> 		      gadget   host platform device	
> >>> 		      		|
> >>> 				roothub
> >>>
> >>> B:
> >>>
> >>> 			IP core device
> >>> 			    |
> >>> 			    |
> >>> 		      |-----|-----|
> >>> 		      gadget   	 roothub
> >>> 		      		
> >>>
> >>>> This API must be called before the hcd/gadget-driver is added so that the otg
> >>>> core knows it's linked to an OTG controller.
> >>>>
> >>>> Any better idea?
> >>>>
> >>>
> >>> A flag stands for this hcd controller is the same with otg controller
> >>> can be used, this flag can be stored at struct usb_otg_config.
> >>
> >> What if there is another architecture like so?
> >>
> >> C:
> >> 			[Parent]
> >> 			   |
> >> 			   |
> >> 		|------------------|--------------|
> >> 	[OTG core]		[gadget]	[host]
> >>
> >> We need a more flexible mechanism to link the gadget and
> >> host device to the otg core for non DT case.
> >>
> >> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> >>
> >> e.g.
> >> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> >>
> >> If otg is NULL it will try DT otg-controller property or parent to
> >> get the otg controller.
> > 
> > How usb_otg_register_hcd get struct usb_otg, from where?
> 
> This only works when the parent driver creating the hcd has registered the
> otg controller too.
> 

Sorry? So we need to find another way to solve this issue, right?

> > 
> >>
> >>>
> >>> Peter
> >>>
> >>> P.S: I still read your code, I find not all APIs in this file are used
> >>> in your dwc3 example. 
> >>
> >> Which ones? The ones for registering/unregistered host/gadget are used
> >> by hcd/udc core as part of usb_add/remove_hcd() and
> >> udc_bind_to_driver()/usb_gadget_remove_driver()
> >>
> > 
> > Ok, now I understand your design, usb_create_hcd must be called before
> > the fsm kicks off. The call flow like below:
> > 
> > usb_otg_register->usb_create_hcd->usb_add_hcd->usb_otg_register_hcd->
> > usb_otg_start_host->usb_otg_add_hcd
> 
> Actually these are the discrete steps
> - usb_otg_register
> - usb_create_hcd
> - usb_add_hcd->usb_otg_register_hcd  (HCD is not really added till FSM in host role)
> 
> Above 3 are prerequisite for FSM to start in addition to gadget controller and
> driver being ready.
> 
> When FSM enters in host role
> - usb_otg_start_host(true)->usb_otg_add_hcd (Now HCD is added)
> 
> When FSM exits host role
> - usb_otg_start_host(false)->usb_otg_remove_hcd (Now HCD is removed, but not unregistered)
> 
> If HCD hardware really goes away
> - usb_remove_hcd->usb_otg_unregister_hcd (Now FSM stops as host resource not available)
> 
> > 
> > We need to make some changes to let chipidea work since usb_create_hcd
> > is included at host->start.
> > 
> 
> Yes, you just need to do the usb_add_hcd() in probe
> and usb_otg_start_host() during role switch.
> 

Thanks.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  9:33                 ` Roger Quadros
@ 2015-09-09  8:45                   ` Peter Chen
  2015-09-09 10:21                     ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-09  8:45 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Wed, Sep 09, 2015 at 12:33:20PM +0300, Roger Quadros wrote:
> On 09/09/15 11:13, Peter Chen wrote:
> > On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
> >> On 09/09/15 05:21, Peter Chen wrote:
> >>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
> >>>>
> >>>>
> >>>> On 08/09/15 11:31, Peter Chen wrote:
> >>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >>>>>> On 07/09/15 04:23, Peter Chen wrote:
> >>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>>>>>> + * This is used by the USB Host stack to register the Host controller
> >>>>>>>> + * to the OTG core. Host controller must not be started by the
> >>>>>>>> + * caller as it is left upto the OTG state machine to do so.
> >>>>>>>> + *
> >>>>>>>> + * Returns: 0 on success, error value otherwise.
> >>>>>>>> + */
> >>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>>>>>> +{
> >>>>>>>> +	struct usb_otg *otgd;
> >>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>>>>>> +
> >>>>>>>
> >>>>>>> One big problem here is: there are two designs for current (IP) driver
> >>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>>>>>> in your patch), like chipidea and dwc2.
> >>>>>>>
> >>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
> >>>>>>
> >>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >>>>>> information to the otg core for such devices like chipidea and dwc2.
> >>>>>>
> >>>>>
> >>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
> >>>>> hierarchy. If the host, device, and otg share the same register
> >>>>> region, host part can't be a platform driver since we don't want
> >>>>> to remap the same register region again.
> >>>>>
> >>>>> So, in the design, we may need to consider both situations, one
> >>>>> is otg/host/device has its own register region, and host is a
> >>>>> separate platform device (A), the other is three parts share the
> >>>>> same register region, there is only one platform driver (B).
> >>>>>
> >>>>> A:
> >>>>>
> >>>>> 			IP core device 
> >>>>> 			    |
> >>>>> 			    |
> >>>>> 		      |-----|-----|
> >>>>> 		      gadget   host platform device	
> >>>>> 		      		|
> >>>>> 				roothub
> >>>>>
> >>>>> B:
> >>>>>
> >>>>> 			IP core device
> >>>>> 			    |
> >>>>> 			    |
> >>>>> 		      |-----|-----|
> >>>>> 		      gadget   	 roothub
> >>>>> 		      		
> >>>>>
> >>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
> >>>>>> core knows it's linked to an OTG controller.
> >>>>>>
> >>>>>> Any better idea?
> >>>>>>
> >>>>>
> >>>>> A flag stands for this hcd controller is the same with otg controller
> >>>>> can be used, this flag can be stored at struct usb_otg_config.
> >>>>
> >>>> What if there is another architecture like so?
> >>>>
> >>>> C:
> >>>> 			[Parent]
> >>>> 			   |
> >>>> 			   |
> >>>> 		|------------------|--------------|
> >>>> 	[OTG core]		[gadget]	[host]
> >>>>
> >>>> We need a more flexible mechanism to link the gadget and
> >>>> host device to the otg core for non DT case.
> >>>>
> >>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> >>>>
> >>>> e.g.
> >>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> >>>>
> >>>> If otg is NULL it will try DT otg-controller property or parent to
> >>>> get the otg controller.
> >>>
> >>> How usb_otg_register_hcd get struct usb_otg, from where?
> >>
> >> This only works when the parent driver creating the hcd has registered the
> >> otg controller too.
> >>
> > 
> > Sorry? So we need to find another way to solve this issue, right?
> 
> For existing cases this is sufficient.
> The otg device is either the one supplied during usb_otg_register_hcd
> (cases B and C) or it is the parent device (case A).

How we differentiate case A and case B at usb_otg_register_hcd?
Would you show me the sample code?

> 
> It does not work when the 3 devices are totally independent and get registered
> at different times.
> I don't think there is such a case for non-DT yet, but let's not have this
> limitation. So yes, we need to look for better solution :).
> 

Yes, we need to find some places to store gadget/host/otg information,
Alan's suggestion to save them at device drvdata may be a direction, but
I still doesn't have way to cover all cases.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  2:21           ` Peter Chen
@ 2015-09-09  9:08             ` Roger Quadros
  2015-09-09  8:13               ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-09  9:08 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 09/09/15 05:21, Peter Chen wrote:
> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
>>
>>
>> On 08/09/15 11:31, Peter Chen wrote:
>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>>>> On 07/09/15 04:23, Peter Chen wrote:
>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>>>> + * This is used by the USB Host stack to register the Host controller
>>>>>> + * to the OTG core. Host controller must not be started by the
>>>>>> + * caller as it is left upto the OTG state machine to do so.
>>>>>> + *
>>>>>> + * Returns: 0 on success, error value otherwise.
>>>>>> + */
>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>>>> +{
>>>>>> +	struct usb_otg *otgd;
>>>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>>>> +
>>>>>
>>>>> One big problem here is: there are two designs for current (IP) driver
>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>>>> in your patch), like chipidea and dwc2.
>>>>>
>>>>> Then, otg_dev will be glue layer device for chipidea after that.
>>>>
>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>>>> information to the otg core for such devices like chipidea and dwc2.
>>>>
>>>
>>> Roger, not only chipidea and dwc2, I think the musb uses the same
>>> hierarchy. If the host, device, and otg share the same register
>>> region, host part can't be a platform driver since we don't want
>>> to remap the same register region again.
>>>
>>> So, in the design, we may need to consider both situations, one
>>> is otg/host/device has its own register region, and host is a
>>> separate platform device (A), the other is three parts share the
>>> same register region, there is only one platform driver (B).
>>>
>>> A:
>>>
>>> 			IP core device 
>>> 			    |
>>> 			    |
>>> 		      |-----|-----|
>>> 		      gadget   host platform device	
>>> 		      		|
>>> 				roothub
>>>
>>> B:
>>>
>>> 			IP core device
>>> 			    |
>>> 			    |
>>> 		      |-----|-----|
>>> 		      gadget   	 roothub
>>> 		      		
>>>
>>>> This API must be called before the hcd/gadget-driver is added so that the otg
>>>> core knows it's linked to an OTG controller.
>>>>
>>>> Any better idea?
>>>>
>>>
>>> A flag stands for this hcd controller is the same with otg controller
>>> can be used, this flag can be stored at struct usb_otg_config.
>>
>> What if there is another architecture like so?
>>
>> C:
>> 			[Parent]
>> 			   |
>> 			   |
>> 		|------------------|--------------|
>> 	[OTG core]		[gadget]	[host]
>>
>> We need a more flexible mechanism to link the gadget and
>> host device to the otg core for non DT case.
>>
>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
>>
>> e.g.
>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
>>
>> If otg is NULL it will try DT otg-controller property or parent to
>> get the otg controller.
> 
> How usb_otg_register_hcd get struct usb_otg, from where?

This only works when the parent driver creating the hcd has registered the
otg controller too.

> 
>>
>>>
>>> Peter
>>>
>>> P.S: I still read your code, I find not all APIs in this file are used
>>> in your dwc3 example. 
>>
>> Which ones? The ones for registering/unregistered host/gadget are used
>> by hcd/udc core as part of usb_add/remove_hcd() and
>> udc_bind_to_driver()/usb_gadget_remove_driver()
>>
> 
> Ok, now I understand your design, usb_create_hcd must be called before
> the fsm kicks off. The call flow like below:
> 
> usb_otg_register->usb_create_hcd->usb_add_hcd->usb_otg_register_hcd->
> usb_otg_start_host->usb_otg_add_hcd

Actually these are the discrete steps
- usb_otg_register
- usb_create_hcd
- usb_add_hcd->usb_otg_register_hcd  (HCD is not really added till FSM in host role)

Above 3 are prerequisite for FSM to start in addition to gadget controller and
driver being ready.

When FSM enters in host role
- usb_otg_start_host(true)->usb_otg_add_hcd (Now HCD is added)

When FSM exits host role
- usb_otg_start_host(false)->usb_otg_remove_hcd (Now HCD is removed, but not unregistered)

If HCD hardware really goes away
- usb_remove_hcd->usb_otg_unregister_hcd (Now FSM stops as host resource not available)

> 
> We need to make some changes to let chipidea work since usb_create_hcd
> is included at host->start.
> 

Yes, you just need to do the usb_add_hcd() in probe
and usb_otg_start_host() during role switch.

cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  8:13               ` Peter Chen
@ 2015-09-09  9:33                 ` Roger Quadros
  2015-09-09  8:45                   ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-09  9:33 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 09/09/15 11:13, Peter Chen wrote:
> On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
>> On 09/09/15 05:21, Peter Chen wrote:
>>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
>>>>
>>>>
>>>> On 08/09/15 11:31, Peter Chen wrote:
>>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>>>>>> On 07/09/15 04:23, Peter Chen wrote:
>>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>>>>>> + * This is used by the USB Host stack to register the Host controller
>>>>>>>> + * to the OTG core. Host controller must not be started by the
>>>>>>>> + * caller as it is left upto the OTG state machine to do so.
>>>>>>>> + *
>>>>>>>> + * Returns: 0 on success, error value otherwise.
>>>>>>>> + */
>>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>>>>>> +{
>>>>>>>> +	struct usb_otg *otgd;
>>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>>>>>> +
>>>>>>>
>>>>>>> One big problem here is: there are two designs for current (IP) driver
>>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>>>>>> in your patch), like chipidea and dwc2.
>>>>>>>
>>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
>>>>>>
>>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>>>>>> information to the otg core for such devices like chipidea and dwc2.
>>>>>>
>>>>>
>>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
>>>>> hierarchy. If the host, device, and otg share the same register
>>>>> region, host part can't be a platform driver since we don't want
>>>>> to remap the same register region again.
>>>>>
>>>>> So, in the design, we may need to consider both situations, one
>>>>> is otg/host/device has its own register region, and host is a
>>>>> separate platform device (A), the other is three parts share the
>>>>> same register region, there is only one platform driver (B).
>>>>>
>>>>> A:
>>>>>
>>>>> 			IP core device 
>>>>> 			    |
>>>>> 			    |
>>>>> 		      |-----|-----|
>>>>> 		      gadget   host platform device	
>>>>> 		      		|
>>>>> 				roothub
>>>>>
>>>>> B:
>>>>>
>>>>> 			IP core device
>>>>> 			    |
>>>>> 			    |
>>>>> 		      |-----|-----|
>>>>> 		      gadget   	 roothub
>>>>> 		      		
>>>>>
>>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
>>>>>> core knows it's linked to an OTG controller.
>>>>>>
>>>>>> Any better idea?
>>>>>>
>>>>>
>>>>> A flag stands for this hcd controller is the same with otg controller
>>>>> can be used, this flag can be stored at struct usb_otg_config.
>>>>
>>>> What if there is another architecture like so?
>>>>
>>>> C:
>>>> 			[Parent]
>>>> 			   |
>>>> 			   |
>>>> 		|------------------|--------------|
>>>> 	[OTG core]		[gadget]	[host]
>>>>
>>>> We need a more flexible mechanism to link the gadget and
>>>> host device to the otg core for non DT case.
>>>>
>>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
>>>>
>>>> e.g.
>>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
>>>>
>>>> If otg is NULL it will try DT otg-controller property or parent to
>>>> get the otg controller.
>>>
>>> How usb_otg_register_hcd get struct usb_otg, from where?
>>
>> This only works when the parent driver creating the hcd has registered the
>> otg controller too.
>>
> 
> Sorry? So we need to find another way to solve this issue, right?

For existing cases this is sufficient.
The otg device is either the one supplied during usb_otg_register_hcd
(cases B and C) or it is the parent device (case A).

It does not work when the 3 devices are totally independent and get registered
at different times.
I don't think there is such a case for non-DT yet, but let's not have this
limitation. So yes, we need to look for better solution :).

--
cheers,
-roger

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

* Re: [PATCH v4 10/13] usb: hcd: Adapt to OTG core
  2015-09-09  2:23   ` Peter Chen
@ 2015-09-09  9:39     ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-09  9:39 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 09/09/15 05:23, Peter Chen wrote:
> On Mon, Aug 24, 2015 at 04:21:21PM +0300, Roger Quadros wrote:
>> The existing usb_add/remove_hcd() functionality
>> remains unchanged for non-OTG devices. For OTG
>> devices they only register the HCD with the OTG core.
>>
>> Introduce usb_otg_add/remove_hcd() for use by OTG core.
>> These functions actually add/remove the HCD.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/usb/core/hcd.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-----
>>  1 file changed, 50 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
>> index c0fd1f6..4851682 100644
>> --- a/drivers/usb/core/hcd.c
>> +++ b/drivers/usb/core/hcd.c
>> @@ -46,6 +46,7 @@
>>  #include <linux/usb.h>
>>  #include <linux/usb/hcd.h>
>>  #include <linux/usb/phy.h>
>> +#include <linux/usb/otg.h>
>>  
>>  #include "usb.h"
>>  
>> @@ -2625,8 +2626,8 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
>>   * buffers of consistent memory, register the bus, request the IRQ line,
>>   * and call the driver's reset() and start() routines.
>>   */
>> -int usb_add_hcd(struct usb_hcd *hcd,
>> -		unsigned int irqnum, unsigned long irqflags)
>> +static int usb_otg_add_hcd(struct usb_hcd *hcd,
>> +			   unsigned int irqnum, unsigned long irqflags)
> 
> You may change the kernel doc to this name too.

Yes.

> 
>>  {
>>  	int retval;
>>  	struct usb_device *rhdev;
>> @@ -2839,17 +2840,16 @@ err_phy:
>>  	}
>>  	return retval;
>>  }
>> -EXPORT_SYMBOL_GPL(usb_add_hcd);
>>  
>>  /**
>> - * usb_remove_hcd - shutdown processing for generic HCDs
>> + * usb_otg_remove_hcd - shutdown processing for generic HCDs
>>   * @hcd: the usb_hcd structure to remove
>>   * Context: !in_interrupt()
>>   *
>>   * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
>>   * invoking the HCD's stop() method.
>>   */
>> -void usb_remove_hcd(struct usb_hcd *hcd)
>> +static void usb_otg_remove_hcd(struct usb_hcd *hcd)
>>  {
>>  	struct usb_device *rhdev = hcd->self.root_hub;
>>  
>> @@ -2923,6 +2923,51 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>>  
>>  	usb_put_invalidate_rhdev(hcd);
>>  }
>> +
>> +static struct otg_hcd_ops otg_hcd_intf = {
>> +	.add = usb_otg_add_hcd,
>> +	.remove = usb_otg_remove_hcd,
>> +};
>> +
>> +/**
>> + * usb_add_hcd - finish generic HCD structure initialization and register
>> + * @hcd: the usb_hcd structure to initialize
>> + * @irqnum: Interrupt line to allocate
>> + * @irqflags: Interrupt type flags
>> + *
>> + * Finish the remaining parts of generic HCD initialization: allocate the
>> + * buffers of consistent memory, register the bus, request the IRQ line,
>> + * and call the driver's reset() and start() routines.
>> + * If it is an OTG device then it only registers the HCD with OTG core.
>> + *
>> + */
>> +int usb_add_hcd(struct usb_hcd *hcd,
>> +		unsigned int irqnum, unsigned long irqflags)
>> +{
>> +	/* If OTG device, OTG core takes care of adding HCD */
>> +	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
>> +		return usb_otg_add_hcd(hcd, irqnum, irqflags);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_add_hcd);
>> +
>> +/**
>> + * usb_remove_hcd - shutdown processing for generic HCDs
>> + * @hcd: the usb_hcd structure to remove
>> + * Context: !in_interrupt()
>> + *
>> + * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
>> + * invoking the HCD's stop() method.
>> + * If it is an OTG device then it unregisters the HCD from OTG core
>> + * as well.
>> + */
>> +void usb_remove_hcd(struct usb_hcd *hcd)
>> +{
>> +	/* If OTG device, OTG core takes care of stopping HCD */
>> +	if (usb_otg_unregister_hcd(hcd))
>> +		usb_otg_remove_hcd(hcd);
>> +}
>>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>>  
>>  void
>> -- 
>> 2.1.4
>>
> 
--
cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  6:20       ` Li Jun
@ 2015-09-09 10:01         ` Roger Quadros
  2015-09-10  9:28           ` Li Jun
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-09 10:01 UTC (permalink / raw)
  To: Li Jun
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On 09/09/15 09:20, Li Jun wrote:
> On Mon, Sep 07, 2015 at 01:53:19PM +0300, Roger Quadros wrote:
>> On 07/09/15 10:40, Li Jun wrote:
>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>> The OTG core instantiates the OTG Finite State Machine
>>>> per OTG controller and manages starting/stopping the
>>>> host and gadget controllers based on the bus state.
>>>>
>>>> It provides APIs for the following tasks
>>>>
>>>> - Registering an OTG capable controller
>>>> - Registering Host and Gadget controllers to OTG core
>>>> - Providing inputs to and kicking the OTG state machine
>>>>
>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>> ---
>>>>  MAINTAINERS                  |    4 +-
>>>>  drivers/usb/Kconfig          |    2 +-
>>>>  drivers/usb/Makefile         |    1 +
>>>>  drivers/usb/common/Makefile  |    3 +-
>>>>  drivers/usb/common/usb-otg.c | 1061 ++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/usb/common/usb-otg.h |   71 +++
>>>>  drivers/usb/core/Kconfig     |   11 +-
>>>>  include/linux/usb/otg.h      |  189 +++++++-
>>>>  8 files changed, 1321 insertions(+), 21 deletions(-)
>>>>  create mode 100644 drivers/usb/common/usb-otg.c
>>>>  create mode 100644 drivers/usb/common/usb-otg.h
>>>>
>>>
>>> ... ...
>>>
>>>> +
>>>> +/**
>>>> + * Get OTG device from host or gadget device.
>>>> + *
>>>> + * For non device tree boot, the OTG controller is assumed to be
>>>> + * the parent of the host/gadget device.
>>>
>>> This assumption/restriction maybe a problem, as I pointed in your previous
>>> version, usb_create_hcd() use the passed dev as its dev, but,
>>> usb_add_gadget_udc() use the passed dev as its parent dev, so often the
>>> host and gadget don't share the same parent device, at least it doesn't
>>> apply to chipidea case.
>>
>> Let's provide a way for OTG driver to provide the OTG core exactly which is
>> the related host/gadget device.
>>
>>>
>>>> + * For device tree boot, the OTG controller is derived from the
>>>> + * "otg-controller" property.
>>>> + */
>>>> +static struct device *usb_otg_get_device(struct device *hcd_gcd_dev)
>>>> +{
>>>> +	struct device *otg_dev;
>>>> +
>>>> +	if (!hcd_gcd_dev)
>>>> +		return NULL;
>>>> +
>>>> +	if (hcd_gcd_dev->of_node) {
>>>> +		struct device_node *np;
>>>> +		struct platform_device *pdev;
>>>> +
>>>> +		np = of_parse_phandle(hcd_gcd_dev->of_node, "otg-controller",
>>>> +				      0);
>>>> +		if (!np)
>>>> +			goto legacy;	/* continue legacy way */
>>>> +
>>>> +		pdev = of_find_device_by_node(np);
>>>> +		of_node_put(np);
>>>> +		if (!pdev) {
>>>> +			dev_err(&pdev->dev, "couldn't get otg-controller device\n");
>>>> +			return NULL;
>>>> +		}
>>>> +
>>>> +		otg_dev = &pdev->dev;
>>>> +		return otg_dev;
>>>> +	}
>>>> +
>>>> +legacy:
>>>> +	/* otg device is parent and must be registered */
>>>> +	otg_dev = hcd_gcd_dev->parent;
>>>> +	if (!usb_otg_get_data(otg_dev))
>>>> +		return NULL;
>>>> +
>>>> +	return otg_dev;
>>>> +}
>>>> +
>>>
>>> ... ...
>>>
>>>> +static void usb_otg_init_timers(struct usb_otg *otgd, unsigned *timeouts)
>>>> +{
>>>> +	struct otg_fsm *fsm = &otgd->fsm;
>>>> +	unsigned long tmouts[NUM_OTG_FSM_TIMERS];
>>>> +	int i;
>>>> +
>>>> +	/* set default timeouts */
>>>> +	tmouts[A_WAIT_VRISE] = TA_WAIT_VRISE;
>>>> +	tmouts[A_WAIT_VFALL] = TA_WAIT_VFALL;
>>>> +	tmouts[A_WAIT_BCON] = TA_WAIT_BCON;
>>>> +	tmouts[A_AIDL_BDIS] = TA_AIDL_BDIS;
>>>> +	tmouts[A_BIDL_ADIS] = TA_BIDL_ADIS;
>>>> +	tmouts[B_ASE0_BRST] = TB_ASE0_BRST;
>>>> +	tmouts[B_SE0_SRP] = TB_SE0_SRP;
>>>> +	tmouts[B_SRP_FAIL] = TB_SRP_FAIL;
>>>> +
>>>> +	/* set controller provided timeouts */
>>>> +	if (timeouts) {
>>>> +		for (i = 0; i < NUM_OTG_FSM_TIMERS; i++) {
>>>> +			if (timeouts[i])
>>>> +				tmouts[i] = timeouts[i];
>>>> +		}
>>>> +	}
>>>> +
>>>> +	otg_timer_init(A_WAIT_VRISE, otgd, set_tmout, TA_WAIT_VRISE,
>>>> +		       &fsm->a_wait_vrise_tmout);
>>>> +	otg_timer_init(A_WAIT_VFALL, otgd, set_tmout, TA_WAIT_VFALL,
>>>> +		       &fsm->a_wait_vfall_tmout);
>>>> +	otg_timer_init(A_WAIT_BCON, otgd, set_tmout, TA_WAIT_BCON,
>>>> +		       &fsm->a_wait_bcon_tmout);
>>>> +	otg_timer_init(A_AIDL_BDIS, otgd, set_tmout, TA_AIDL_BDIS,
>>>> +		       &fsm->a_aidl_bdis_tmout);
>>>> +	otg_timer_init(A_BIDL_ADIS, otgd, set_tmout, TA_BIDL_ADIS,
>>>> +		       &fsm->a_bidl_adis_tmout);
>>>> +	otg_timer_init(B_ASE0_BRST, otgd, set_tmout, TB_ASE0_BRST,
>>>> +		       &fsm->b_ase0_brst_tmout);
>>>> +
>>>> +	otg_timer_init(B_SE0_SRP, otgd, set_tmout, TB_SE0_SRP,
>>>> +		       &fsm->b_se0_srp);
>>>> +	otg_timer_init(B_SRP_FAIL, otgd, set_tmout, TB_SRP_FAIL,
>>>> +		       &fsm->b_srp_done);
>>>> +
>>>> +	/* FIXME: what about A_WAIT_ENUM? */
>>>
>>> Either you init it as other timers, or you remove all of it, otherwise
>>> there will be NULL pointer crash.
>>
>> I want to initialize it but was not sure about the timeout value.
>> What timeout value I must use?
>>
> 
> It's not defined in OTG spec, I don't know either.
> or you filter it out when add/del timer in below 2 functions.
> 	if (id == A_WAIT_ENUM)
> 		return;
> 

Looks like it is used for some workaround. See phy-fsl-usb.c line 269

/*
 * Workaround for a_host suspending too fast.  When a_bus_req=0,
 * a_host will start by SRP.  It needs to set b_hnp_enable before
 * actually suspending to start HNP
 */
void a_wait_enum(unsigned long foo)
{
        VDBG("a_wait_enum timeout\n");
        if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
                fsl_otg_add_timer(&fsl_otg_dev->fsm, a_wait_enum_tmr);
        else
                otg_statemachine(&fsl_otg_dev->fsm);
}

I'll filter it out for now as per your suggestion. We can look back
into it if we face issues as mentioned in the workaround.

>>>
>>>> +}
>>>> +
>>>> +/**
>>>> + * OTG FSM ops function to add timer
>>>> + */
>>>> +static void usb_otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
>>>> +{
>>>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>>>> +	struct otg_timer *otgtimer = &otgd->timers[id];
>>>> +	struct hrtimer *timer = &otgtimer->timer;
>>>> +
>>>> +	if (!otgd->fsm_running)
>>>> +		return;
>>>> +
>>>> +	/* if timer is already active, exit */
>>>> +	if (hrtimer_active(timer)) {
>>>> +		dev_err(otgd->dev, "otg: timer %d is already running\n", id);
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	hrtimer_start(timer, otgtimer->timeout, HRTIMER_MODE_REL);
>>>> +}
>>>> +
>>>> +/**
>>>> + * OTG FSM ops function to delete timer
>>>> + */
>>>> +static void usb_otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer id)
>>>> +{
>>>> +	struct usb_otg *otgd = container_of(fsm, struct usb_otg, fsm);
>>>> +	struct hrtimer *timer = &otgd->timers[id].timer;
>>>> +
>>>> +	hrtimer_cancel(timer);
>>>> +}
>>>> +
> 
> ... ...
> 
>>>> +	}
>>>> +
>>>> +	otgd->dev = dev;
>>>> +	otgd->caps = &config->otg_caps;
>>>
>>> How about define otgd->caps as a pointer, then don't need copy it.
>>
>> otgd->caps is a pointer.
>>
> 
> okay, you are right.
> 
>>>
>>>> +	INIT_WORK(&otgd->work, usb_otg_work);
>>>> +	otgd->wq = create_singlethread_workqueue("usb_otg");
>>>> +	if (!otgd->wq) {
>>>> +		dev_err(dev, "otg: %s: can't create workqueue\n",
>>>> +			__func__);
>>>> +		ret = -ENOMEM;
>>>> +		goto err_wq;
>>>> +	}
>>>> +
>>>> +	usb_otg_init_timers(otgd, config->otg_timeouts);
>>>> +
>>>> +	/* create copy of original ops */
>>>> +	otgd->fsm_ops = *config->fsm_ops;
>>>
>>> The same, use a pointer is enough?
>>
>> We are creating a copy because we are overriding timer ops.
>>
> 
> okay.
> 
>>>
>>>> +	/* FIXME: we ignore caller's timer ops */
>>>> +	otgd->fsm_ops.add_timer = usb_otg_add_timer;
>>>> +	otgd->fsm_ops.del_timer = usb_otg_del_timer;
>>>> +	/* set otg ops */
>>>> +	otgd->fsm.ops = &otgd->fsm_ops;
>>>> +	otgd->fsm.otg = otgd;
>>>> + *
> 
> ... ...
> 
>>>> + * This is used by the USB Host stack to register the Host controller
>>>> + * to the OTG core. Host controller must not be started by the
>>>> + * caller as it is left upto the OTG state machine to do so.
>>>
>>> I am confused on how to use this function.
>>> - This function should be called before start fsm per usb_otg_start_fsm().
>>
>> yes.
>>
>>> - Called by usb_add_hcd(), so we need call usb_add_hcd() before start fsm.
>>
>> yes.
>>
>>> - If I want to add hcd when switch to host role, and remove hcd when switch
>>>   to peripheral, with this design, I cannot use this function?
>>
>> You add hcd only once during the life of the OTG device. If it is linked to the
>> OTG controller the OTG fsm manages the start/stop of hcd using the otg_hcd_ops.
>>
>> "usb/core/hcd.c"
>> static struct otg_hcd_ops otg_hcd_intf = {
>>         .add = usb_otg_add_hcd,
>>         .remove = usb_otg_remove_hcd,
>> };
>>
>> Your otg driver must use teh usb_otg_add/remove_hcd to start/stop the controller.
>> Using usb_remove_hcd() means the hcd resource is no longer available and the
>> otg fsm will be stopped.
>>
>>> - How about split it out of usb_add_hcd()?
>>
>> Adding the HCD and starting/stopping the hcd is split into
>> usb_add/remove_hcd() and usb_otg_add/remove_hcd() for OTG case.
>>
> 
> Catch your point now.
> Do usb_add_hcd to register hcd before start fsm, and use usb_otg_start_host()
> to start/stop host role for otg fsm.
> 
correct :).

>>>
>>>> + *
>>>> + * Returns: 0 on success, error value otherwise.
>>>> + */
>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>> +{
>>>> +	struct usb_otg *otgd;
>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>> +
>>>> +	if (!otg_dev)
>>>> +		return -EINVAL;	/* we're definitely not OTG */
>>>> +
>>>> +	/* we're otg but otg controller might not yet be registered */
>>>> +	mutex_lock(&otg_list_mutex);
>>>> +	otgd = usb_otg_get_data(otg_dev);
>>>> +	mutex_unlock(&otg_list_mutex);
>>>> +	if (!otgd) {
>>>> +		dev_dbg(hcd_dev,
>>>> +			"otg: controller not yet registered. waiting..\n");
>>>> +		/*
>>>> +		 * otg controller might register later. Put the hcd in
>>>> +		 * wait list and call us back when ready
>>>> +		 */
>>>> +		if (usb_otg_hcd_wait_add(otg_dev, hcd, irqnum, irqflags, ops)) {
>>>> +			dev_dbg(hcd_dev, "otg: failed to add to wait list\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	/* HCD will be started by OTG fsm when needed */
>>>> +	mutex_lock(&otgd->fsm.lock);
>>>
>>> If call usb_add_hcd() when start host role, deadlock.
>>
>> No. You must call usb_otg_add_hcd() to start host role.
>>
>>>
>>>> +	if (otgd->primary_hcd.hcd) {
>>>> +		/* probably a shared HCD ? */
>>>> +		if (usb_otg_hcd_is_primary_hcd(hcd)) {
>>>> +			dev_err(otg_dev, "otg: primary host already registered\n");
>>>> +			goto err;
>>>> +		}
>>>> +
>>>> +		if (hcd->shared_hcd == otgd->primary_hcd.hcd) {
>>>> +			if (otgd->shared_hcd.hcd) {
>>>> +				dev_err(otg_dev, "otg: shared host already registered\n");
>>>> +				goto err;
>>>> +			}
>>>> +
>>>> +			otgd->shared_hcd.hcd = hcd;
>>>> +			otgd->shared_hcd.irqnum = irqnum;
>>>> +			otgd->shared_hcd.irqflags = irqflags;
>>>> +			otgd->shared_hcd.ops = ops;
>>>> +			dev_info(otg_dev, "otg: shared host %s registered\n",
>>>> +				 dev_name(hcd->self.controller));
>>>> +		} else {
>>>> +			dev_err(otg_dev, "otg: invalid shared host %s\n",
>>>> +				dev_name(hcd->self.controller));
>>>> +			goto err;
>>>> +		}
>>>> +	} else {
>>>> +		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
>>>> +			dev_err(otg_dev, "otg: primary host must be registered first\n");
>>>> +			goto err;
>>>> +		}
>>>> +
>>>> +		otgd->primary_hcd.hcd = hcd;
>>>> +		otgd->primary_hcd.irqnum = irqnum;
>>>> +		otgd->primary_hcd.irqflags = irqflags;
>>>> +		otgd->primary_hcd.ops = ops;
>>>> +		dev_info(otg_dev, "otg: primary host %s registered\n",
>>>> +			 dev_name(hcd->self.controller));
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * we're ready only if we have shared HCD
>>>> +	 * or we don't need shared HCD.
>>>> +	 */
>>>> +	if (otgd->shared_hcd.hcd || !otgd->primary_hcd.hcd->shared_hcd) {
>>>> +		otgd->fsm.otg->host = hcd_to_bus(hcd);
>>>
>>> otgd->host = hcd_to_bus(hcd);
>>
>> ok. So we set host at both places. struct usb_otg in struct otg_fsm starts to
>> feel redundant now. I think we should get rid of it and get the usb_otg struct
>> using container_of() instead.
>>
> 
> Then you may come to force existing otg fsm code to use your OTG core.

Let's leave it around then.

> 
>>>
>>>> +		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
>>>> +
>>>> +		/* start FSM */
>>>> +		usb_otg_start_fsm(&otgd->fsm);
>>>> +	} else {
>>>> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
>>>> +	}
>>>> +
>>>> +	mutex_unlock(&otgd->fsm.lock);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +err:
>>>> +	mutex_unlock(&otgd->fsm.lock);
>>>> +	return -EINVAL;
>>>
>>> Return non-zero, then if err, do we need call usb_otg_add_hcd() after
>>> usb_otg_register_hcd() fails?
>>
>> You should not call usb_otg_register_hcd() but usb_add_hcd().
>> If that fails then you fail as ususal.
> 
> My point is if we use usb_add_hcd(), but failed in usb_otg_register_hcd(),
> then usb_otg_add_hcd() will be called in *all* error case, is this your
> expectation?
> 	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
> 		return usb_otg_add_hcd(hcd, irqnum, irqflags);
> 

Yes, my intention was that if otg fails then it is a non otg HCD so register normally.
Let me correct my previous statement. If you are absolutely sure
that the HCD is for otg/dual-role usage then you should call usb_otg_register_hcd().

>>>> + * @fsm_running: state machine running/stopped indicator
>>>> + */
>>>>  struct usb_otg {
>>>>  	u8			default_a;
>>>>  
>>>>  	struct phy		*phy;
>>>>  	/* old usb_phy interface */
>>>>  	struct usb_phy		*usb_phy;
>>>> +
>>>
>>> add a blank line?
>>>
> 
> You missed this.

Sorry. Did you suggest to remove that blank line
or add a new one before usb_phy?

> 
>>>>  	struct usb_bus		*host;
>>>>  	struct usb_gadget	*gadget;
>>>>  
>>>>  	enum usb_otg_state	state;
>>>>  
>>>> +	struct device *dev;
>>>> +	struct usb_otg_caps *caps;
>>>> +	struct otg_fsm fsm;
>>>> +	struct otg_fsm_ops fsm_ops;
>>>> +
>>>> +	/* internal use only */
>>>> +	struct otg_hcd primary_hcd;
>>>> +	struct otg_hcd shared_hcd;
>>>> +	struct otg_gadget_ops *gadget_ops;
>>>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
>>>> +	struct list_head list;
>>>> +	struct work_struct work;
>>>> -- 
>>>> 2.1.4
> 

--
cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09  8:45                   ` Peter Chen
@ 2015-09-09 10:21                     ` Roger Quadros
  2015-09-10  5:35                       ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-09 10:21 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 09/09/15 11:45, Peter Chen wrote:
> On Wed, Sep 09, 2015 at 12:33:20PM +0300, Roger Quadros wrote:
>> On 09/09/15 11:13, Peter Chen wrote:
>>> On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
>>>> On 09/09/15 05:21, Peter Chen wrote:
>>>>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
>>>>>>
>>>>>>
>>>>>> On 08/09/15 11:31, Peter Chen wrote:
>>>>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>>>>>>>> On 07/09/15 04:23, Peter Chen wrote:
>>>>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>>>>>>>> + * This is used by the USB Host stack to register the Host controller
>>>>>>>>>> + * to the OTG core. Host controller must not be started by the
>>>>>>>>>> + * caller as it is left upto the OTG state machine to do so.
>>>>>>>>>> + *
>>>>>>>>>> + * Returns: 0 on success, error value otherwise.
>>>>>>>>>> + */
>>>>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>>>>>>>> +{
>>>>>>>>>> +	struct usb_otg *otgd;
>>>>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>>>>>>>> +
>>>>>>>>>
>>>>>>>>> One big problem here is: there are two designs for current (IP) driver
>>>>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>>>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>>>>>>>> in your patch), like chipidea and dwc2.
>>>>>>>>>
>>>>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
>>>>>>>>
>>>>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>>>>>>>> information to the otg core for such devices like chipidea and dwc2.
>>>>>>>>
>>>>>>>
>>>>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
>>>>>>> hierarchy. If the host, device, and otg share the same register
>>>>>>> region, host part can't be a platform driver since we don't want
>>>>>>> to remap the same register region again.
>>>>>>>
>>>>>>> So, in the design, we may need to consider both situations, one
>>>>>>> is otg/host/device has its own register region, and host is a
>>>>>>> separate platform device (A), the other is three parts share the
>>>>>>> same register region, there is only one platform driver (B).
>>>>>>>
>>>>>>> A:
>>>>>>>
>>>>>>> 			IP core device 
>>>>>>> 			    |
>>>>>>> 			    |
>>>>>>> 		      |-----|-----|
>>>>>>> 		      gadget   host platform device	
>>>>>>> 		      		|
>>>>>>> 				roothub
>>>>>>>
>>>>>>> B:
>>>>>>>
>>>>>>> 			IP core device
>>>>>>> 			    |
>>>>>>> 			    |
>>>>>>> 		      |-----|-----|
>>>>>>> 		      gadget   	 roothub
>>>>>>> 		      		
>>>>>>>
>>>>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
>>>>>>>> core knows it's linked to an OTG controller.
>>>>>>>>
>>>>>>>> Any better idea?
>>>>>>>>
>>>>>>>
>>>>>>> A flag stands for this hcd controller is the same with otg controller
>>>>>>> can be used, this flag can be stored at struct usb_otg_config.
>>>>>>
>>>>>> What if there is another architecture like so?
>>>>>>
>>>>>> C:
>>>>>> 			[Parent]
>>>>>> 			   |
>>>>>> 			   |
>>>>>> 		|------------------|--------------|
>>>>>> 	[OTG core]		[gadget]	[host]
>>>>>>
>>>>>> We need a more flexible mechanism to link the gadget and
>>>>>> host device to the otg core for non DT case.
>>>>>>
>>>>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
>>>>>>
>>>>>> e.g.
>>>>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
>>>>>>
>>>>>> If otg is NULL it will try DT otg-controller property or parent to
>>>>>> get the otg controller.
>>>>>
>>>>> How usb_otg_register_hcd get struct usb_otg, from where?
>>>>
>>>> This only works when the parent driver creating the hcd has registered the
>>>> otg controller too.
>>>>
>>>
>>> Sorry? So we need to find another way to solve this issue, right?
>>
>> For existing cases this is sufficient.
>> The otg device is either the one supplied during usb_otg_register_hcd
>> (cases B and C) or it is the parent device (case A).
> 
> How we differentiate case A and case B at usb_otg_register_hcd?
> Would you show me the sample code?

Case A:

hcd platform driver doesn't know about otg device so it calls

	usb_add_hcd(hcd,..)->usb_otg_register_hcd(NULL, hcd,..);

Case B:

core driver knows about both otg and hcd so it calls
	usb_otg_register_hcd(otg, hcd,...);

code:

usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ...)
{
	if (!otg) {
		struct device *otg_dev;
		struct device *hcd_dev = hcd->self.controller;

		/* first get otg device */
		if (hcd_dev->of_node) { /* DT */
			struct device_node *np;
			struct platform_device *pdev;

			/* get otg from otg-controller property */
			np = of_parse_phandle(hcd_dev->of_node, "otg-controller",
					      0);
			pdev = of_find_device_by_node(np);
			of_node_put(np);
			if (!pdev) {
				dev_err(&pdev->dev, "couldn't get otg-controller device\n");
				return -EINVAL;
			}

			otg_dev = &pdev->dev;
		} else {
			/* Assume otg dev is parent */
			otg_dev = hcd_dev->parent;
		}

		otg = usb_otg_get_data(otg_dev);
		if (!otg) {
			/* otg controller not registered */
			return -EVINVAL
		}
	} else {
		/* use otg as is */
	}
}

usb_otg_get_data() returns the usb_otg structure if it finds a matching
otg_dev in the otg_dev list.

For this to work otg controller _must_ register before hcd/gadget.

> 
>>
>> It does not work when the 3 devices are totally independent and get registered
>> at different times.
>> I don't think there is such a case for non-DT yet, but let's not have this
>> limitation. So yes, we need to look for better solution :).
>>
> 
> Yes, we need to find some places to store gadget/host/otg information,
> Alan's suggestion to save them at device drvdata may be a direction, but
> I still doesn't have way to cover all cases.
> 

Yes, let's discuss more in that direction.

--
cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09 10:21                     ` Roger Quadros
@ 2015-09-10  5:35                       ` Peter Chen
  2015-09-10 14:17                         ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-09-10  5:35 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Wed, Sep 09, 2015 at 01:21:50PM +0300, Roger Quadros wrote:
> On 09/09/15 11:45, Peter Chen wrote:
> > On Wed, Sep 09, 2015 at 12:33:20PM +0300, Roger Quadros wrote:
> >> On 09/09/15 11:13, Peter Chen wrote:
> >>> On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
> >>>> On 09/09/15 05:21, Peter Chen wrote:
> >>>>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
> >>>>>>
> >>>>>>
> >>>>>> On 08/09/15 11:31, Peter Chen wrote:
> >>>>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >>>>>>>> On 07/09/15 04:23, Peter Chen wrote:
> >>>>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>>>>>>>> + * This is used by the USB Host stack to register the Host controller
> >>>>>>>>>> + * to the OTG core. Host controller must not be started by the
> >>>>>>>>>> + * caller as it is left upto the OTG state machine to do so.
> >>>>>>>>>> + *
> >>>>>>>>>> + * Returns: 0 on success, error value otherwise.
> >>>>>>>>>> + */
> >>>>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>>>>>>>> +{
> >>>>>>>>>> +	struct usb_otg *otgd;
> >>>>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>>>>>>>> +
> >>>>>>>>>
> >>>>>>>>> One big problem here is: there are two designs for current (IP) driver
> >>>>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>>>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>>>>>>>> in your patch), like chipidea and dwc2.
> >>>>>>>>>
> >>>>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
> >>>>>>>>
> >>>>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >>>>>>>> information to the otg core for such devices like chipidea and dwc2.
> >>>>>>>>
> >>>>>>>
> >>>>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
> >>>>>>> hierarchy. If the host, device, and otg share the same register
> >>>>>>> region, host part can't be a platform driver since we don't want
> >>>>>>> to remap the same register region again.
> >>>>>>>
> >>>>>>> So, in the design, we may need to consider both situations, one
> >>>>>>> is otg/host/device has its own register region, and host is a
> >>>>>>> separate platform device (A), the other is three parts share the
> >>>>>>> same register region, there is only one platform driver (B).
> >>>>>>>
> >>>>>>> A:
> >>>>>>>
> >>>>>>> 			IP core device 
> >>>>>>> 			    |
> >>>>>>> 			    |
> >>>>>>> 		      |-----|-----|
> >>>>>>> 		      gadget   host platform device	
> >>>>>>> 		      		|
> >>>>>>> 				roothub
> >>>>>>>
> >>>>>>> B:
> >>>>>>>
> >>>>>>> 			IP core device
> >>>>>>> 			    |
> >>>>>>> 			    |
> >>>>>>> 		      |-----|-----|
> >>>>>>> 		      gadget   	 roothub
> >>>>>>> 		      		
> >>>>>>>
> >>>>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
> >>>>>>>> core knows it's linked to an OTG controller.
> >>>>>>>>
> >>>>>>>> Any better idea?
> >>>>>>>>
> >>>>>>>
> >>>>>>> A flag stands for this hcd controller is the same with otg controller
> >>>>>>> can be used, this flag can be stored at struct usb_otg_config.
> >>>>>>
> >>>>>> What if there is another architecture like so?
> >>>>>>
> >>>>>> C:
> >>>>>> 			[Parent]
> >>>>>> 			   |
> >>>>>> 			   |
> >>>>>> 		|------------------|--------------|
> >>>>>> 	[OTG core]		[gadget]	[host]
> >>>>>>
> >>>>>> We need a more flexible mechanism to link the gadget and
> >>>>>> host device to the otg core for non DT case.
> >>>>>>
> >>>>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> >>>>>>
> >>>>>> e.g.
> >>>>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> >>>>>>
> >>>>>> If otg is NULL it will try DT otg-controller property or parent to
> >>>>>> get the otg controller.
> >>>>>
> >>>>> How usb_otg_register_hcd get struct usb_otg, from where?
> >>>>
> >>>> This only works when the parent driver creating the hcd has registered the
> >>>> otg controller too.
> >>>>
> >>>
> >>> Sorry? So we need to find another way to solve this issue, right?
> >>
> >> For existing cases this is sufficient.
> >> The otg device is either the one supplied during usb_otg_register_hcd
> >> (cases B and C) or it is the parent device (case A).
> > 
> > How we differentiate case A and case B at usb_otg_register_hcd?
> > Would you show me the sample code?
> 
> Case A:
> 
> hcd platform driver doesn't know about otg device so it calls
> 
> 	usb_add_hcd(hcd,..)->usb_otg_register_hcd(NULL, hcd,..);
> 
> Case B:
> 
> core driver knows about both otg and hcd so it calls
> 	usb_otg_register_hcd(otg, hcd,...);
> 

Ok, Get your points, you mean invoke usb_otg_register_hcd at platform
driver directly instead of at hcd.c. It may be not a good solution
due to we use different otg APIs for two cases, it may confuse the
users, unless we can have some APIs (flags) are easy to read and well
documentation.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-09 10:01         ` Roger Quadros
@ 2015-09-10  9:28           ` Li Jun
  2015-09-10 14:14             ` Roger Quadros
  0 siblings, 1 reply; 49+ messages in thread
From: Li Jun @ 2015-09-10  9:28 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On Wed, Sep 09, 2015 at 01:01:14PM +0300, Roger Quadros wrote:
... ...

> >>>> +	return -EINVAL;
> >>>
> >>> Return non-zero, then if err, do we need call usb_otg_add_hcd() after
> >>> usb_otg_register_hcd() fails?
> >>
> >> You should not call usb_otg_register_hcd() but usb_add_hcd().
> >> If that fails then you fail as ususal.
> > 
> > My point is if we use usb_add_hcd(), but failed in usb_otg_register_hcd(),
> > then usb_otg_add_hcd() will be called in *all* error case, is this your
> > expectation?
> > 	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
> > 		return usb_otg_add_hcd(hcd, irqnum, irqflags);
> > 
> 
> Yes, my intention was that if otg fails then it is a non otg HCD so register normally.
> Let me correct my previous statement. If you are absolutely sure
> that the HCD is for otg/dual-role usage then you should call usb_otg_register_hcd().
> 

I think this is not just about a statement, in your usb_otg_register_hcd()
implementation, there are several places will return error, I think only
the first two are for a non-otg HCD case, the following error cases seems
mean this is for otg usage, but it fails in middle of registration, if that
is the case, is it reasonable to call usb_otg_add_hcd()?

> >>>> + * @fsm_running: state machine running/stopped indicator
> >>>> + */
> >>>>  struct usb_otg {
> >>>>  	u8			default_a;
> >>>>  
> >>>>  	struct phy		*phy;
> >>>>  	/* old usb_phy interface */
> >>>>  	struct usb_phy		*usb_phy;
> >>>> +
> >>>
> >>> add a blank line?
> >>>
> > 
> > You missed this.
> 
> Sorry. Did you suggest to remove that blank line
> or add a new one before usb_phy?
> 

Remove it.

> > 
> >>>>  	struct usb_bus		*host;
> >>>>  	struct usb_gadget	*gadget;
> >>>>  
> >>>>  	enum usb_otg_state	state;
> >>>>  
> >>>> +	struct device *dev;
> >>>> +	struct usb_otg_caps *caps;
> >>>> +	struct otg_fsm fsm;
> >>>> +	struct otg_fsm_ops fsm_ops;
> >>>> +
> >>>> +	/* internal use only */
> >>>> +	struct otg_hcd primary_hcd;
> >>>> +	struct otg_hcd shared_hcd;
> >>>> +	struct otg_gadget_ops *gadget_ops;
> >>>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
> >>>> +	struct list_head list;
> >>>> +	struct work_struct work;
> >>>> -- 
> >>>> 2.1.4
> > 
> 
> --
> cheers,
> -roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-10  9:28           ` Li Jun
@ 2015-09-10 14:14             ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-09-10 14:14 UTC (permalink / raw)
  To: Li Jun
  Cc: stern, balbi, gregkh, peter.chen, dan.j.williams, jun.li,
	mathias.nyman, tony, Joao.Pinto, abrestic, linux-usb,
	linux-kernel, linux-omap

On 10/09/15 12:28, Li Jun wrote:
> On Wed, Sep 09, 2015 at 01:01:14PM +0300, Roger Quadros wrote:
> ... ...
> 
>>>>>> +	return -EINVAL;
>>>>>
>>>>> Return non-zero, then if err, do we need call usb_otg_add_hcd() after
>>>>> usb_otg_register_hcd() fails?
>>>>
>>>> You should not call usb_otg_register_hcd() but usb_add_hcd().
>>>> If that fails then you fail as ususal.
>>>
>>> My point is if we use usb_add_hcd(), but failed in usb_otg_register_hcd(),
>>> then usb_otg_add_hcd() will be called in *all* error case, is this your
>>> expectation?
>>> 	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
>>> 		return usb_otg_add_hcd(hcd, irqnum, irqflags);
>>>
>>
>> Yes, my intention was that if otg fails then it is a non otg HCD so register normally.
>> Let me correct my previous statement. If you are absolutely sure
>> that the HCD is for otg/dual-role usage then you should call usb_otg_register_hcd().
>>
> 
> I think this is not just about a statement, in your usb_otg_register_hcd()
> implementation, there are several places will return error, I think only
> the first two are for a non-otg HCD case, the following error cases seems
> mean this is for otg usage, but it fails in middle of registration, if that
> is the case, is it reasonable to call usb_otg_add_hcd()?

OK. We need to check the return value then and differentiate if it is non-otg
or otg with failure.
If it is non-otg then only we must call usb_otg_add_hcd().

I will fix usb_add_hcd().

> 
>>>>>> + * @fsm_running: state machine running/stopped indicator
>>>>>> + */
>>>>>>  struct usb_otg {
>>>>>>  	u8			default_a;
>>>>>>  
>>>>>>  	struct phy		*phy;
>>>>>>  	/* old usb_phy interface */
>>>>>>  	struct usb_phy		*usb_phy;
>>>>>> +
>>>>>
>>>>> add a blank line?
>>>>>
>>>
>>> You missed this.
>>
>> Sorry. Did you suggest to remove that blank line
>> or add a new one before usb_phy?
>>
> 
> Remove it.

OK.

> 
>>>
>>>>>>  	struct usb_bus		*host;
>>>>>>  	struct usb_gadget	*gadget;
>>>>>>  
>>>>>>  	enum usb_otg_state	state;
>>>>>>  
>>>>>> +	struct device *dev;
>>>>>> +	struct usb_otg_caps *caps;
>>>>>> +	struct otg_fsm fsm;
>>>>>> +	struct otg_fsm_ops fsm_ops;
>>>>>> +
>>>>>> +	/* internal use only */
>>>>>> +	struct otg_hcd primary_hcd;
>>>>>> +	struct otg_hcd shared_hcd;
>>>>>> +	struct otg_gadget_ops *gadget_ops;
>>>>>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
>>>>>> +	struct list_head list;
>>>>>> +	struct work_struct work;
>>>>>> -- 
>>>>>> 2.1.4
>>>
--
cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-10  5:35                       ` Peter Chen
@ 2015-09-10 14:17                         ` Roger Quadros
  2015-09-11  1:50                           ` Peter Chen
  0 siblings, 1 reply; 49+ messages in thread
From: Roger Quadros @ 2015-09-10 14:17 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On 10/09/15 08:35, Peter Chen wrote:
> On Wed, Sep 09, 2015 at 01:21:50PM +0300, Roger Quadros wrote:
>> On 09/09/15 11:45, Peter Chen wrote:
>>> On Wed, Sep 09, 2015 at 12:33:20PM +0300, Roger Quadros wrote:
>>>> On 09/09/15 11:13, Peter Chen wrote:
>>>>> On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
>>>>>> On 09/09/15 05:21, Peter Chen wrote:
>>>>>>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 08/09/15 11:31, Peter Chen wrote:
>>>>>>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
>>>>>>>>>> On 07/09/15 04:23, Peter Chen wrote:
>>>>>>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
>>>>>>>>>>>> + * This is used by the USB Host stack to register the Host controller
>>>>>>>>>>>> + * to the OTG core. Host controller must not be started by the
>>>>>>>>>>>> + * caller as it is left upto the OTG state machine to do so.
>>>>>>>>>>>> + *
>>>>>>>>>>>> + * Returns: 0 on success, error value otherwise.
>>>>>>>>>>>> + */
>>>>>>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>>>>>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +	struct usb_otg *otgd;
>>>>>>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
>>>>>>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
>>>>>>>>>>>> +
>>>>>>>>>>>
>>>>>>>>>>> One big problem here is: there are two designs for current (IP) driver
>>>>>>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
>>>>>>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
>>>>>>>>>>> in your patch), like chipidea and dwc2.
>>>>>>>>>>>
>>>>>>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
>>>>>>>>>>
>>>>>>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
>>>>>>>>>> information to the otg core for such devices like chipidea and dwc2.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
>>>>>>>>> hierarchy. If the host, device, and otg share the same register
>>>>>>>>> region, host part can't be a platform driver since we don't want
>>>>>>>>> to remap the same register region again.
>>>>>>>>>
>>>>>>>>> So, in the design, we may need to consider both situations, one
>>>>>>>>> is otg/host/device has its own register region, and host is a
>>>>>>>>> separate platform device (A), the other is three parts share the
>>>>>>>>> same register region, there is only one platform driver (B).
>>>>>>>>>
>>>>>>>>> A:
>>>>>>>>>
>>>>>>>>> 			IP core device 
>>>>>>>>> 			    |
>>>>>>>>> 			    |
>>>>>>>>> 		      |-----|-----|
>>>>>>>>> 		      gadget   host platform device	
>>>>>>>>> 		      		|
>>>>>>>>> 				roothub
>>>>>>>>>
>>>>>>>>> B:
>>>>>>>>>
>>>>>>>>> 			IP core device
>>>>>>>>> 			    |
>>>>>>>>> 			    |
>>>>>>>>> 		      |-----|-----|
>>>>>>>>> 		      gadget   	 roothub
>>>>>>>>> 		      		
>>>>>>>>>
>>>>>>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
>>>>>>>>>> core knows it's linked to an OTG controller.
>>>>>>>>>>
>>>>>>>>>> Any better idea?
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> A flag stands for this hcd controller is the same with otg controller
>>>>>>>>> can be used, this flag can be stored at struct usb_otg_config.
>>>>>>>>
>>>>>>>> What if there is another architecture like so?
>>>>>>>>
>>>>>>>> C:
>>>>>>>> 			[Parent]
>>>>>>>> 			   |
>>>>>>>> 			   |
>>>>>>>> 		|------------------|--------------|
>>>>>>>> 	[OTG core]		[gadget]	[host]
>>>>>>>>
>>>>>>>> We need a more flexible mechanism to link the gadget and
>>>>>>>> host device to the otg core for non DT case.
>>>>>>>>
>>>>>>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
>>>>>>>>
>>>>>>>> e.g.
>>>>>>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
>>>>>>>>
>>>>>>>> If otg is NULL it will try DT otg-controller property or parent to
>>>>>>>> get the otg controller.
>>>>>>>
>>>>>>> How usb_otg_register_hcd get struct usb_otg, from where?
>>>>>>
>>>>>> This only works when the parent driver creating the hcd has registered the
>>>>>> otg controller too.
>>>>>>
>>>>>
>>>>> Sorry? So we need to find another way to solve this issue, right?
>>>>
>>>> For existing cases this is sufficient.
>>>> The otg device is either the one supplied during usb_otg_register_hcd
>>>> (cases B and C) or it is the parent device (case A).
>>>
>>> How we differentiate case A and case B at usb_otg_register_hcd?
>>> Would you show me the sample code?
>>
>> Case A:
>>
>> hcd platform driver doesn't know about otg device so it calls
>>
>> 	usb_add_hcd(hcd,..)->usb_otg_register_hcd(NULL, hcd,..);
>>
>> Case B:
>>
>> core driver knows about both otg and hcd so it calls
>> 	usb_otg_register_hcd(otg, hcd,...);
>>
> 
> Ok, Get your points, you mean invoke usb_otg_register_hcd at platform
> driver directly instead of at hcd.c. It may be not a good solution
> due to we use different otg APIs for two cases, it may confuse the
> users, unless we can have some APIs (flags) are easy to read and well
> documentation.
> 

I need to think how else we can solve this problem so that it is usable
for all scenarios. If you get some bright ideas please do share :)

cheers,
-roger

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

* Re: [PATCH v4 07/13] usb: otg: add OTG core
  2015-09-10 14:17                         ` Roger Quadros
@ 2015-09-11  1:50                           ` Peter Chen
  0 siblings, 0 replies; 49+ messages in thread
From: Peter Chen @ 2015-09-11  1:50 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Thu, Sep 10, 2015 at 05:17:36PM +0300, Roger Quadros wrote:
> On 10/09/15 08:35, Peter Chen wrote:
> > On Wed, Sep 09, 2015 at 01:21:50PM +0300, Roger Quadros wrote:
> >> On 09/09/15 11:45, Peter Chen wrote:
> >>> On Wed, Sep 09, 2015 at 12:33:20PM +0300, Roger Quadros wrote:
> >>>> On 09/09/15 11:13, Peter Chen wrote:
> >>>>> On Wed, Sep 09, 2015 at 12:08:10PM +0300, Roger Quadros wrote:
> >>>>>> On 09/09/15 05:21, Peter Chen wrote:
> >>>>>>> On Tue, Sep 08, 2015 at 03:25:25PM +0300, Roger Quadros wrote:
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On 08/09/15 11:31, Peter Chen wrote:
> >>>>>>>>> On Mon, Sep 07, 2015 at 01:23:01PM +0300, Roger Quadros wrote:
> >>>>>>>>>> On 07/09/15 04:23, Peter Chen wrote:
> >>>>>>>>>>> On Mon, Aug 24, 2015 at 04:21:18PM +0300, Roger Quadros wrote:
> >>>>>>>>>>>> + * This is used by the USB Host stack to register the Host controller
> >>>>>>>>>>>> + * to the OTG core. Host controller must not be started by the
> >>>>>>>>>>>> + * caller as it is left upto the OTG state machine to do so.
> >>>>>>>>>>>> + *
> >>>>>>>>>>>> + * Returns: 0 on success, error value otherwise.
> >>>>>>>>>>>> + */
> >>>>>>>>>>>> +int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
> >>>>>>>>>>>> +			 unsigned long irqflags, struct otg_hcd_ops *ops)
> >>>>>>>>>>>> +{
> >>>>>>>>>>>> +	struct usb_otg *otgd;
> >>>>>>>>>>>> +	struct device *hcd_dev = hcd->self.controller;
> >>>>>>>>>>>> +	struct device *otg_dev = usb_otg_get_device(hcd_dev);
> >>>>>>>>>>>> +
> >>>>>>>>>>>
> >>>>>>>>>>> One big problem here is: there are two designs for current (IP) driver
> >>>>>>>>>>> code, one creates dedicated hcd device as roothub's parent, like dwc3.
> >>>>>>>>>>> Another one doesn't do this, roothub's parent is core device (or otg device
> >>>>>>>>>>> in your patch), like chipidea and dwc2.
> >>>>>>>>>>>
> >>>>>>>>>>> Then, otg_dev will be glue layer device for chipidea after that.
> >>>>>>>>>>
> >>>>>>>>>> OK. Let's add a way for the otg controller driver to provide the host and gadget
> >>>>>>>>>> information to the otg core for such devices like chipidea and dwc2.
> >>>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> Roger, not only chipidea and dwc2, I think the musb uses the same
> >>>>>>>>> hierarchy. If the host, device, and otg share the same register
> >>>>>>>>> region, host part can't be a platform driver since we don't want
> >>>>>>>>> to remap the same register region again.
> >>>>>>>>>
> >>>>>>>>> So, in the design, we may need to consider both situations, one
> >>>>>>>>> is otg/host/device has its own register region, and host is a
> >>>>>>>>> separate platform device (A), the other is three parts share the
> >>>>>>>>> same register region, there is only one platform driver (B).
> >>>>>>>>>
> >>>>>>>>> A:
> >>>>>>>>>
> >>>>>>>>> 			IP core device 
> >>>>>>>>> 			    |
> >>>>>>>>> 			    |
> >>>>>>>>> 		      |-----|-----|
> >>>>>>>>> 		      gadget   host platform device	
> >>>>>>>>> 		      		|
> >>>>>>>>> 				roothub
> >>>>>>>>>
> >>>>>>>>> B:
> >>>>>>>>>
> >>>>>>>>> 			IP core device
> >>>>>>>>> 			    |
> >>>>>>>>> 			    |
> >>>>>>>>> 		      |-----|-----|
> >>>>>>>>> 		      gadget   	 roothub
> >>>>>>>>> 		      		
> >>>>>>>>>
> >>>>>>>>>> This API must be called before the hcd/gadget-driver is added so that the otg
> >>>>>>>>>> core knows it's linked to an OTG controller.
> >>>>>>>>>>
> >>>>>>>>>> Any better idea?
> >>>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> A flag stands for this hcd controller is the same with otg controller
> >>>>>>>>> can be used, this flag can be stored at struct usb_otg_config.
> >>>>>>>>
> >>>>>>>> What if there is another architecture like so?
> >>>>>>>>
> >>>>>>>> C:
> >>>>>>>> 			[Parent]
> >>>>>>>> 			   |
> >>>>>>>> 			   |
> >>>>>>>> 		|------------------|--------------|
> >>>>>>>> 	[OTG core]		[gadget]	[host]
> >>>>>>>>
> >>>>>>>> We need a more flexible mechanism to link the gadget and
> >>>>>>>> host device to the otg core for non DT case.
> >>>>>>>>
> >>>>>>>> How about adding struct usb_otg parameter to usb_otg_register_hcd()?
> >>>>>>>>
> >>>>>>>> e.g.
> >>>>>>>> int usb_otg_register_hcd(struct usb_otg *otg, struct usb_hcd *hcd, ..)
> >>>>>>>>
> >>>>>>>> If otg is NULL it will try DT otg-controller property or parent to
> >>>>>>>> get the otg controller.
> >>>>>>>
> >>>>>>> How usb_otg_register_hcd get struct usb_otg, from where?
> >>>>>>
> >>>>>> This only works when the parent driver creating the hcd has registered the
> >>>>>> otg controller too.
> >>>>>>
> >>>>>
> >>>>> Sorry? So we need to find another way to solve this issue, right?
> >>>>
> >>>> For existing cases this is sufficient.
> >>>> The otg device is either the one supplied during usb_otg_register_hcd
> >>>> (cases B and C) or it is the parent device (case A).
> >>>
> >>> How we differentiate case A and case B at usb_otg_register_hcd?
> >>> Would you show me the sample code?
> >>
> >> Case A:
> >>
> >> hcd platform driver doesn't know about otg device so it calls
> >>
> >> 	usb_add_hcd(hcd,..)->usb_otg_register_hcd(NULL, hcd,..);
> >>
> >> Case B:
> >>
> >> core driver knows about both otg and hcd so it calls
> >> 	usb_otg_register_hcd(otg, hcd,...);
> >>
> > 
> > Ok, Get your points, you mean invoke usb_otg_register_hcd at platform
> > driver directly instead of at hcd.c. It may be not a good solution
> > due to we use different otg APIs for two cases, it may confuse the
> > users, unless we can have some APIs (flags) are easy to read and well
> > documentation.
> > 
> 
> I need to think how else we can solve this problem so that it is usable
> for all scenarios. If you get some bright ideas please do share :)
> 

If we want to call OTG stuff at hcd/gadget driver, we'd better store
struct usb_otg pointer at struct usb_hcd and struct usb_gadget, since
the parent/child relationship can't be used now.

The platform driver can call usb_otg_register_hcd/usb_otg_register_gadget
to achieve this, it is a little different with your current design.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 00/13]  USB: OTG/DRD Core functionality
  2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
                   ` (14 preceding siblings ...)
  2015-09-06  7:06 ` Peter Chen
@ 2015-12-03  8:19 ` Peter Chen
  2015-12-03  8:54   ` Roger Quadros
  15 siblings, 1 reply; 49+ messages in thread
From: Peter Chen @ 2015-12-03  8:19 UTC (permalink / raw)
  To: Roger Quadros
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

On Mon, Aug 24, 2015 at 04:21:11PM +0300, Roger Quadros wrote:
> Hi,
> 
> This series centralizes OTG/Dual-role functionality in the kernel.
> As of now I've got Dual-role functionality working pretty reliably on
> dra7-evm and am437x-gp-evm.
> 
> DWC3 controller and platform related patches will be sent separately.
> 
> Series is based on Greg's usb-next tree.

Hi Roger,

Will you go on for this patch set?

Peter
> 
> Changelog:
> ---------
> v4:
> - Added DT support for tying otg-controller to host and gadget
>  controllers. For DT we no longer have the constraint that
>  OTG controller needs to be parent of host and gadget. They can be
>  tied together using the "otg-controller" property.
> - Relax the requirement for DT case that otg controller must register before
>  host/gadget. We maintain a wait list of host/gadget devices
>  waiting on the otg controller.
> - Use a single struct usb_otg for otg data.
> - Don't override host/gadget start/stop APIs. Let the controller
>  drivers do what they want as they know best. Helper API is provided
>  for controller start/stop that controller driver can use.
> - Introduce struct usb_otg_config to pass the otg capabilities,
>  otg ops and otg timer timeouts during otg controller registration.
> - rebased on Greg's usb.git/usb-next
> 
> v3:
> - all otg related definations now in otg.h
> - single kernel config USB_OTG to enable OTG core and FSM.
> - resolved symbol dependency issues.
> - use dev_vdbg instead of VDBG() in usb-otg-fsm.c
> - rebased on v4.2-rc1
> 
> v2:
> - Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
>  the host controller
> - added dual-role-device (DRD) state machine which is a much simpler
>  mode of operation when compared to OTG. Here we don't support fancy
>  OTG features like HNP, SRP, on the fly role-swap. The mode of operation
>  is determined based on ID pin (cable type) and the role doesn't change
>  till the cable type changes.
> 
> Why?:
> ----
> 
> Most of the OTG drivers have been dealing with the OTG state machine
> themselves and there is a scope for code re-use. This has been
> partly addressed by the usb/common/usb-otg-fsm.c but it still
> leaves the instantiation of the state machine and OTG timers
> to the controller drivers. We re-use usb-otg-fsm.c but
> go one step further by instantiating the state machine and timers
> thus making it easier for drivers to implement OTG functionality.
> 
> Newer OTG cores support standard host interface (e.g. xHCI) so
> host and gadget functionality are no longer closely knit like older
> cores. There needs to be a way to co-ordinate the operation of the
> host and gadget in OTG mode. i.e. to stop and start them from a
> central location. This central location should be the USB OTG core.
> 
> Host and gadget controllers might be sharing resources and can't
> be always running. One has to be stopped for the other to run.
> This can't be done as of now and can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG core instantiates the OTG/DRD Finite State Machine
> per OTG controller and manages starting/stopping the
> host and gadget controllers based on the bus state.
>     
> It provides APIs for the following
>     
> - Registering an OTG capable controller
> struct otg_fsm *usb_otg_register(struct device *dev,
>                                  struct usb_otg_config *config);
> 
> int usb_otg_unregister(struct device *dev);
> 
> - Registering Host controllers to OTG core (used by hcd-core)
> int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>                          unsigned long irqflags, struct otg_hcd_ops *ops);
> int usb_otg_unregister_hcd(struct usb_hcd *hcd);
> 
> 
> - Registering Gadget controllers to OTG core (used by udc-core)
> int usb_otg_register_gadget(struct usb_gadget *gadget,
>                             struct otg_gadget_ops *ops);
> int usb_otg_unregister_gadget(struct usb_gadget *gadget);
> 
> 
> - Providing inputs to and kicking the OTG state machine
> void usb_otg_sync_inputs(struct otg_fsm *fsm);
> int usb_otg_kick_fsm(struct device *hcd_gcd_device);
> 
> - Getting controller device structure from OTG state machine instance
> struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
> 
> 'struct otg_fsm' is the interface to the OTG state machine.
> It contains inputs to the fsm, status of the fsm and operations
> for the OTG controller driver.
> 
> - Helper APIs for starting/stopping host/gadget controllers
> int usb_otg_start_host(struct otg_fsm *fsm, int on);
> int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
> 
> Usage model:
> -----------
> 
> - The OTG core needs to know what host and gadget controllers are
> linked to the OTG controller. For DT boots we can provide that
> information by adding "otg-controller" property to the host and
> gadget controller nodes that points to the right otg controller.
> For legacy boot we assume that OTG controller is the parent
> of the host and gadget controllers. For DT if "otg-controller"
> property is not present then parent child relationship constraint
> applies.
> 
> - The OTG controller driver must call usb_otg_register() to register
> itself with the OTG core. It must also provide the required
> OTG configuration, fsm operations and timer timeouts (optional)
> via struct usb_otg_config. The fsm operations will be called
> depending on the OTG bus state.
> 
> - The host/gadget core stacks are modified to inform the OTG core
> whenever a new host/gadget device is added. The OTG core then
> checks if the host/gadget is part of the OTG controller and if yes
> then prevents the host/gadget from starting till both host and
> gadget are registered, OTG state machine is running and the
> USB bus state is appropriate to start host/gadget.
> For this, APIs have been added to host/gadget stacks to start/stop
> the controllers from the OTG core.
> For DT boots, If the OTG controller hasn't yet been registered
> while the host/gadget are added, the OTG core will hold it in a wait list
> and register them when the OTG controller registers.
> 
> - No modification is needed for the host/gadget controller drivers.
> They must ensure that their start/stop methods can be called repeatedly
> and any shared resources between host & gadget are properly managed.
> The OTG core ensures that both are not started simultaneously.
> 
> - The OTG core instantiates one OTG state machine per OTG controller
> and the necessary OTG timers to manage OTG state timeouts.
> If none of the otg features are set during usb_otg_register() then it
> instanciates a DRD (dual-role device) state machine instead.
> The state machine is started when both host & gadget register and
> stopped when either of them unregisters. The controllers are started
> and stopped depending on bus state.
> 
> - During the lifetime of the OTG state machine, inputs can be
> provided to it by modifying the appropriate members of 'struct otg_fsm'
> and calling usb_otg_sync_inputs(). This is typically done by the
> OTG controller driver that called usb_otg_register().
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: otg-fsm: Add documentation for struct otg_fsm
>   usb: otg-fsm: support multiple instances
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   otg-fsm: move usb_bus_start_enum into otg-fsm->ops
>   usb: hcd.h: Add OTG to HCD interface
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: add OTG core
>   usb: doc: dt-binding: Add otg-controller property
>   usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
>   usb: hcd: Adapt to OTG core
>   usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
>   usb: gadget: udc: adapt to OTG core
>   usb: otg: Add dual-role device (DRD) support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |    5 +
>  Documentation/usb/chipidea.txt                    |    2 +-
>  MAINTAINERS                                       |    4 +-
>  drivers/usb/Kconfig                               |    2 +-
>  drivers/usb/Makefile                              |    1 +
>  drivers/usb/chipidea/Makefile                     |    2 +-
>  drivers/usb/chipidea/ci.h                         |    2 +-
>  drivers/usb/chipidea/otg_fsm.c                    |    1 +
>  drivers/usb/chipidea/otg_fsm.h                    |    2 +-
>  drivers/usb/common/Makefile                       |    3 +-
>  drivers/usb/common/usb-otg-fsm.c                  |   26 +-
>  drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
>  drivers/usb/common/usb-otg.h                      |   71 ++
>  drivers/usb/core/Kconfig                          |   11 +-
>  drivers/usb/core/hcd.c                            |   55 +-
>  drivers/usb/core/hub.c                            |   10 +-
>  drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
>  drivers/usb/phy/Kconfig                           |    2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     |    3 +
>  include/linux/usb/gadget.h                        |   14 +
>  include/linux/usb/hcd.h                           |   14 +
>  include/linux/usb/otg-fsm.h                       |  116 +-
>  include/linux/usb/otg.h                           |  191 +++-
>  23 files changed, 1808 insertions(+), 76 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>  create mode 100644 drivers/usb/common/usb-otg.h
> 
> -- 
> 2.1.4
> 

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v4 00/13] USB: OTG/DRD Core functionality
  2015-12-03  8:19 ` Peter Chen
@ 2015-12-03  8:54   ` Roger Quadros
  0 siblings, 0 replies; 49+ messages in thread
From: Roger Quadros @ 2015-12-03  8:54 UTC (permalink / raw)
  To: Peter Chen
  Cc: stern, balbi, gregkh, dan.j.williams, jun.li, mathias.nyman,
	tony, Joao.Pinto, abrestic, linux-usb, linux-kernel, linux-omap

Peter,

On 03/12/15 13:49, Peter Chen wrote:
> On Mon, Aug 24, 2015 at 04:21:11PM +0300, Roger Quadros wrote:
>> Hi,
>>
>> This series centralizes OTG/Dual-role functionality in the kernel.
>> As of now I've got Dual-role functionality working pretty reliably on
>> dra7-evm and am437x-gp-evm.
>>
>> DWC3 controller and platform related patches will be sent separately.
>>
>> Series is based on Greg's usb-next tree.
> 
> Hi Roger,
> 
> Will you go on for this patch set?

Yes, but I can only work on this from Feb onwards.

cheers,
-roger
> 
> Peter
>>
>> Changelog:
>> ---------
>> v4:
>> - Added DT support for tying otg-controller to host and gadget
>>  controllers. For DT we no longer have the constraint that
>>  OTG controller needs to be parent of host and gadget. They can be
>>  tied together using the "otg-controller" property.
>> - Relax the requirement for DT case that otg controller must register before
>>  host/gadget. We maintain a wait list of host/gadget devices
>>  waiting on the otg controller.
>> - Use a single struct usb_otg for otg data.
>> - Don't override host/gadget start/stop APIs. Let the controller
>>  drivers do what they want as they know best. Helper API is provided
>>  for controller start/stop that controller driver can use.
>> - Introduce struct usb_otg_config to pass the otg capabilities,
>>  otg ops and otg timer timeouts during otg controller registration.
>> - rebased on Greg's usb.git/usb-next
>>
>> v3:
>> - all otg related definations now in otg.h
>> - single kernel config USB_OTG to enable OTG core and FSM.
>> - resolved symbol dependency issues.
>> - use dev_vdbg instead of VDBG() in usb-otg-fsm.c
>> - rebased on v4.2-rc1
>>
>> v2:
>> - Use add/remove_hcd() instead of start/stop_hcd() to enable/disable
>>  the host controller
>> - added dual-role-device (DRD) state machine which is a much simpler
>>  mode of operation when compared to OTG. Here we don't support fancy
>>  OTG features like HNP, SRP, on the fly role-swap. The mode of operation
>>  is determined based on ID pin (cable type) and the role doesn't change
>>  till the cable type changes.
>>
>> Why?:
>> ----
>>
>> Most of the OTG drivers have been dealing with the OTG state machine
>> themselves and there is a scope for code re-use. This has been
>> partly addressed by the usb/common/usb-otg-fsm.c but it still
>> leaves the instantiation of the state machine and OTG timers
>> to the controller drivers. We re-use usb-otg-fsm.c but
>> go one step further by instantiating the state machine and timers
>> thus making it easier for drivers to implement OTG functionality.
>>
>> Newer OTG cores support standard host interface (e.g. xHCI) so
>> host and gadget functionality are no longer closely knit like older
>> cores. There needs to be a way to co-ordinate the operation of the
>> host and gadget in OTG mode. i.e. to stop and start them from a
>> central location. This central location should be the USB OTG core.
>>
>> Host and gadget controllers might be sharing resources and can't
>> be always running. One has to be stopped for the other to run.
>> This can't be done as of now and can be done from the OTG core.
>>
>> What?:
>> -----
>>
>> The OTG core instantiates the OTG/DRD Finite State Machine
>> per OTG controller and manages starting/stopping the
>> host and gadget controllers based on the bus state.
>>     
>> It provides APIs for the following
>>     
>> - Registering an OTG capable controller
>> struct otg_fsm *usb_otg_register(struct device *dev,
>>                                  struct usb_otg_config *config);
>>
>> int usb_otg_unregister(struct device *dev);
>>
>> - Registering Host controllers to OTG core (used by hcd-core)
>> int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
>>                          unsigned long irqflags, struct otg_hcd_ops *ops);
>> int usb_otg_unregister_hcd(struct usb_hcd *hcd);
>>
>>
>> - Registering Gadget controllers to OTG core (used by udc-core)
>> int usb_otg_register_gadget(struct usb_gadget *gadget,
>>                             struct otg_gadget_ops *ops);
>> int usb_otg_unregister_gadget(struct usb_gadget *gadget);
>>
>>
>> - Providing inputs to and kicking the OTG state machine
>> void usb_otg_sync_inputs(struct otg_fsm *fsm);
>> int usb_otg_kick_fsm(struct device *hcd_gcd_device);
>>
>> - Getting controller device structure from OTG state machine instance
>> struct device *usb_otg_fsm_to_dev(struct otg_fsm *fsm);
>>
>> 'struct otg_fsm' is the interface to the OTG state machine.
>> It contains inputs to the fsm, status of the fsm and operations
>> for the OTG controller driver.
>>
>> - Helper APIs for starting/stopping host/gadget controllers
>> int usb_otg_start_host(struct otg_fsm *fsm, int on);
>> int usb_otg_start_gadget(struct otg_fsm *fsm, int on);
>>
>> Usage model:
>> -----------
>>
>> - The OTG core needs to know what host and gadget controllers are
>> linked to the OTG controller. For DT boots we can provide that
>> information by adding "otg-controller" property to the host and
>> gadget controller nodes that points to the right otg controller.
>> For legacy boot we assume that OTG controller is the parent
>> of the host and gadget controllers. For DT if "otg-controller"
>> property is not present then parent child relationship constraint
>> applies.
>>
>> - The OTG controller driver must call usb_otg_register() to register
>> itself with the OTG core. It must also provide the required
>> OTG configuration, fsm operations and timer timeouts (optional)
>> via struct usb_otg_config. The fsm operations will be called
>> depending on the OTG bus state.
>>
>> - The host/gadget core stacks are modified to inform the OTG core
>> whenever a new host/gadget device is added. The OTG core then
>> checks if the host/gadget is part of the OTG controller and if yes
>> then prevents the host/gadget from starting till both host and
>> gadget are registered, OTG state machine is running and the
>> USB bus state is appropriate to start host/gadget.
>> For this, APIs have been added to host/gadget stacks to start/stop
>> the controllers from the OTG core.
>> For DT boots, If the OTG controller hasn't yet been registered
>> while the host/gadget are added, the OTG core will hold it in a wait list
>> and register them when the OTG controller registers.
>>
>> - No modification is needed for the host/gadget controller drivers.
>> They must ensure that their start/stop methods can be called repeatedly
>> and any shared resources between host & gadget are properly managed.
>> The OTG core ensures that both are not started simultaneously.
>>
>> - The OTG core instantiates one OTG state machine per OTG controller
>> and the necessary OTG timers to manage OTG state timeouts.
>> If none of the otg features are set during usb_otg_register() then it
>> instanciates a DRD (dual-role device) state machine instead.
>> The state machine is started when both host & gadget register and
>> stopped when either of them unregisters. The controllers are started
>> and stopped depending on bus state.
>>
>> - During the lifetime of the OTG state machine, inputs can be
>> provided to it by modifying the appropriate members of 'struct otg_fsm'
>> and calling usb_otg_sync_inputs(). This is typically done by the
>> OTG controller driver that called usb_otg_register().
>>
>> --
>> cheers,
>> -roger
>>
>> Roger Quadros (13):
>>   usb: otg-fsm: Add documentation for struct otg_fsm
>>   usb: otg-fsm: support multiple instances
>>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>>   otg-fsm: move usb_bus_start_enum into otg-fsm->ops
>>   usb: hcd.h: Add OTG to HCD interface
>>   usb: gadget.h: Add OTG to gadget interface
>>   usb: otg: add OTG core
>>   usb: doc: dt-binding: Add otg-controller property
>>   usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG
>>   usb: hcd: Adapt to OTG core
>>   usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable
>>   usb: gadget: udc: adapt to OTG core
>>   usb: otg: Add dual-role device (DRD) support
>>
>>  Documentation/devicetree/bindings/usb/generic.txt |    5 +
>>  Documentation/usb/chipidea.txt                    |    2 +-
>>  MAINTAINERS                                       |    4 +-
>>  drivers/usb/Kconfig                               |    2 +-
>>  drivers/usb/Makefile                              |    1 +
>>  drivers/usb/chipidea/Makefile                     |    2 +-
>>  drivers/usb/chipidea/ci.h                         |    2 +-
>>  drivers/usb/chipidea/otg_fsm.c                    |    1 +
>>  drivers/usb/chipidea/otg_fsm.h                    |    2 +-
>>  drivers/usb/common/Makefile                       |    3 +-
>>  drivers/usb/common/usb-otg-fsm.c                  |   26 +-
>>  drivers/usb/common/usb-otg.c                      | 1223 +++++++++++++++++++++
>>  drivers/usb/common/usb-otg.h                      |   71 ++
>>  drivers/usb/core/Kconfig                          |   11 +-
>>  drivers/usb/core/hcd.c                            |   55 +-
>>  drivers/usb/core/hub.c                            |   10 +-
>>  drivers/usb/gadget/udc/udc-core.c                 |  124 ++-
>>  drivers/usb/phy/Kconfig                           |    2 +-
>>  drivers/usb/phy/phy-fsl-usb.c                     |    3 +
>>  include/linux/usb/gadget.h                        |   14 +
>>  include/linux/usb/hcd.h                           |   14 +
>>  include/linux/usb/otg-fsm.h                       |  116 +-
>>  include/linux/usb/otg.h                           |  191 +++-
>>  23 files changed, 1808 insertions(+), 76 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>  create mode 100644 drivers/usb/common/usb-otg.h
>>
>> -- 
>> 2.1.4
>>
> 

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

end of thread, other threads:[~2015-12-03  8:54 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-24 13:21 [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros
2015-08-24 13:21 ` [PATCH v4 01/13] usb: otg-fsm: Add documentation for struct otg_fsm Roger Quadros
2015-08-24 13:21 ` [PATCH v4 02/13] usb: otg-fsm: support multiple instances Roger Quadros
2015-09-06  5:52   ` Peter Chen
2015-08-24 13:21 ` [PATCH v4 03/13] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros
2015-08-24 13:21 ` [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops Roger Quadros
2015-09-07  1:24   ` Peter Chen
2015-09-07  9:57     ` Roger Quadros
2015-09-08  6:54       ` Peter Chen
2015-09-08  8:24         ` Roger Quadros
2015-08-24 13:21 ` [PATCH v4 05/13] usb: hcd.h: Add OTG to HCD interface Roger Quadros
2015-08-24 13:21 ` [PATCH v4 06/13] usb: gadget.h: Add OTG to gadget interface Roger Quadros
2015-08-24 13:21 ` [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros
2015-09-07  1:23   ` Peter Chen
2015-09-07 10:23     ` Roger Quadros
2015-09-08  8:31       ` Peter Chen
2015-09-08 12:25         ` Roger Quadros
2015-09-08 14:34           ` Alan Stern
2015-09-08 17:29             ` Roger Quadros
2015-09-09  2:21           ` Peter Chen
2015-09-09  9:08             ` Roger Quadros
2015-09-09  8:13               ` Peter Chen
2015-09-09  9:33                 ` Roger Quadros
2015-09-09  8:45                   ` Peter Chen
2015-09-09 10:21                     ` Roger Quadros
2015-09-10  5:35                       ` Peter Chen
2015-09-10 14:17                         ` Roger Quadros
2015-09-11  1:50                           ` Peter Chen
2015-09-07  7:40   ` Li Jun
2015-09-07 10:53     ` Roger Quadros
2015-09-09  6:20       ` Li Jun
2015-09-09 10:01         ` Roger Quadros
2015-09-10  9:28           ` Li Jun
2015-09-10 14:14             ` Roger Quadros
2015-08-24 13:21 ` [PATCH v4 08/13] usb: doc: dt-binding: Add otg-controller property Roger Quadros
2015-08-24 13:21 ` [PATCH v4 09/13] usb: chipidea: move from CONFIG_USB_OTG_FSM to CONFIG_USB_OTG Roger Quadros
2015-08-24 13:21 ` [PATCH v4 10/13] usb: hcd: Adapt to OTG core Roger Quadros
2015-09-09  2:23   ` Peter Chen
2015-09-09  9:39     ` Roger Quadros
2015-08-24 13:21 ` [PATCH v4 11/13] usb: core: hub: Notify OTG fsm when A device sets b_hnp_enable Roger Quadros
2015-08-24 13:21 ` [PATCH v4 12/13] usb: gadget: udc: adapt to OTG core Roger Quadros
2015-08-24 13:21 ` [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros
2015-09-07  7:53   ` Li Jun
2015-09-07  9:51     ` Roger Quadros
2015-08-26  6:19 ` [PATCH v4 00/13] USB: OTG/DRD Core functionality Peter Chen
2015-09-06  7:06 ` Peter Chen
2015-09-07 11:42   ` Roger Quadros
2015-12-03  8:19 ` Peter Chen
2015-12-03  8:54   ` Roger Quadros

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).