All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-10 13:07 ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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 TI platform related patches will be sent separately.

Series is based on v4.7-rc1 + balbi/usb.git testing/next
commit 4a2786c10462df650965785462ca82c185164d98.

Why?:
----

Currently there is no central location where OTG/dual-role functionality is
implemented in the Linux USB stack and every USB controller driver is
doing their own thing for OTG/dual-role. We can benefit from code-reuse
and simplicity by adding the OTG/dual-role core driver.

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 controllers in dual-role mode. i.e. to stop and start them
from a central location. This central location should be the
USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.

What?:
-----

The OTG/dual-role core consists of a set of APIs that allow
registration of OTG controller device and OTG capable host and gadget
controllers.

- The OTG controller driver can provide the OTG capabilities and the
Finite State Machine work function via 'struct usb_otg_config'
at the time of registration i.e. usb_otg_register();

	struct usb_otg *usb_otg_register(struct device *dev,
        	                         struct usb_otg_config *config);
	int usb_otg_unregister(struct device *dev);
	/**
	 * struct usb_otg_config - otg controller configuration
	 * @caps: otg capabilities of the controller
	 * @ops: otg fsm operations
	 * @otg_work: optional custom otg state machine work function
	 */
	struct usb_otg_config {
	        struct usb_otg_caps *otg_caps;
	        struct otg_fsm_ops *fsm_ops;
	        void (*otg_work)(struct work_struct *work);
	};

The dual-role state machine is built-into the OTG core so nothing
special needs to be provided if only dual-role functionality is desired.
The low level OTG controller driver ops are povided via
'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.

After registration, the OTG core waits for host, gadget controller
and the gadget function driver to be registered. Once all resources are
available it instantiates the Finite State Machine (FSM).
The host/gadget controllers are started/stopped according to the FSM.

- Host and gadget controllers that are a part of OTG/dual-role port must
use the OTG core provided APIs to add/remove the host/gadget.
i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
This ensures that the host and gadget controllers are not started till
the state machine is ready and the right bus conditions are met.
It also allows the host and gadget controllers to provide the OTG
controller device to link them together. For Device tree boots
the related OTG controller is automatically picked up via the
'otg-controller' property in the Host/Gadget controller nodes.

	int usb_otg_add_hcd(struct usb_hcd *hcd,
			    unsigned int irqnum, unsigned long irqflags,
			    struct device *otg_dev);
	void usb_otg_remove_hcd(struct usb_hcd *hcd);

	int usb_otg_add_gadget_udc(struct device *parent,
				   struct usb_gadget *gadget,
				   struct device *otg_dev);
	usb_del_gadget_udc() must be used for removal.


- During the lifetime of the FSM, the OTG controller driver can provide
inputs event changes using usb_otg_sync_inputs(). The OTG core will
then schedule the FSM work function (or internal dual-role state machine)
to update the FSM state. The FSM then calls the OTG controller
operations (fsm_ops) as necessary.
	void usb_otg_sync_inputs(struct usb_otg *otg);

- The following 2 functions are provided as helpers for use by the
OTG controller driver to start/stop the host/gadget controllers.
	int usb_otg_start_host(struct usb_otg *otg, int on);
	int usb_otg_start_gadget(struct usb_otg *otg, int on);

- The following function is provided for use by the USB host stack
to sync OTG related events to the OTG state machine.
e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
	int usb_otg_kick_fsm(struct device *otg_device);

- The following function is provided for use by the USB gadget stack
to notify OTG/DRD about gadget function driver being ready/not-ready
	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)

Changelog:
---------
v10:
- added missing mutex_unlock in failure path in usb_otg_unregister()
- removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
- comment fixes: urb->URB.
- fix commit log: say dev_vdbg() instead of dev_dbg().
- Update comments so that HCD means Host Controller Driver.
- rebased on Felipe's balbi/usb.git /testing/next
- include <linux/usb/of.h> in usb-otg.c
- in usb_otg_start_host() check if hcd_ops->add() failed and return
error code if it did.
- in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
error code if it did.
- follow kernel-doc style in usb-otg.c

v9:
- In the DT bindings, clearly indicate which properties are for OTG controller
and which ones are for host/device controllers
- Removed host/gadget wait list from otg core. Use defer probing if host/gadget
registers before dual-role/otg controller.
- move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
an additional mechanism to know when the gadget function driver registers.
So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
ready/not-ready function driver.
- update otg->caps based on capabilities provided by the controller and the
device tree overrides.
- in usb_drd_work() we must keep calling the drd_statemachine() as long as
there is a state change.
- updated kconfig so that usbotg can be a module when both host and gadget
are modules.
- rebased on v4.7-rc1

v8:
- split out start/stop gadget and connect/disconnect operations.
- make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
- use create_freezable_workqueue() for OTG work as per Peter's suggestion.
- remove usb-otg.h as we're not initializing any OTG timers.
- don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)

v7:
- added dual-role support for host controllers requiring a companion
controller. e.g. EHCI + OHCI.
- added of_usb_get_otg() to get the OTG controller device
from the USB controller's device node.
- addressed review comments.

v6:
- added otg specific APIs for host/gadget registration. behaviour of
original host/gadget API remains unchanged. Platform devices can now
pass the otg device explicitly while registering host/gadget.
- moved hcd specific operations from struct otg_fsm to struct hcd_ops.
- made struct usb_otg mandatory for all otg related APIs.
- allow otg controller to provide it's own otg_work function so that
it can implement it's own state machine.
- removed otg fsm and timers from usb-otg.c. Only dual-role state machine
is implemented.
- vbus is controlled in the dual-role state machine.
- PM runtime is used around drd_statemachine().
- added otg_dev to xhci platform data to allow platform code to specify
the otg controller tied to the xhci host controller.

v5: Internal version. Not sent to mailing list

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.

--
cheers,
-roger

Roger Quadros (13):
  usb: hcd: Initialize hcd->flags to 0
  usb: otg-fsm: Prevent build warning "VDBG" redefined
  usb: hcd.h: Add OTG to HCD interface
  usb: otg-fsm: use usb_otg wherever possible
  usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
  usb: gadget.h: Add OTG to gadget interface
  usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
  usb: otg: add OTG/dual-role core
  usb: of: add an API to get OTG device from USB controller node
  usb: otg: use dev_vdbg() instead of VDBG()
  usb: hcd: Adapt to OTG core
  usb: gadget: udc: adapt to OTG core
  usb: host: xhci-plat: Add otg device to platform data

Yoshihiro Shimoda (1):
  usb: otg: add hcd companion support

 Documentation/devicetree/bindings/usb/generic.txt |   6 +
 Documentation/usb/chipidea.txt                    |   2 +-
 drivers/usb/Kconfig                               |  18 +
 drivers/usb/Makefile                              |   1 +
 drivers/usb/chipidea/Makefile                     |   2 +-
 drivers/usb/chipidea/ci.h                         |   3 +-
 drivers/usb/chipidea/core.c                       |  14 +-
 drivers/usb/chipidea/debug.c                      |   2 +-
 drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
 drivers/usb/chipidea/otg_fsm.h                    |   2 +-
 drivers/usb/chipidea/udc.c                        |  17 +-
 drivers/usb/common/Makefile                       |   5 +-
 drivers/usb/common/common.c                       |  27 +
 drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
 drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
 drivers/usb/core/Kconfig                          |  22 -
 drivers/usb/core/hcd.c                            |  56 ++
 drivers/usb/gadget/Kconfig                        |   1 +
 drivers/usb/gadget/udc/core.c                     | 202 ++++-
 drivers/usb/host/xhci-plat.c                      |  35 +-
 drivers/usb/phy/Kconfig                           |   2 +-
 drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
 drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
 include/linux/usb/gadget.h                        |  22 +
 include/linux/usb/hcd.h                           |  29 +
 include/linux/usb/of.h                            |   9 +
 include/linux/usb/otg-fsm.h                       | 154 +---
 include/linux/usb/otg.h                           | 290 ++++++-
 include/linux/usb/xhci_pdriver.h                  |   3 +
 29 files changed, 1918 insertions(+), 462 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

-- 
2.7.4

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

* [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-10 13:07 ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, 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 TI platform related patches will be sent separately.

Series is based on v4.7-rc1 + balbi/usb.git testing/next
commit 4a2786c10462df650965785462ca82c185164d98.

Why?:
----

Currently there is no central location where OTG/dual-role functionality is
implemented in the Linux USB stack and every USB controller driver is
doing their own thing for OTG/dual-role. We can benefit from code-reuse
and simplicity by adding the OTG/dual-role core driver.

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 controllers in dual-role mode. i.e. to stop and start them
from a central location. This central location should be the
USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.

What?:
-----

The OTG/dual-role core consists of a set of APIs that allow
registration of OTG controller device and OTG capable host and gadget
controllers.

- The OTG controller driver can provide the OTG capabilities and the
Finite State Machine work function via 'struct usb_otg_config'
at the time of registration i.e. usb_otg_register();

	struct usb_otg *usb_otg_register(struct device *dev,
        	                         struct usb_otg_config *config);
	int usb_otg_unregister(struct device *dev);
	/**
	 * struct usb_otg_config - otg controller configuration
	 * @caps: otg capabilities of the controller
	 * @ops: otg fsm operations
	 * @otg_work: optional custom otg state machine work function
	 */
	struct usb_otg_config {
	        struct usb_otg_caps *otg_caps;
	        struct otg_fsm_ops *fsm_ops;
	        void (*otg_work)(struct work_struct *work);
	};

The dual-role state machine is built-into the OTG core so nothing
special needs to be provided if only dual-role functionality is desired.
The low level OTG controller driver ops are povided via
'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.

After registration, the OTG core waits for host, gadget controller
and the gadget function driver to be registered. Once all resources are
available it instantiates the Finite State Machine (FSM).
The host/gadget controllers are started/stopped according to the FSM.

- Host and gadget controllers that are a part of OTG/dual-role port must
use the OTG core provided APIs to add/remove the host/gadget.
i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
This ensures that the host and gadget controllers are not started till
the state machine is ready and the right bus conditions are met.
It also allows the host and gadget controllers to provide the OTG
controller device to link them together. For Device tree boots
the related OTG controller is automatically picked up via the
'otg-controller' property in the Host/Gadget controller nodes.

	int usb_otg_add_hcd(struct usb_hcd *hcd,
			    unsigned int irqnum, unsigned long irqflags,
			    struct device *otg_dev);
	void usb_otg_remove_hcd(struct usb_hcd *hcd);

	int usb_otg_add_gadget_udc(struct device *parent,
				   struct usb_gadget *gadget,
				   struct device *otg_dev);
	usb_del_gadget_udc() must be used for removal.


- During the lifetime of the FSM, the OTG controller driver can provide
inputs event changes using usb_otg_sync_inputs(). The OTG core will
then schedule the FSM work function (or internal dual-role state machine)
to update the FSM state. The FSM then calls the OTG controller
operations (fsm_ops) as necessary.
	void usb_otg_sync_inputs(struct usb_otg *otg);

- The following 2 functions are provided as helpers for use by the
OTG controller driver to start/stop the host/gadget controllers.
	int usb_otg_start_host(struct usb_otg *otg, int on);
	int usb_otg_start_gadget(struct usb_otg *otg, int on);

- The following function is provided for use by the USB host stack
to sync OTG related events to the OTG state machine.
e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
	int usb_otg_kick_fsm(struct device *otg_device);

- The following function is provided for use by the USB gadget stack
to notify OTG/DRD about gadget function driver being ready/not-ready
	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)

Changelog:
---------
v10:
- added missing mutex_unlock in failure path in usb_otg_unregister()
- removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
- comment fixes: urb->URB.
- fix commit log: say dev_vdbg() instead of dev_dbg().
- Update comments so that HCD means Host Controller Driver.
- rebased on Felipe's balbi/usb.git /testing/next
- include <linux/usb/of.h> in usb-otg.c
- in usb_otg_start_host() check if hcd_ops->add() failed and return
error code if it did.
- in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
error code if it did.
- follow kernel-doc style in usb-otg.c

v9:
- In the DT bindings, clearly indicate which properties are for OTG controller
and which ones are for host/device controllers
- Removed host/gadget wait list from otg core. Use defer probing if host/gadget
registers before dual-role/otg controller.
- move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
an additional mechanism to know when the gadget function driver registers.
So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
ready/not-ready function driver.
- update otg->caps based on capabilities provided by the controller and the
device tree overrides.
- in usb_drd_work() we must keep calling the drd_statemachine() as long as
there is a state change.
- updated kconfig so that usbotg can be a module when both host and gadget
are modules.
- rebased on v4.7-rc1

v8:
- split out start/stop gadget and connect/disconnect operations.
- make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
- use create_freezable_workqueue() for OTG work as per Peter's suggestion.
- remove usb-otg.h as we're not initializing any OTG timers.
- don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)

v7:
- added dual-role support for host controllers requiring a companion
controller. e.g. EHCI + OHCI.
- added of_usb_get_otg() to get the OTG controller device
from the USB controller's device node.
- addressed review comments.

v6:
- added otg specific APIs for host/gadget registration. behaviour of
original host/gadget API remains unchanged. Platform devices can now
pass the otg device explicitly while registering host/gadget.
- moved hcd specific operations from struct otg_fsm to struct hcd_ops.
- made struct usb_otg mandatory for all otg related APIs.
- allow otg controller to provide it's own otg_work function so that
it can implement it's own state machine.
- removed otg fsm and timers from usb-otg.c. Only dual-role state machine
is implemented.
- vbus is controlled in the dual-role state machine.
- PM runtime is used around drd_statemachine().
- added otg_dev to xhci platform data to allow platform code to specify
the otg controller tied to the xhci host controller.

v5: Internal version. Not sent to mailing list

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.

--
cheers,
-roger

Roger Quadros (13):
  usb: hcd: Initialize hcd->flags to 0
  usb: otg-fsm: Prevent build warning "VDBG" redefined
  usb: hcd.h: Add OTG to HCD interface
  usb: otg-fsm: use usb_otg wherever possible
  usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
  usb: gadget.h: Add OTG to gadget interface
  usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
  usb: otg: add OTG/dual-role core
  usb: of: add an API to get OTG device from USB controller node
  usb: otg: use dev_vdbg() instead of VDBG()
  usb: hcd: Adapt to OTG core
  usb: gadget: udc: adapt to OTG core
  usb: host: xhci-plat: Add otg device to platform data

Yoshihiro Shimoda (1):
  usb: otg: add hcd companion support

 Documentation/devicetree/bindings/usb/generic.txt |   6 +
 Documentation/usb/chipidea.txt                    |   2 +-
 drivers/usb/Kconfig                               |  18 +
 drivers/usb/Makefile                              |   1 +
 drivers/usb/chipidea/Makefile                     |   2 +-
 drivers/usb/chipidea/ci.h                         |   3 +-
 drivers/usb/chipidea/core.c                       |  14 +-
 drivers/usb/chipidea/debug.c                      |   2 +-
 drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
 drivers/usb/chipidea/otg_fsm.h                    |   2 +-
 drivers/usb/chipidea/udc.c                        |  17 +-
 drivers/usb/common/Makefile                       |   5 +-
 drivers/usb/common/common.c                       |  27 +
 drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
 drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
 drivers/usb/core/Kconfig                          |  22 -
 drivers/usb/core/hcd.c                            |  56 ++
 drivers/usb/gadget/Kconfig                        |   1 +
 drivers/usb/gadget/udc/core.c                     | 202 ++++-
 drivers/usb/host/xhci-plat.c                      |  35 +-
 drivers/usb/phy/Kconfig                           |   2 +-
 drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
 drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
 include/linux/usb/gadget.h                        |  22 +
 include/linux/usb/hcd.h                           |  29 +
 include/linux/usb/of.h                            |   9 +
 include/linux/usb/otg-fsm.h                       | 154 +---
 include/linux/usb/otg.h                           | 290 ++++++-
 include/linux/usb/xhci_pdriver.h                  |   3 +
 29 files changed, 1918 insertions(+), 462 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

-- 
2.7.4

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

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

* [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

When using the OTG/DRD library we can call hcd_add/remove
consecutively without calling usb_put_hcd/usb_create_hcd in between
so hcd->flags can be stale.

If the HC dies due to whatever reason then without this
patch we get the below error on next hcd_add.

[   91.494257] xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
[   91.502068] hub 3-0:1.0: state 0 ports 1 chg 0000 evt 0000
[   91.510240] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[   91.516940] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
[   91.529745] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
[   91.540637] usb usb4: New USB device found, idVendor=1d6b, idProduct=0003
[   91.757865] irq 254: nobody cared (try booting with the "irqpoll" option)
[   91.757880] CPU: 0 PID: 68 Comm: kworker/u2:2 Not tainted 4.1.4-00828-g1f0ed8c-dirty #44
[   91.757885] Hardware name: Generic AM43 (Flattened Device Tree)
[   91.757914] Workqueue: usb_otg usb_otg_work
[   91.757921] Backtrace:
[   91.757954] [<c0012af0>] (dump_backtrace) from [<c0012c8c>] (show_stack+0x18/0x1c)
[   91.757972]  r6:c089d4a4 r5:ffffffff r4:00000000 r3:ee440000
[   91.757991] [<c0012c74>] (show_stack) from [<c05f7c14>] (dump_stack+0x84/0xd0)
[   91.758008] [<c05f7b90>] (dump_stack) from [<c0084b30>] (__report_bad_irq+0x28/0xc8)
[   91.758024]  r7:00000000 r6:000000fe r5:00000000 r4:ee514c40
[   91.758037] [<c0084b08>] (__report_bad_irq) from [<c00850b0>] (note_interrupt+0x24c/0x2ac)
[   91.758052]  r6:000000fe r5:00000000 r4:ee514c40 r3:00000000
[   91.758065] [<c0084e64>] (note_interrupt) from [<c00828fc>] (handle_irq_event_percpu+0xb0/0x158)
[   91.758085]  r10:ee514c40 r9:c08ce49a r8:000000fe r7:00000000 r6:00000000 r5:00000000
[   91.758094]  r4:00000000 r3:00000000
[   91.758105] [<c008284c>] (handle_irq_event_percpu) from [<c00829e8>] (handle_irq_event+0x44/0x64)
[   91.758126]  r10:00000001 r9:ee441ab0 r8:ee441bb8 r7:c0858b4c r6:ed174280 r5:ee514ca0
[   91.758132]  r4:ee514c40
[   91.758144] [<c00829a4>] (handle_irq_event) from [<c0085970>] (handle_fasteoi_irq+0x100/0x1bc)
[   91.758159]  r6:c085dba0 r5:ee514ca0 r4:ee514c40 r3:00000000
[   91.758171] [<c0085870>] (handle_fasteoi_irq) from [<c0082058>] (generic_handle_irq+0x28/0x38)
[   91.758186]  r7:c0853d40 r6:c0858b4c r5:000000fe r4:000000fe
[   91.758197] [<c0082030>] (generic_handle_irq) from [<c00821c0>] (__handle_domain_irq+0x98/0x12c)
[   91.758207]  r4:c0853d40 r3:00000100
[   91.758219] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
[   91.758239]  r10:00000001 r9:ee441bb8 r8:fa240100 r7:c0858d70 r6:ee441ab0 r5:000000b8
[   91.758245]  r4:fa24010c
[   91.758264] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
[   91.758271] Exception stack(0xee441ab0 to 0xee441af8)
[   91.758280] 1aa0:                                     00000000 c08d2980 ee441ac0 00000000
[   91.758292] 1ac0: 00000008 00000089 c0858b4c c0858080 00000000 ee441bb8 00000001 ee441b3c
[   91.758301] 1ae0: 00000101 ee441af8 c02fc418 c0046a1c 20000113 ffffffff
[   91.758321]  r8:00000000 r7:ee441ae4 r6:ffffffff r5:20000113 r4:c0046a1c r3:c02fc418
[   91.758347] [<c00469a0>] (__do_softirq) from [<c0046eac>] (irq_exit+0xb8/0x104)
[   91.758367]  r10:00000001 r9:ee441bb8 r8:00000000 r7:c0853d40 r6:c0858b4c r5:00000089
[   91.758373]  r4:00000000
[   91.758386] [<c0046df4>] (irq_exit) from [<c00821c8>] (__handle_domain_irq+0xa0/0x12c)
[   91.758395]  r4:00000000 r3:00000100
[   91.758406] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
[   91.758426]  r10:c08e3510 r9:20000013 r8:fa240100 r7:c0858d70 r6:ee441bb8 r5:00000039
[   91.758433]  r4:fa24010c
[   91.758445] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
[   91.758450] Exception stack(0xee441bb8 to 0xee441c00)
[   91.758457] 1ba0:                                                       00000000 00000001
[   91.758468] 1bc0: 00000000 ee440000 c08e2524 0000004d 00000274 00000000 00000000 20000013
[   91.758479] 1be0: c08e3510 ee441c4c ee441b60 ee441c00 c03acfec c0080d4c 60000013 ffffffff
[   91.758499]  r8:00000000 r7:ee441bec r6:ffffffff r5:60000013 r4:c0080d4c r3:c03acfec
[   91.758524] [<c0080950>] (console_unlock) from [<c0081670>] (vprintk_emit+0x20c/0x500)
[   91.758544]  r10:ee441cc0 r9:c08d3550 r8:c08e3ea0 r7:00000000 r6:00000001 r5:0000003d
[   91.758551]  r4:c08d3550
[   91.758573] [<c0081464>] (vprintk_emit) from [<c03f6f70>] (dev_vprintk_emit+0x104/0x1ac)
[   91.758593]  r10:ee441d8c r9:0000000e r8:c07951e0 r7:00000006 r6:ee441cc0 r5:0000000d
[   91.758599]  r4:ee731068
[   91.758612] [<c03f6e6c>] (dev_vprintk_emit) from [<c03f7040>] (dev_printk_emit+0x28/0x30)
[   91.758632]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:ed429000 r6:00000006 r5:ee441dc0
[   91.758638]  r4:ee731068
[   91.758651] [<c03f701c>] (dev_printk_emit) from [<c03f7098>] (__dev_printk+0x50/0x70)
[   91.758660]  r3:bf2268cc r2:c07951e0
[   91.758673] [<c03f7048>] (__dev_printk) from [<c03f70f4>] (_dev_info+0x3c/0x48)
[   91.758686]  r6:00000000 r5:ee731068 r4:ee731000
[   91.758790] [<c03f70bc>] (_dev_info) from [<bf20ec3c>] (usb_new_device+0x11c/0x518 [usbcore])
[   91.758804]  r3:00000003 r2:00001d6b r1:bf225bc4
[   91.758881] [<bf20eb20>] (usb_new_device [usbcore]) from [<bf213560>] (usb_otg_add_hcd+0x514/0x7f8 [usbcore])
[   91.758903]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:000000fe r6:ed4290c8 r5:00000000
[   91.758909]  r4:ed429000
[   91.758957] [<bf21304c>] (usb_otg_add_hcd [usbcore]) from [<c047a238>] (usb_otg_start_host+0xb8/0xf8)
[   91.758978]  r10:00000000 r9:00000002 r8:00000000 r7:ee02b000 r6:ee452808 r5:ee452808
[   91.758985]  r4:ee452808
[   91.758997] [<c047a180>] (usb_otg_start_host) from [<c047a020>] (drd_set_protocol+0xac/0xd8)
[   91.759007]  r4:00000001 r3:c047a180
[   91.759018] [<c0479f74>] (drd_set_protocol) from [<c047a2ec>] (drd_set_state+0x74/0x98)
[   91.759027]  r5:ee452808 r4:00000009
[   91.759039] [<c047a278>] (drd_set_state) from [<c047a3dc>] (usb_otg_work+0xcc/0x154)
[   91.759054]  r6:ee452808 r5:ee4528b8 r4:ee452968 r3:00000000
[   91.759072] [<c047a310>] (usb_otg_work) from [<c005754c>] (process_one_work+0x128/0x340)
[   91.759087]  r6:ee02ac00 r5:ee452968 r4:ee42b900 r3:c047a310
[   91.759100] [<c0057424>] (process_one_work) from [<c00578f8>] (worker_thread+0x158/0x49c)
[   91.759120]  r10:ee42b900 r9:00000002 r8:ee02ac00 r7:00000088 r6:ee42b918 r5:ee02ac00
[   91.759127]  r4:ee02ac14
[   91.759145] [<c00577a0>] (worker_thread) from [<c005cc40>] (kthread+0xdc/0xf8)
[   91.759165]  r10:00000000 r9:00000000 r8:00000000 r7:c00577a0 r6:ee42b900 r5:ee429940
[   91.759174]  r4:00000000 r3:00000000
[   91.759190] [<c005cb64>] (kthread) from [<c000fc08>] (ret_from_fork+0x14/0x2c)
[   91.759206]  r7:00000000 r6:00000000 r5:c005cb64 r4:ee429940
[   91.759209] handlers:
[   91.759255] [<bf211b5c>] usb_hcd_irq [usbcore]
[   91.759260] Disabling IRQ #254

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/core/hcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 34b837a..ae6c76d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -3021,6 +3021,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	}
 
 	usb_put_invalidate_rhdev(hcd);
+	hcd->flags = 0;
 }
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
-- 
2.7.4

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

* [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

When using the OTG/DRD library we can call hcd_add/remove
consecutively without calling usb_put_hcd/usb_create_hcd in between
so hcd->flags can be stale.

If the HC dies due to whatever reason then without this
patch we get the below error on next hcd_add.

[   91.494257] xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
[   91.502068] hub 3-0:1.0: state 0 ports 1 chg 0000 evt 0000
[   91.510240] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[   91.516940] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
[   91.529745] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
[   91.540637] usb usb4: New USB device found, idVendor=1d6b, idProduct=0003
[   91.757865] irq 254: nobody cared (try booting with the "irqpoll" option)
[   91.757880] CPU: 0 PID: 68 Comm: kworker/u2:2 Not tainted 4.1.4-00828-g1f0ed8c-dirty #44
[   91.757885] Hardware name: Generic AM43 (Flattened Device Tree)
[   91.757914] Workqueue: usb_otg usb_otg_work
[   91.757921] Backtrace:
[   91.757954] [<c0012af0>] (dump_backtrace) from [<c0012c8c>] (show_stack+0x18/0x1c)
[   91.757972]  r6:c089d4a4 r5:ffffffff r4:00000000 r3:ee440000
[   91.757991] [<c0012c74>] (show_stack) from [<c05f7c14>] (dump_stack+0x84/0xd0)
[   91.758008] [<c05f7b90>] (dump_stack) from [<c0084b30>] (__report_bad_irq+0x28/0xc8)
[   91.758024]  r7:00000000 r6:000000fe r5:00000000 r4:ee514c40
[   91.758037] [<c0084b08>] (__report_bad_irq) from [<c00850b0>] (note_interrupt+0x24c/0x2ac)
[   91.758052]  r6:000000fe r5:00000000 r4:ee514c40 r3:00000000
[   91.758065] [<c0084e64>] (note_interrupt) from [<c00828fc>] (handle_irq_event_percpu+0xb0/0x158)
[   91.758085]  r10:ee514c40 r9:c08ce49a r8:000000fe r7:00000000 r6:00000000 r5:00000000
[   91.758094]  r4:00000000 r3:00000000
[   91.758105] [<c008284c>] (handle_irq_event_percpu) from [<c00829e8>] (handle_irq_event+0x44/0x64)
[   91.758126]  r10:00000001 r9:ee441ab0 r8:ee441bb8 r7:c0858b4c r6:ed174280 r5:ee514ca0
[   91.758132]  r4:ee514c40
[   91.758144] [<c00829a4>] (handle_irq_event) from [<c0085970>] (handle_fasteoi_irq+0x100/0x1bc)
[   91.758159]  r6:c085dba0 r5:ee514ca0 r4:ee514c40 r3:00000000
[   91.758171] [<c0085870>] (handle_fasteoi_irq) from [<c0082058>] (generic_handle_irq+0x28/0x38)
[   91.758186]  r7:c0853d40 r6:c0858b4c r5:000000fe r4:000000fe
[   91.758197] [<c0082030>] (generic_handle_irq) from [<c00821c0>] (__handle_domain_irq+0x98/0x12c)
[   91.758207]  r4:c0853d40 r3:00000100
[   91.758219] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
[   91.758239]  r10:00000001 r9:ee441bb8 r8:fa240100 r7:c0858d70 r6:ee441ab0 r5:000000b8
[   91.758245]  r4:fa24010c
[   91.758264] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
[   91.758271] Exception stack(0xee441ab0 to 0xee441af8)
[   91.758280] 1aa0:                                     00000000 c08d2980 ee441ac0 00000000
[   91.758292] 1ac0: 00000008 00000089 c0858b4c c0858080 00000000 ee441bb8 00000001 ee441b3c
[   91.758301] 1ae0: 00000101 ee441af8 c02fc418 c0046a1c 20000113 ffffffff
[   91.758321]  r8:00000000 r7:ee441ae4 r6:ffffffff r5:20000113 r4:c0046a1c r3:c02fc418
[   91.758347] [<c00469a0>] (__do_softirq) from [<c0046eac>] (irq_exit+0xb8/0x104)
[   91.758367]  r10:00000001 r9:ee441bb8 r8:00000000 r7:c0853d40 r6:c0858b4c r5:00000089
[   91.758373]  r4:00000000
[   91.758386] [<c0046df4>] (irq_exit) from [<c00821c8>] (__handle_domain_irq+0xa0/0x12c)
[   91.758395]  r4:00000000 r3:00000100
[   91.758406] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
[   91.758426]  r10:c08e3510 r9:20000013 r8:fa240100 r7:c0858d70 r6:ee441bb8 r5:00000039
[   91.758433]  r4:fa24010c
[   91.758445] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
[   91.758450] Exception stack(0xee441bb8 to 0xee441c00)
[   91.758457] 1ba0:                                                       00000000 00000001
[   91.758468] 1bc0: 00000000 ee440000 c08e2524 0000004d 00000274 00000000 00000000 20000013
[   91.758479] 1be0: c08e3510 ee441c4c ee441b60 ee441c00 c03acfec c0080d4c 60000013 ffffffff
[   91.758499]  r8:00000000 r7:ee441bec r6:ffffffff r5:60000013 r4:c0080d4c r3:c03acfec
[   91.758524] [<c0080950>] (console_unlock) from [<c0081670>] (vprintk_emit+0x20c/0x500)
[   91.758544]  r10:ee441cc0 r9:c08d3550 r8:c08e3ea0 r7:00000000 r6:00000001 r5:0000003d
[   91.758551]  r4:c08d3550
[   91.758573] [<c0081464>] (vprintk_emit) from [<c03f6f70>] (dev_vprintk_emit+0x104/0x1ac)
[   91.758593]  r10:ee441d8c r9:0000000e r8:c07951e0 r7:00000006 r6:ee441cc0 r5:0000000d
[   91.758599]  r4:ee731068
[   91.758612] [<c03f6e6c>] (dev_vprintk_emit) from [<c03f7040>] (dev_printk_emit+0x28/0x30)
[   91.758632]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:ed429000 r6:00000006 r5:ee441dc0
[   91.758638]  r4:ee731068
[   91.758651] [<c03f701c>] (dev_printk_emit) from [<c03f7098>] (__dev_printk+0x50/0x70)
[   91.758660]  r3:bf2268cc r2:c07951e0
[   91.758673] [<c03f7048>] (__dev_printk) from [<c03f70f4>] (_dev_info+0x3c/0x48)
[   91.758686]  r6:00000000 r5:ee731068 r4:ee731000
[   91.758790] [<c03f70bc>] (_dev_info) from [<bf20ec3c>] (usb_new_device+0x11c/0x518 [usbcore])
[   91.758804]  r3:00000003 r2:00001d6b r1:bf225bc4
[   91.758881] [<bf20eb20>] (usb_new_device [usbcore]) from [<bf213560>] (usb_otg_add_hcd+0x514/0x7f8 [usbcore])
[   91.758903]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:000000fe r6:ed4290c8 r5:00000000
[   91.758909]  r4:ed429000
[   91.758957] [<bf21304c>] (usb_otg_add_hcd [usbcore]) from [<c047a238>] (usb_otg_start_host+0xb8/0xf8)
[   91.758978]  r10:00000000 r9:00000002 r8:00000000 r7:ee02b000 r6:ee452808 r5:ee452808
[   91.758985]  r4:ee452808
[   91.758997] [<c047a180>] (usb_otg_start_host) from [<c047a020>] (drd_set_protocol+0xac/0xd8)
[   91.759007]  r4:00000001 r3:c047a180
[   91.759018] [<c0479f74>] (drd_set_protocol) from [<c047a2ec>] (drd_set_state+0x74/0x98)
[   91.759027]  r5:ee452808 r4:00000009
[   91.759039] [<c047a278>] (drd_set_state) from [<c047a3dc>] (usb_otg_work+0xcc/0x154)
[   91.759054]  r6:ee452808 r5:ee4528b8 r4:ee452968 r3:00000000
[   91.759072] [<c047a310>] (usb_otg_work) from [<c005754c>] (process_one_work+0x128/0x340)
[   91.759087]  r6:ee02ac00 r5:ee452968 r4:ee42b900 r3:c047a310
[   91.759100] [<c0057424>] (process_one_work) from [<c00578f8>] (worker_thread+0x158/0x49c)
[   91.759120]  r10:ee42b900 r9:00000002 r8:ee02ac00 r7:00000088 r6:ee42b918 r5:ee02ac00
[   91.759127]  r4:ee02ac14
[   91.759145] [<c00577a0>] (worker_thread) from [<c005cc40>] (kthread+0xdc/0xf8)
[   91.759165]  r10:00000000 r9:00000000 r8:00000000 r7:c00577a0 r6:ee42b900 r5:ee429940
[   91.759174]  r4:00000000 r3:00000000
[   91.759190] [<c005cb64>] (kthread) from [<c000fc08>] (ret_from_fork+0x14/0x2c)
[   91.759206]  r7:00000000 r6:00000000 r5:c005cb64 r4:ee429940
[   91.759209] handlers:
[   91.759255] [<bf211b5c>] usb_hcd_irq [usbcore]
[   91.759260] Disabling IRQ #254

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/core/hcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 34b837a..ae6c76d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -3021,6 +3021,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	}
 
 	usb_put_invalidate_rhdev(hcd);
+	hcd->flags = 0;
 }
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
-- 
2.7.4

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

* [PATCH v10 02/14] usb: otg-fsm: Prevent build warning "VDBG" redefined
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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 defining VDBG locally.

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@nxp.com>
---
 drivers/usb/common/usb-otg-fsm.c |  7 +++++++
 drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
 include/linux/usb/otg-fsm.h      | 15 ---------------
 3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 9059b7d..199dee0 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -30,6 +30,13 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+				 __func__, ## args)
+#else
+#define VDBG(stuff...)	do {} while (0)
+#endif
+
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 94eb292..a8784ec 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -44,6 +44,13 @@
 
 #include "phy-fsl-usb.h"
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+				 __func__, ## args)
+#else
+#define VDBG(stuff...)	do {} while (0)
+#endif
+
 #define DRIVER_VERSION "Rev. 1.55"
 #define DRIVER_AUTHOR "Jerry Huang/Li Yang"
 #define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 7a03505..a0a8f87 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -21,21 +21,6 @@
 #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)
-- 
2.7.4

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

* [PATCH v10 02/14] usb: otg-fsm: Prevent build warning "VDBG" redefined
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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 defining VDBG locally.

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@nxp.com>
---
 drivers/usb/common/usb-otg-fsm.c |  7 +++++++
 drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
 include/linux/usb/otg-fsm.h      | 15 ---------------
 3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 9059b7d..199dee0 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -30,6 +30,13 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+				 __func__, ## args)
+#else
+#define VDBG(stuff...)	do {} while (0)
+#endif
+
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 94eb292..a8784ec 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -44,6 +44,13 @@
 
 #include "phy-fsl-usb.h"
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+				 __func__, ## args)
+#else
+#define VDBG(stuff...)	do {} while (0)
+#endif
+
 #define DRIVER_VERSION "Rev. 1.55"
 #define DRIVER_AUTHOR "Jerry Huang/Li Yang"
 #define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 7a03505..a0a8f87 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -21,21 +21,6 @@
 #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)
-- 
2.7.4

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

* [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

The OTG core will use struct otg_hcd_ops to interface
with the HCD (Host Controller Driver).

The main purpose of this interface is to avoid directly
calling HCD APIs 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>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 66fc137..7729c1f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -400,6 +400,30 @@ struct hc_driver {
 
 };
 
+/**
+ * struct otg_hcd_ops - Interface between OTG core and HCD
+ *
+ * Provided by the HCD core to allow the OTG core to interface with the HCD
+ *
+ * @add: function to add the HCD
+ * @remove: function to remove the HCD
+ * @usb_bus_start_enum: function to immediately start bus enumeration
+ * @usb_control_msg: function to build and send a control URB
+ * @usb_hub_find_child: function to get pointer to the child device
+ */
+struct otg_hcd_ops {
+	int (*add)(struct usb_hcd *hcd,
+		   unsigned int irqnum, unsigned long irqflags);
+	void (*remove)(struct usb_hcd *hcd);
+	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int port_num);
+	int (*usb_control_msg)(struct usb_device *dev, unsigned int pipe,
+			       __u8 request, __u8 requesttype, __u16 value,
+			       __u16 index, void *data, __u16 size,
+			       int timeout);
+	struct usb_device * (*usb_hub_find_child)(struct usb_device *hdev,
+						  int port1);
+};
+
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
 {
 	return hcd->driver->flags & HCD_BH;
-- 
2.7.4

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

* [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

The OTG core will use struct otg_hcd_ops to interface
with the HCD (Host Controller Driver).

The main purpose of this interface is to avoid directly
calling HCD APIs 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>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 66fc137..7729c1f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -400,6 +400,30 @@ struct hc_driver {
 
 };
 
+/**
+ * struct otg_hcd_ops - Interface between OTG core and HCD
+ *
+ * Provided by the HCD core to allow the OTG core to interface with the HCD
+ *
+ * @add: function to add the HCD
+ * @remove: function to remove the HCD
+ * @usb_bus_start_enum: function to immediately start bus enumeration
+ * @usb_control_msg: function to build and send a control URB
+ * @usb_hub_find_child: function to get pointer to the child device
+ */
+struct otg_hcd_ops {
+	int (*add)(struct usb_hcd *hcd,
+		   unsigned int irqnum, unsigned long irqflags);
+	void (*remove)(struct usb_hcd *hcd);
+	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int port_num);
+	int (*usb_control_msg)(struct usb_device *dev, unsigned int pipe,
+			       __u8 request, __u8 requesttype, __u16 value,
+			       __u16 index, void *data, __u16 size,
+			       int timeout);
+	struct usb_device * (*usb_hub_find_child)(struct usb_device *hdev,
+						  int port1);
+};
+
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
 {
 	return hcd->driver->flags & HCD_BH;
-- 
2.7.4

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

* [PATCH v10 04/14] usb: otg-fsm: use usb_otg wherever possible
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Move otg_fsm into usb_otg and use usb_otg wherever possible
in the usb_otg APIs.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/chipidea/ci.h        |   1 -
 drivers/usb/chipidea/core.c      |  14 +--
 drivers/usb/chipidea/debug.c     |   2 +-
 drivers/usb/chipidea/otg_fsm.c   | 169 ++++++++++++++++++------------------
 drivers/usb/chipidea/udc.c       |  17 ++--
 drivers/usb/common/usb-otg-fsm.c | 180 ++++++++++++++++++++-------------------
 drivers/usb/phy/phy-fsl-usb.c    | 141 +++++++++++++++---------------
 drivers/usb/phy/phy-fsl-usb.h    |   3 +-
 include/linux/usb/otg-fsm.h      | 132 +++-------------------------
 include/linux/usb/otg.h          | 107 +++++++++++++++++++++++
 10 files changed, 383 insertions(+), 383 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index cd41455..c523975 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -209,7 +209,6 @@ struct ci_hdrc {
 	enum ci_role			role;
 	bool				is_otg;
 	struct usb_otg			otg;
-	struct otg_fsm			fsm;
 	struct hrtimer			otg_fsm_hrtimer;
 	ktime_t				hr_timeouts[NUM_OTG_FSM_TIMERS];
 	unsigned			enabled_otg_timer_bits;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 69426e6..56b6ac6 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -1085,8 +1085,8 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 /* Prepare wakeup by SRP before suspend */
 static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
 {
-	if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
-				!hw_read_otgsc(ci, OTGSC_ID)) {
+	if ((ci->otg.state == OTG_STATE_A_IDLE) &&
+	    !hw_read_otgsc(ci, OTGSC_ID)) {
 		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
 								PORTSC_PP);
 		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN,
@@ -1097,13 +1097,13 @@ static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
 /* Handle SRP when wakeup by data pulse */
 static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
 {
-	if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
-		(ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
+	if ((ci->otg.state == OTG_STATE_A_IDLE) &&
+	    (ci->otg.fsm.a_bus_drop == 1) && (ci->otg.fsm.a_bus_req == 0)) {
 		if (!hw_read_otgsc(ci, OTGSC_ID)) {
-			ci->fsm.a_srp_det = 1;
-			ci->fsm.a_bus_drop = 0;
+			ci->otg.fsm.a_srp_det = 1;
+			ci->otg.fsm.a_bus_drop = 0;
 		} else {
-			ci->fsm.id = 1;
+			ci->otg.fsm.id = 1;
 		}
 		ci_otg_queue_work(ci);
 	}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 6d23eed..374cdaa 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -224,7 +224,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
 	if (!ci || !ci_otg_is_fsm_mode(ci))
 		return 0;
 
-	fsm = &ci->fsm;
+	fsm = &ci->otg.fsm;
 
 	/* ------ State ----- */
 	seq_printf(s, "OTG state: %s\n\n",
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index de8e22e..1c0c750 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -40,7 +40,7 @@ get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.a_bus_req);
 	size -= t;
 	next += t;
 
@@ -56,25 +56,25 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0') {
-		ci->fsm.a_bus_req = 0;
+		ci->otg.fsm.a_bus_req = 0;
 	} else if (buf[0] == '1') {
 		/* If a_bus_drop is TRUE, a_bus_req can't be set */
-		if (ci->fsm.a_bus_drop) {
-			mutex_unlock(&ci->fsm.lock);
+		if (ci->otg.fsm.a_bus_drop) {
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
-		ci->fsm.a_bus_req = 1;
-		if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+		ci->otg.fsm.a_bus_req = 1;
+		if (ci->otg.state == OTG_STATE_A_PERIPHERAL) {
 			ci->gadget.host_request_flag = 1;
-			mutex_unlock(&ci->fsm.lock);
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -89,7 +89,7 @@ get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.a_bus_drop);
 	size -= t;
 	next += t;
 
@@ -105,16 +105,16 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0') {
-		ci->fsm.a_bus_drop = 0;
+		ci->otg.fsm.a_bus_drop = 0;
 	} else if (buf[0] == '1') {
-		ci->fsm.a_bus_drop = 1;
-		ci->fsm.a_bus_req = 0;
+		ci->otg.fsm.a_bus_drop = 1;
+		ci->otg.fsm.a_bus_req = 0;
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -130,7 +130,7 @@ get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.b_bus_req);
 	size -= t;
 	next += t;
 
@@ -146,20 +146,20 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0')
-		ci->fsm.b_bus_req = 0;
+		ci->otg.fsm.b_bus_req = 0;
 	else if (buf[0] == '1') {
-		ci->fsm.b_bus_req = 1;
-		if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+		ci->otg.fsm.b_bus_req = 1;
+		if (ci->otg.state == OTG_STATE_B_PERIPHERAL) {
 			ci->gadget.host_request_flag = 1;
-			mutex_unlock(&ci->fsm.lock);
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -174,12 +174,12 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '1')
-		ci->fsm.a_clr_err = 1;
+		ci->otg.fsm.a_clr_err = 1;
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -287,64 +287,64 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
 /* OTG FSM timer handlers */
 static int a_wait_vrise_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_vrise_tmout = 1;
+	ci->otg.fsm.a_wait_vrise_tmout = 1;
 	return 0;
 }
 
 static int a_wait_vfall_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_vfall_tmout = 1;
+	ci->otg.fsm.a_wait_vfall_tmout = 1;
 	return 0;
 }
 
 static int a_wait_bcon_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_bcon_tmout = 1;
+	ci->otg.fsm.a_wait_bcon_tmout = 1;
 	return 0;
 }
 
 static int a_aidl_bdis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_aidl_bdis_tmout = 1;
+	ci->otg.fsm.a_aidl_bdis_tmout = 1;
 	return 0;
 }
 
 static int b_ase0_brst_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_ase0_brst_tmout = 1;
+	ci->otg.fsm.b_ase0_brst_tmout = 1;
 	return 0;
 }
 
 static int a_bidl_adis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_bidl_adis_tmout = 1;
+	ci->otg.fsm.a_bidl_adis_tmout = 1;
 	return 0;
 }
 
 static int b_aidl_bdis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_bus_suspend = 1;
+	ci->otg.fsm.a_bus_suspend = 1;
 	return 0;
 }
 
 static int b_se0_srp_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_se0_srp = 1;
+	ci->otg.fsm.b_se0_srp = 1;
 	return 0;
 }
 
 static int b_srp_fail_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_srp_done = 1;
+	ci->otg.fsm.b_srp_done = 1;
 	return 1;
 }
 
 static int b_data_pls_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_srp_done = 1;
-	ci->fsm.b_bus_req = 0;
-	if (ci->fsm.power_up)
-		ci->fsm.power_up = 0;
+	ci->otg.fsm.b_srp_done = 1;
+	ci->otg.fsm.b_bus_req = 0;
+	if (ci->otg.fsm.power_up)
+		ci->otg.fsm.power_up = 0;
 	hw_write_otgsc(ci, OTGSC_HABA, 0);
 	pm_runtime_put(ci->dev);
 	return 0;
@@ -352,9 +352,9 @@ static int b_data_pls_tmout(struct ci_hdrc *ci)
 
 static int b_ssend_srp_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_ssend_srp = 1;
+	ci->otg.fsm.b_ssend_srp = 1;
 	/* only vbus fall below B_sess_vld in b_idle state */
-	if (ci->fsm.otg->state == OTG_STATE_B_IDLE)
+	if (ci->otg.state == OTG_STATE_B_IDLE)
 		return 0;
 	else
 		return 1;
@@ -435,18 +435,18 @@ static int ci_otg_init_timers(struct ci_hdrc *ci)
 /* -------------------------------------------------------------*/
 /* Operations that will be called from OTG Finite State Machine */
 /* -------------------------------------------------------------*/
-static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void ci_otg_fsm_add_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (t < NUM_OTG_FSM_TIMERS)
 		ci_otg_add_timer(ci, t);
 	return;
 }
 
-static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void ci_otg_fsm_del_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (t < NUM_OTG_FSM_TIMERS)
 		ci_otg_del_timer(ci, t);
@@ -457,10 +457,10 @@ static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
  * A-device drive vbus: turn on vbus regulator and enable port power
  * Data pulse irq should be disabled while vbus is on.
  */
-static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
+static void ci_otg_drv_vbus(struct usb_otg *otg, int on)
 {
 	int ret;
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on) {
 		/* Enable power power */
@@ -478,23 +478,23 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
 		/* Disable data pulse irq */
 		hw_write_otgsc(ci, OTGSC_DPIE, 0);
 
-		fsm->a_srp_det = 0;
-		fsm->power_up = 0;
+		otg->fsm.a_srp_det = 0;
+		otg->fsm.power_up = 0;
 	} else {
 		if (ci->platdata->reg_vbus)
 			regulator_disable(ci->platdata->reg_vbus);
 
-		fsm->a_bus_drop = 1;
-		fsm->a_bus_req = 0;
+		otg->fsm.a_bus_drop = 1;
+		otg->fsm.a_bus_req = 0;
 	}
 }
 
 /*
  * Control data line by Run Stop bit.
  */
-static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
+static void ci_otg_loc_conn(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on)
 		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
@@ -511,14 +511,14 @@ static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
  * so the usb device class driver need support autosuspend,
  * otherwise the bus suspend will not happen.
  */
-static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
+static void ci_otg_loc_sof(struct usb_otg *otg, int on)
 {
 	struct usb_device *udev;
 
-	if (!fsm->otg->host)
+	if (!otg->host)
 		return;
 
-	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+	udev = usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev)
 		return;
 
@@ -534,9 +534,9 @@ static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
  * Start SRP pulsing by data-line pulsing,
  * no v-bus pulsing followed
  */
-static void ci_otg_start_pulse(struct otg_fsm *fsm)
+static void ci_otg_start_pulse(struct usb_otg *otg)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	/* Hardware Assistant Data pulse */
 	hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP);
@@ -545,9 +545,9 @@ static void ci_otg_start_pulse(struct otg_fsm *fsm)
 	ci_otg_add_timer(ci, B_DATA_PLS);
 }
 
-static int ci_otg_start_host(struct otg_fsm *fsm, int on)
+static int ci_otg_start_host(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on) {
 		ci_role_stop(ci);
@@ -559,9 +559,9 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
 	return 0;
 }
 
-static int ci_otg_start_gadget(struct otg_fsm *fsm, int on)
+static int ci_otg_start_gadget(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on)
 		usb_gadget_vbus_connect(&ci->gadget);
@@ -588,13 +588,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 	 * Don't do fsm transition for B device
 	 * when there is no gadget class driver
 	 */
-	if (ci->fsm.id && !(ci->driver) &&
-		ci->fsm.otg->state < OTG_STATE_A_IDLE)
+	if (ci->otg.fsm.id && !(ci->driver) &&
+	    ci->otg.state < OTG_STATE_A_IDLE)
 		return 0;
 
 	pm_runtime_get_sync(ci->dev);
-	if (otg_statemachine(&ci->fsm)) {
-		if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
+	if (otg_statemachine(&ci->otg)) {
+		if (ci->otg.state == OTG_STATE_A_IDLE) {
 			/*
 			 * Further state change for cases:
 			 * a_idle to b_idle; or
@@ -603,8 +603,8 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 			 * consequently; or
 			 * a_idle to a_wait_vrise when power up
 			 */
-			if ((ci->fsm.id) || (ci->id_event) ||
-						(ci->fsm.power_up)) {
+			if ((ci->otg.fsm.id) || (ci->id_event) ||
+			    (ci->otg.fsm.power_up)) {
 				ci_otg_queue_work(ci);
 			} else {
 				/* Enable data pulse irq */
@@ -615,16 +615,16 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 			}
 			if (ci->id_event)
 				ci->id_event = false;
-		} else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
-			if (ci->fsm.b_sess_vld) {
-				ci->fsm.power_up = 0;
+		} else if (ci->otg.state == OTG_STATE_B_IDLE) {
+			if (ci->otg.fsm.b_sess_vld) {
+				ci->otg.fsm.power_up = 0;
 				/*
 				 * Further transite to b_periphearl state
 				 * when register gadget driver with vbus on
 				 */
 				ci_otg_queue_work(ci);
 			}
-		} else if (ci->fsm.otg->state == OTG_STATE_A_HOST) {
+		} else if (ci->otg.state == OTG_STATE_A_HOST) {
 			pm_runtime_mark_last_busy(ci->dev);
 			pm_runtime_put_autosuspend(ci->dev);
 			return 0;
@@ -641,13 +641,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 static void ci_otg_fsm_event(struct ci_hdrc *ci)
 {
 	u32 intr_sts, otg_bsess_vld, port_conn;
-	struct otg_fsm *fsm = &ci->fsm;
+	struct otg_fsm *fsm = &ci->otg.fsm;
 
 	intr_sts = hw_read_intr_status(ci);
 	otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV);
 	port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS);
 
-	switch (ci->fsm.otg->state) {
+	switch (ci->otg.state) {
 	case OTG_STATE_A_WAIT_BCON:
 		if (port_conn) {
 			fsm->b_conn = 1;
@@ -737,7 +737,7 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci)
 {
 	irqreturn_t retval =  IRQ_NONE;
 	u32 otgsc, otg_int_src = 0;
-	struct otg_fsm *fsm = &ci->fsm;
+	struct otg_fsm *fsm = &ci->otg.fsm;
 
 	otgsc = hw_read_otgsc(ci, ~0);
 	otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8);
@@ -800,17 +800,16 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 		ci->otg.usb_phy = ci->usb_phy;
 
 	ci->otg.gadget = &ci->gadget;
-	ci->fsm.otg = &ci->otg;
-	ci->fsm.power_up = 1;
-	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->otg.fsm.power_up = 1;
+	ci->otg.fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
+	ci->otg.state = OTG_STATE_UNDEFINED;
+	ci->otg.fsm.ops = &ci_otg_ops;
 	ci->gadget.hnp_polling_support = 1;
-	ci->fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
-	if (!ci->fsm.host_req_flag)
+	ci->otg.fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
+	if (!ci->otg.fsm.host_req_flag)
 		return -ENOMEM;
 
-	mutex_init(&ci->fsm.lock);
+	mutex_init(&ci->otg.fsm.lock);
 
 	retval = ci_otg_init_timers(ci);
 	if (retval) {
@@ -830,10 +829,10 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 	/* Enable A vbus valid irq */
 	hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE);
 
-	if (ci->fsm.id) {
-		ci->fsm.b_ssend_srp =
+	if (ci->otg.fsm.id) {
+		ci->otg.fsm.b_ssend_srp =
 			hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1;
-		ci->fsm.b_sess_vld =
+		ci->otg.fsm.b_sess_vld =
 			hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0;
 		/* Enable BSV irq */
 		hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 065f5d9..7a6b0b5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -20,6 +20,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 #include <linux/usb/chipidea.h>
 
@@ -1739,7 +1740,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
 	ci->driver = driver;
 
 	/* Start otg fsm for B-device */
-	if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) {
+	if (ci_otg_is_fsm_mode(ci) && ci->otg.fsm.id) {
 		ci_hdrc_otg_fsm_start(ci);
 		return retval;
 	}
@@ -1767,15 +1768,15 @@ static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
 	if (!ci_otg_is_fsm_mode(ci))
 		return;
 
-	mutex_lock(&ci->fsm.lock);
-	if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
-		ci->fsm.a_bidl_adis_tmout = 1;
+	mutex_lock(&ci->otg.fsm.lock);
+	if (ci->otg.state == OTG_STATE_A_PERIPHERAL) {
+		ci->otg.fsm.a_bidl_adis_tmout = 1;
 		ci_hdrc_otg_fsm_start(ci);
-	} else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
-		ci->fsm.protocol = PROTO_UNDEF;
-		ci->fsm.otg->state = OTG_STATE_UNDEFINED;
+	} else if (ci->otg.state == OTG_STATE_B_PERIPHERAL) {
+		ci->otg.fsm.protocol = PROTO_UNDEF;
+		ci->otg.state = OTG_STATE_UNDEFINED;
 	}
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 }
 
 /**
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 199dee0..610b5bd6 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -40,6 +40,7 @@
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
 	int ret = 0;
 
 	if (fsm->protocol != protocol) {
@@ -47,17 +48,17 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 			fsm->protocol, protocol);
 		/* stop old protocol */
 		if (fsm->protocol == PROTO_HOST)
-			ret = otg_start_host(fsm, 0);
+			ret = otg_start_host(otg, 0);
 		else if (fsm->protocol == PROTO_GADGET)
-			ret = otg_start_gadget(fsm, 0);
+			ret = otg_start_gadget(otg, 0);
 		if (ret)
 			return ret;
 
 		/* start new protocol */
 		if (protocol == PROTO_HOST)
-			ret = otg_start_host(fsm, 1);
+			ret = otg_start_host(otg, 1);
 		else if (protocol == PROTO_GADGET)
-			ret = otg_start_gadget(fsm, 1);
+			ret = otg_start_gadget(otg, 1);
 		if (ret)
 			return ret;
 
@@ -71,9 +72,11 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 /* 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)
 {
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
 	switch (old_state) {
 	case OTG_STATE_B_IDLE:
-		otg_del_timer(fsm, B_SE0_SRP);
+		otg_del_timer(otg, B_SE0_SRP);
 		fsm->b_se0_srp = 0;
 		fsm->adp_sns = 0;
 		fsm->adp_prb = 0;
@@ -83,11 +86,11 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 		fsm->b_srp_done = 0;
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		if (fsm->otg->gadget)
-			fsm->otg->gadget->host_request_flag = 0;
+		if (otg->gadget)
+			otg->gadget->host_request_flag = 0;
 		break;
 	case OTG_STATE_B_WAIT_ACON:
-		otg_del_timer(fsm, B_ASE0_BRST);
+		otg_del_timer(otg, B_ASE0_BRST);
 		fsm->b_ase0_brst_tmout = 0;
 		break;
 	case OTG_STATE_B_HOST:
@@ -96,31 +99,31 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 		fsm->adp_prb = 0;
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
-		otg_del_timer(fsm, A_WAIT_VRISE);
+		otg_del_timer(otg, A_WAIT_VRISE);
 		fsm->a_wait_vrise_tmout = 0;
 		break;
 	case OTG_STATE_A_WAIT_BCON:
-		otg_del_timer(fsm, A_WAIT_BCON);
+		otg_del_timer(otg, A_WAIT_BCON);
 		fsm->a_wait_bcon_tmout = 0;
 		break;
 	case OTG_STATE_A_HOST:
-		otg_del_timer(fsm, A_WAIT_ENUM);
+		otg_del_timer(otg, A_WAIT_ENUM);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		otg_del_timer(fsm, A_AIDL_BDIS);
+		otg_del_timer(otg, A_AIDL_BDIS);
 		fsm->a_aidl_bdis_tmout = 0;
 		fsm->a_suspend_req_inf = 0;
 		break;
 	case OTG_STATE_A_PERIPHERAL:
-		otg_del_timer(fsm, A_BIDL_ADIS);
+		otg_del_timer(otg, A_BIDL_ADIS);
 		fsm->a_bidl_adis_tmout = 0;
-		if (fsm->otg->gadget)
-			fsm->otg->gadget->host_request_flag = 0;
+		if (otg->gadget)
+			otg->gadget->host_request_flag = 0;
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		otg_del_timer(fsm, A_WAIT_VFALL);
+		otg_del_timer(otg, A_WAIT_VFALL);
 		fsm->a_wait_vfall_tmout = 0;
-		otg_del_timer(fsm, A_WAIT_VRISE);
+		otg_del_timer(otg, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
 		break;
@@ -133,17 +136,18 @@ static void otg_hnp_polling_work(struct work_struct *work)
 {
 	struct otg_fsm *fsm = container_of(to_delayed_work(work),
 				struct otg_fsm, hnp_polling_work);
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
 	struct usb_device *udev;
-	enum usb_otg_state state = fsm->otg->state;
+	enum usb_otg_state state = otg->state;
 	u8 flag;
 	int retval;
 
 	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
 		return;
 
-	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+	udev = usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev) {
-		dev_err(fsm->otg->host->controller,
+		dev_err(otg->host->controller,
 			"no usb dev connected, can't start HNP polling\n");
 		return;
 	}
@@ -178,7 +182,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	/* Host request flag is set */
 	if (state == OTG_STATE_A_HOST) {
 		/* Set b_hnp_enable */
-		if (!fsm->otg->host->b_hnp_enable) {
+		if (!otg->host->b_hnp_enable) {
 			retval = usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_SET_FEATURE, 0,
@@ -186,14 +190,14 @@ static void otg_hnp_polling_work(struct work_struct *work)
 					0, NULL, 0,
 					USB_CTRL_SET_TIMEOUT);
 			if (retval >= 0)
-				fsm->otg->host->b_hnp_enable = 1;
+				otg->host->b_hnp_enable = 1;
 		}
 		fsm->a_bus_req = 0;
 	} else if (state == OTG_STATE_B_HOST) {
 		fsm->b_bus_req = 0;
 	}
 
-	otg_statemachine(fsm);
+	otg_statemachine(otg);
 }
 
 static void otg_start_hnp_polling(struct otg_fsm *fsm)
@@ -213,133 +217,135 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm)
 /* Called when entering a state */
 static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 {
-	if (fsm->otg->state == new_state)
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
 		return 0;
 	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
-	otg_leave_state(fsm, fsm->otg->state);
+	otg_leave_state(fsm, otg->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
-		otg_drv_vbus(fsm, 0);
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		/*
 		 * Driver is responsible for starting ADP probing
 		 * if ADP sensing times out.
 		 */
-		otg_start_adp_sns(fsm);
+		otg_start_adp_sns(otg);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, B_SE0_SRP);
+		otg_add_timer(otg, B_SE0_SRP);
 		break;
 	case OTG_STATE_B_SRP_INIT:
-		otg_start_pulse(fsm);
-		otg_loc_sof(fsm, 0);
+		otg_start_pulse(otg);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, B_SRP_FAIL);
+		otg_add_timer(otg, B_SRP_FAIL);
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_GADGET);
-		otg_loc_conn(fsm, 1);
+		otg_loc_conn(otg, 1);
 		break;
 	case OTG_STATE_B_WAIT_ACON:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, B_ASE0_BRST);
+		otg_add_timer(otg, B_ASE0_BRST);
 		fsm->a_bus_suspend = 0;
 		break;
 	case OTG_STATE_B_HOST:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 1);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(fsm->otg->host,
-				fsm->otg->host->otg_port);
+		usb_bus_start_enum(otg->host, otg->host->otg_port);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_IDLE:
-		otg_drv_vbus(fsm, 0);
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
-		otg_start_adp_prb(fsm);
+		otg_drv_vbus(otg, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
+		otg_start_adp_prb(otg);
 		otg_set_protocol(fsm, PROTO_HOST);
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_VRISE);
+		otg_add_timer(otg, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_WAIT_BCON:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_BCON);
+		otg_add_timer(otg, A_WAIT_BCON);
 		break;
 	case OTG_STATE_A_HOST:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 1);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
 		/*
 		 * When HNP is triggered while a_bus_req = 0, a_host will
 		 * suspend too fast to complete a_set_b_hnp_en
 		 */
 		if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
-			otg_add_timer(fsm, A_WAIT_ENUM);
+			otg_add_timer(otg, A_WAIT_ENUM);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_AIDL_BDIS);
+		otg_add_timer(otg, A_AIDL_BDIS);
 
 		break;
 	case OTG_STATE_A_PERIPHERAL:
-		otg_loc_sof(fsm, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_GADGET);
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 1);
-		otg_add_timer(fsm, A_BIDL_ADIS);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 1);
+		otg_add_timer(otg, A_BIDL_ADIS);
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		otg_drv_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_VFALL);
+		otg_add_timer(otg, A_WAIT_VFALL);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
-		otg_drv_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_UNDEF);
 		break;
 	default:
 		break;
 	}
 
-	fsm->otg->state = new_state;
+	otg->state = new_state;
 	fsm->state_changed = 1;
 	return 0;
 }
 
 /* State change judgement */
-int otg_statemachine(struct otg_fsm *fsm)
+int otg_statemachine(struct usb_otg *otg)
 {
 	enum usb_otg_state state;
+	struct otg_fsm *fsm = &otg->fsm;
 
 	mutex_lock(&fsm->lock);
 
-	state = fsm->otg->state;
+	state = otg->state;
 	fsm->state_changed = 0;
 	/* State machine state change judgement */
 
@@ -354,7 +360,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_B_IDLE:
 		if (!fsm->id)
 			otg_set_state(fsm, OTG_STATE_A_IDLE);
-		else if (fsm->b_sess_vld && fsm->otg->gadget)
+		else if (fsm->b_sess_vld && otg->gadget)
 			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
 		else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
 				fsm->b_ssend_srp && fsm->b_se0_srp)
@@ -367,8 +373,8 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_B_PERIPHERAL:
 		if (!fsm->id || !fsm->b_sess_vld)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
-		else if (fsm->b_bus_req && fsm->otg->
-				gadget->b_hnp_enable && fsm->a_bus_suspend)
+		else if (fsm->b_bus_req && otg->gadget->b_hnp_enable &&
+			 fsm->a_bus_suspend)
 			otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
 		break;
 	case OTG_STATE_B_WAIT_ACON:
@@ -413,7 +419,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 		if (fsm->id || fsm->a_bus_drop)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
 		else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
-				fsm->otg->host->b_hnp_enable)
+			 otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_SUSPEND);
 		else if (!fsm->b_conn)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
@@ -421,9 +427,9 @@ int otg_statemachine(struct otg_fsm *fsm)
 			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
+		if (!fsm->b_conn && otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
-		else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
+		else if (!fsm->b_conn && !otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
 		else if (fsm->a_bus_req || fsm->b_bus_resume)
 			otg_set_state(fsm, OTG_STATE_A_HOST);
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index a8784ec..3ffa4c6 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -127,7 +127,7 @@ int write_ulpi(u8 addr, u8 data)
 /* Operations that will be called from OTG Finite State Machine */
 
 /* Charge vbus for vbus pulsing in SRP */
-void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
+void fsl_otg_chrg_vbus(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -163,7 +163,7 @@ void fsl_otg_dischrg_vbus(int on)
 }
 
 /* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
+void fsl_otg_drv_vbus(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -181,7 +181,7 @@ void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
  * Pull-up D+, signalling connect by periperal. Also used in
  * data-line pulsing in SRP
  */
-void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
+void fsl_otg_loc_conn(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -200,7 +200,7 @@ void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
  * port.  In host mode, controller will automatically send SOF.
  * Suspend will block the data on the port.
  */
-void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
+void fsl_otg_loc_sof(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -215,7 +215,7 @@ void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
 }
 
 /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
-void fsl_otg_start_pulse(struct otg_fsm *fsm)
+void fsl_otg_start_pulse(struct usb_otg *otg)
 {
 	u32 tmp;
 
@@ -228,7 +228,7 @@ void fsl_otg_start_pulse(struct otg_fsm *fsm)
 	fsl_otg_loc_conn(1);
 #endif
 
-	fsl_otg_add_timer(fsm, b_data_pulse_tmr);
+	fsl_otg_add_timer(&otg->fsm, b_data_pulse_tmr);
 }
 
 void b_data_pulse_end(unsigned long foo)
@@ -245,14 +245,14 @@ void b_data_pulse_end(unsigned long foo)
 void fsl_otg_pulse_vbus(void)
 {
 	srp_wait_done = 0;
-	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->otg, 1);
 	/* start the timer to end vbus charge */
-	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, b_vbus_pulse_tmr);
 }
 
 void b_vbus_pulse_end(unsigned long foo)
 {
-	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->otg, 0);
 
 	/*
 	 * As USB3300 using the same a_sess_vld and b_sess_vld voltage
@@ -260,7 +260,7 @@ void b_vbus_pulse_end(unsigned long foo)
 	 * residual voltage of vbus pulsing and A device pull up
 	 */
 	fsl_otg_dischrg_vbus(1);
-	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, b_srp_wait_tmr);
 }
 
 void b_srp_end(unsigned long foo)
@@ -269,8 +269,8 @@ void b_srp_end(unsigned long foo)
 	srp_wait_done = 1;
 
 	if ((fsl_otg_dev->phy.otg->state == OTG_STATE_B_SRP_INIT) &&
-	    fsl_otg_dev->fsm.b_sess_vld)
-		fsl_otg_dev->fsm.b_srp_done = 1;
+	    fsl_otg_dev->otg.fsm.b_sess_vld)
+		fsl_otg_dev->otg.fsm.b_srp_done = 1;
 }
 
 /*
@@ -282,9 +282,9 @@ 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);
+		fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, a_wait_enum_tmr);
 	else
-		otg_statemachine(&fsl_otg_dev->fsm);
+		otg_statemachine(&fsl_otg_dev->otg);
 }
 
 /* The timeout callback function to set time out bit */
@@ -421,7 +421,7 @@ void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)
 	list_add_tail(&timer->list, &active_timers);
 }
 
-static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void fsl_otg_fsm_add_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
 	struct fsl_otg_timer *timer;
 
@@ -429,7 +429,7 @@ static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
 	if (!timer)
 		return;
 
-	fsl_otg_add_timer(fsm, timer);
+	fsl_otg_add_timer(&otg->fsm, timer);
 }
 
 /* Remove timer from the timer list; clear timeout status */
@@ -443,7 +443,7 @@ void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)
 			list_del(&timer->list);
 }
 
-static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void fsl_otg_fsm_del_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
 	struct fsl_otg_timer *timer;
 
@@ -451,7 +451,7 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
 	if (!timer)
 		return;
 
-	fsl_otg_del_timer(fsm, timer);
+	fsl_otg_del_timer(&otg->fsm, timer);
 }
 
 /* Reset controller, not reset the bus */
@@ -467,9 +467,9 @@ void otg_reset_controller(void)
 }
 
 /* Call suspend/resume routines in host driver */
-int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+int fsl_otg_start_host(struct usb_otg *otg, int on)
 {
-	struct usb_otg *otg = fsm->otg;
+	struct otg_fsm *fsm = &otg->fsm;
 	struct device *dev;
 	struct fsl_otg *otg_dev =
 		container_of(otg->usb_phy, struct fsl_otg, phy);
@@ -496,7 +496,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 				retval = dev->driver->pm->resume(dev);
 				if (fsm->id) {
 					/* default-b */
-					fsl_otg_drv_vbus(fsm, 1);
+					fsl_otg_drv_vbus(otg, 1);
 					/*
 					 * Workaround: b_host can't driver
 					 * vbus, but PP in PORTSC needs to
@@ -521,7 +521,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 					retval = dev->driver->pm->suspend(dev);
 				if (fsm->id)
 					/* default-b */
-					fsl_otg_drv_vbus(fsm, 0);
+					fsl_otg_drv_vbus(otg, 0);
 			}
 			otg_dev->host_working = 0;
 		}
@@ -534,9 +534,8 @@ end:
  * Call suspend and resume function in udc driver
  * to stop and start udc driver.
  */
-int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
+int fsl_otg_start_gadget(struct usb_otg *otg, int on)
 {
-	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
 
 	if (!otg->gadget || !otg->gadget->dev.parent)
@@ -573,14 +572,14 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 	otg->host = host;
 
-	otg_dev->fsm.a_bus_drop = 0;
-	otg_dev->fsm.a_bus_req = 1;
+	otg->fsm.a_bus_drop = 0;
+	otg->fsm.a_bus_req = 1;
 
 	if (host) {
 		VDBG("host off......\n");
 
 		otg->host->otg_port = fsl_otg_initdata.otg_port;
-		otg->host->is_b_host = otg_dev->fsm.id;
+		otg->host->is_b_host = otg->fsm.id;
 		/*
 		 * must leave time for hub_wq to finish its thing
 		 * before yanking the host driver out from under it,
@@ -594,7 +593,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 		if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) &
 		      OTGSC_STS_USB_ID)) {
 			/* Mini-A cable connected */
-			struct otg_fsm *fsm = &otg_dev->fsm;
+			struct otg_fsm *fsm = &otg->fsm;
 
 			otg->state = OTG_STATE_UNDEFINED;
 			fsm->protocol = PROTO_UNDEF;
@@ -603,7 +602,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 	otg_dev->host_working = 0;
 
-	otg_statemachine(&otg_dev->fsm);
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -628,22 +627,22 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg,
 			otg->gadget->ops->vbus_draw(otg->gadget, 0);
 		usb_gadget_vbus_disconnect(otg->gadget);
 		otg->gadget = 0;
-		otg_dev->fsm.b_bus_req = 0;
-		otg_statemachine(&otg_dev->fsm);
+		otg->fsm.b_bus_req = 0;
+		otg_statemachine(otg);
 		return 0;
 	}
 
 	otg->gadget = gadget;
-	otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
+	otg->gadget->is_a_peripheral = !otg->fsm.id;
 
-	otg_dev->fsm.b_bus_req = 1;
+	otg->fsm.b_bus_req = 1;
 
 	/* start the gadget right away if the ID pin says Mini-B */
-	pr_debug("ID pin=%d\n", otg_dev->fsm.id);
-	if (otg_dev->fsm.id == 1) {
-		fsl_otg_start_host(&otg_dev->fsm, 0);
-		otg_drv_vbus(&otg_dev->fsm, 0);
-		fsl_otg_start_gadget(&otg_dev->fsm, 1);
+	pr_debug("ID pin=%d\n", otg->fsm.id);
+	if (otg->fsm.id == 1) {
+		fsl_otg_start_host(otg, 0);
+		otg_drv_vbus(otg, 0);
+		fsl_otg_start_gadget(otg, 1);
 	}
 
 	return 0;
@@ -672,13 +671,14 @@ static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
  */
 static void fsl_otg_event(struct work_struct *work)
 {
-	struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
-	struct otg_fsm *fsm = &og->fsm;
-
-	if (fsm->id) {		/* switch to gadget */
-		fsl_otg_start_host(fsm, 0);
-		otg_drv_vbus(fsm, 0);
-		fsl_otg_start_gadget(fsm, 1);
+	struct fsl_otg *fotg = container_of(work, struct fsl_otg,
+					    otg_event.work);
+	struct usb_otg *otg = &fotg->otg;
+
+	if (otg->fsm.id) {		/* switch to gadget */
+		fsl_otg_start_host(otg, 0);
+		otg_drv_vbus(otg, 0);
+		fsl_otg_start_gadget(otg, 1);
 	}
 }
 
@@ -694,8 +694,8 @@ static int fsl_otg_start_srp(struct usb_otg *otg)
 	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
-	otg_dev->fsm.b_bus_req = 1;
-	otg_statemachine(&otg_dev->fsm);
+	otg->fsm.b_bus_req = 1;
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -715,8 +715,8 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
 	pr_debug("start_hnp...\n");
 
 	/* clear a_bus_req to enter a_suspend state */
-	otg_dev->fsm.a_bus_req = 0;
-	otg_statemachine(&otg_dev->fsm);
+	otg->fsm.a_bus_req = 0;
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -729,8 +729,8 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
  */
 irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 {
-	struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
-	struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
+	struct usb_otg *otg = &((struct fsl_otg *)dev_id)->otg;
+	struct otg_fsm *fsm = &otg->fsm;
 	u32 otg_int_src, otg_sc;
 
 	otg_sc = fsl_readl(&usb_dr_regs->otgsc);
@@ -768,9 +768,9 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 				cancel_delayed_work(&
 						    ((struct fsl_otg *)dev_id)->
 						    otg_event);
-				fsl_otg_start_gadget(fsm, 0);
-				otg_drv_vbus(fsm, 1);
-				fsl_otg_start_host(fsm, 1);
+				fsl_otg_start_gadget(otg, 0);
+				otg_drv_vbus(otg, 1);
+				fsl_otg_start_host(otg, 1);
 			}
 			return IRQ_HANDLED;
 		}
@@ -806,24 +806,20 @@ static int fsl_otg_conf(struct platform_device *pdev)
 	if (!fsl_otg_tc)
 		return -ENOMEM;
 
-	fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
-	if (!fsl_otg_tc->phy.otg) {
-		kfree(fsl_otg_tc);
-		return -ENOMEM;
-	}
+	fsl_otg_tc->phy.otg = &fsl_otg_tc->otg;
 
 	INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
 
 	INIT_LIST_HEAD(&active_timers);
-	status = fsl_otg_init_timers(&fsl_otg_tc->fsm);
+	status = fsl_otg_init_timers(&fsl_otg_tc->otg.fsm);
 	if (status) {
 		pr_info("Couldn't init OTG timers\n");
 		goto err;
 	}
-	mutex_init(&fsl_otg_tc->fsm.lock);
+	mutex_init(&fsl_otg_tc->otg.fsm.lock);
 
 	/* Set OTG state machine operations */
-	fsl_otg_tc->fsm.ops = &fsl_otg_ops;
+	fsl_otg_tc->otg.fsm.ops = &fsl_otg_ops;
 
 	/* initialize the otg structure */
 	fsl_otg_tc->phy.label = DRIVER_DESC;
@@ -858,18 +854,15 @@ int usb_otg_start(struct platform_device *pdev)
 {
 	struct fsl_otg *p_otg;
 	struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
-	struct otg_fsm *fsm;
 	int status;
 	struct resource *res;
 	u32 temp;
 	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	p_otg = container_of(otg_trans, struct fsl_otg, phy);
-	fsm = &p_otg->fsm;
 
 	/* Initialize the state machine structure with default values */
 	SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
-	fsm->otg = p_otg->phy.otg;
 
 	/* We don't require predefined MEM/IRQ resource index */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -963,13 +956,13 @@ int usb_otg_start(struct platform_device *pdev)
 	 */
 	if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
 		p_otg->phy.otg->state = OTG_STATE_UNDEFINED;
-		p_otg->fsm.id = 1;
+		p_otg->otg.fsm.id = 1;
 	} else {
 		p_otg->phy.otg->state = OTG_STATE_A_IDLE;
-		p_otg->fsm.id = 0;
+		p_otg->otg.fsm.id = 0;
 	}
 
-	pr_debug("initial ID pin=%d\n", p_otg->fsm.id);
+	pr_debug("initial ID pin=%d\n", p_otg->otg.fsm.id);
 
 	/* enable OTG ID pin interrupt */
 	temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
@@ -986,7 +979,7 @@ int usb_otg_start(struct platform_device *pdev)
 static int show_fsl_usb2_otg_state(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct otg_fsm *fsm = &fsl_otg_dev->fsm;
+	struct otg_fsm *fsm = &fsl_otg_dev->otg.fsm;
 	char *next = buf;
 	unsigned size = PAGE_SIZE;
 	int t;
@@ -1084,26 +1077,26 @@ static long fsl_otg_ioctl(struct file *file, unsigned int cmd,
 		break;
 
 	case SET_A_SUSPEND_REQ:
-		fsl_otg_dev->fsm.a_suspend_req_inf = arg;
+		fsl_otg_dev->otg.fsm.a_suspend_req_inf = arg;
 		break;
 
 	case SET_A_BUS_DROP:
-		fsl_otg_dev->fsm.a_bus_drop = arg;
+		fsl_otg_dev->otg.fsm.a_bus_drop = arg;
 		break;
 
 	case SET_A_BUS_REQ:
-		fsl_otg_dev->fsm.a_bus_req = arg;
+		fsl_otg_dev->otg.fsm.a_bus_req = arg;
 		break;
 
 	case SET_B_BUS_REQ:
-		fsl_otg_dev->fsm.b_bus_req = arg;
+		fsl_otg_dev->otg.fsm.b_bus_req = arg;
 		break;
 
 	default:
 		break;
 	}
 
-	otg_statemachine(&fsl_otg_dev->fsm);
+	otg_statemachine(&fsl_otg_dev->otg);
 
 	return retval;
 }
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index 2314995..e207cfb 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -15,7 +15,6 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/usb/otg-fsm.h>
 #include <linux/usb/otg.h>
 #include <linux/ioctl.h>
 
@@ -370,7 +369,7 @@ inline struct fsl_otg_timer *otg_timer_initializer
 
 struct fsl_otg {
 	struct usb_phy phy;
-	struct otg_fsm fsm;
+	struct usb_otg otg;
 	struct usb_dr_mmap *dr_mem_map;
 	struct delayed_work otg_event;
 
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index a0a8f87..26e6531 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -188,7 +188,6 @@ struct otg_fsm {
 	int a_bidl_adis_tmout;
 
 	struct otg_fsm_ops *ops;
-	struct usb_otg *otg;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
 	int protocol;
@@ -198,126 +197,23 @@ struct otg_fsm {
 	bool state_changed;
 };
 
+struct usb_otg;
+
 struct otg_fsm_ops {
-	void	(*chrg_vbus)(struct otg_fsm *fsm, int on);
-	void	(*drv_vbus)(struct otg_fsm *fsm, int on);
-	void	(*loc_conn)(struct otg_fsm *fsm, int on);
-	void	(*loc_sof)(struct otg_fsm *fsm, int on);
-	void	(*start_pulse)(struct otg_fsm *fsm);
-	void	(*start_adp_prb)(struct otg_fsm *fsm);
-	void	(*start_adp_sns)(struct otg_fsm *fsm);
-	void	(*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
-	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);
+	void	(*chrg_vbus)(struct usb_otg *otg, int on);
+	void	(*drv_vbus)(struct usb_otg *otg, int on);
+	void	(*loc_conn)(struct usb_otg *otg, int on);
+	void	(*loc_sof)(struct usb_otg *otg, int on);
+	void	(*start_pulse)(struct usb_otg *otg);
+	void	(*start_adp_prb)(struct usb_otg *otg);
+	void	(*start_adp_sns)(struct usb_otg *otg);
+	void	(*add_timer)(struct usb_otg *otg, enum otg_fsm_timer timer);
+	void	(*del_timer)(struct usb_otg *otg, enum otg_fsm_timer timer);
+	int	(*start_host)(struct usb_otg *otg, int on);
+	int	(*start_gadget)(struct usb_otg *otg, int on);
 };
 
 
-static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->chrg_vbus)
-		return -EOPNOTSUPP;
-	fsm->ops->chrg_vbus(fsm, on);
-	return 0;
-}
-
-static inline int otg_drv_vbus(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->drv_vbus)
-		return -EOPNOTSUPP;
-	if (fsm->drv_vbus != on) {
-		fsm->drv_vbus = on;
-		fsm->ops->drv_vbus(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_loc_conn(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->loc_conn)
-		return -EOPNOTSUPP;
-	if (fsm->loc_conn != on) {
-		fsm->loc_conn = on;
-		fsm->ops->loc_conn(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_loc_sof(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->loc_sof)
-		return -EOPNOTSUPP;
-	if (fsm->loc_sof != on) {
-		fsm->loc_sof = on;
-		fsm->ops->loc_sof(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_start_pulse(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_pulse)
-		return -EOPNOTSUPP;
-	if (!fsm->data_pulse) {
-		fsm->data_pulse = 1;
-		fsm->ops->start_pulse(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_start_adp_prb(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_adp_prb)
-		return -EOPNOTSUPP;
-	if (!fsm->adp_prb) {
-		fsm->adp_sns = 0;
-		fsm->adp_prb = 1;
-		fsm->ops->start_adp_prb(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_start_adp_sns(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_adp_sns)
-		return -EOPNOTSUPP;
-	if (!fsm->adp_sns) {
-		fsm->adp_sns = 1;
-		fsm->ops->start_adp_sns(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
-{
-	if (!fsm->ops->add_timer)
-		return -EOPNOTSUPP;
-	fsm->ops->add_timer(fsm, timer);
-	return 0;
-}
-
-static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
-{
-	if (!fsm->ops->del_timer)
-		return -EOPNOTSUPP;
-	fsm->ops->del_timer(fsm, timer);
-	return 0;
-}
-
-static inline int otg_start_host(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->start_host)
-		return -EOPNOTSUPP;
-	return fsm->ops->start_host(fsm, on);
-}
-
-static inline int otg_start_gadget(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->start_gadget)
-		return -EOPNOTSUPP;
-	return fsm->ops->start_gadget(fsm, on);
-}
-
-int otg_statemachine(struct otg_fsm *fsm);
+int otg_statemachine(struct usb_otg *otg);
 
 #endif /* __LINUX_USB_OTG_FSM_H */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 67929df..e8a14dc 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -11,6 +11,7 @@
 
 #include <linux/phy/phy.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/otg-fsm.h>
 
 struct usb_otg {
 	u8			default_a;
@@ -22,6 +23,7 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct otg_fsm fsm;
 
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
@@ -128,4 +130,109 @@ enum usb_dr_mode {
  */
 extern enum usb_dr_mode usb_get_dr_mode(struct device *dev);
 
+static inline int otg_chrg_vbus(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->chrg_vbus)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->chrg_vbus(otg, on);
+	return 0;
+}
+
+static inline int otg_drv_vbus(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->drv_vbus)
+		return -EOPNOTSUPP;
+	if (otg->fsm.drv_vbus != on) {
+		otg->fsm.drv_vbus = on;
+		otg->fsm.ops->drv_vbus(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_loc_conn(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->loc_conn)
+		return -EOPNOTSUPP;
+	if (otg->fsm.loc_conn != on) {
+		otg->fsm.loc_conn = on;
+		otg->fsm.ops->loc_conn(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_loc_sof(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->loc_sof)
+		return -EOPNOTSUPP;
+	if (otg->fsm.loc_sof != on) {
+		otg->fsm.loc_sof = on;
+		otg->fsm.ops->loc_sof(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_start_pulse(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_pulse)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.data_pulse) {
+		otg->fsm.data_pulse = 1;
+		otg->fsm.ops->start_pulse(otg);
+	}
+	return 0;
+}
+
+static inline int otg_start_adp_prb(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_adp_prb)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.adp_prb) {
+		otg->fsm.adp_sns = 0;
+		otg->fsm.adp_prb = 1;
+		otg->fsm.ops->start_adp_prb(otg);
+	}
+	return 0;
+}
+
+static inline int otg_start_adp_sns(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_adp_sns)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.adp_sns) {
+		otg->fsm.adp_sns = 1;
+		otg->fsm.ops->start_adp_sns(otg);
+	}
+	return 0;
+}
+
+static inline int otg_add_timer(struct usb_otg *otg, enum otg_fsm_timer timer)
+{
+	if (!otg->fsm.ops->add_timer)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->add_timer(otg, timer);
+	return 0;
+}
+
+static inline int otg_del_timer(struct usb_otg *otg, enum otg_fsm_timer timer)
+{
+	if (!otg->fsm.ops->del_timer)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->del_timer(otg, timer);
+	return 0;
+}
+
+static inline int otg_start_host(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->start_host)
+		return -EOPNOTSUPP;
+	return otg->fsm.ops->start_host(otg, on);
+}
+
+static inline int otg_start_gadget(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->start_gadget)
+		return -EOPNOTSUPP;
+	return otg->fsm.ops->start_gadget(otg, on);
+}
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

* [PATCH v10 04/14] usb: otg-fsm: use usb_otg wherever possible
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Move otg_fsm into usb_otg and use usb_otg wherever possible
in the usb_otg APIs.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/chipidea/ci.h        |   1 -
 drivers/usb/chipidea/core.c      |  14 +--
 drivers/usb/chipidea/debug.c     |   2 +-
 drivers/usb/chipidea/otg_fsm.c   | 169 ++++++++++++++++++------------------
 drivers/usb/chipidea/udc.c       |  17 ++--
 drivers/usb/common/usb-otg-fsm.c | 180 ++++++++++++++++++++-------------------
 drivers/usb/phy/phy-fsl-usb.c    | 141 +++++++++++++++---------------
 drivers/usb/phy/phy-fsl-usb.h    |   3 +-
 include/linux/usb/otg-fsm.h      | 132 +++-------------------------
 include/linux/usb/otg.h          | 107 +++++++++++++++++++++++
 10 files changed, 383 insertions(+), 383 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index cd41455..c523975 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -209,7 +209,6 @@ struct ci_hdrc {
 	enum ci_role			role;
 	bool				is_otg;
 	struct usb_otg			otg;
-	struct otg_fsm			fsm;
 	struct hrtimer			otg_fsm_hrtimer;
 	ktime_t				hr_timeouts[NUM_OTG_FSM_TIMERS];
 	unsigned			enabled_otg_timer_bits;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 69426e6..56b6ac6 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -1085,8 +1085,8 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 /* Prepare wakeup by SRP before suspend */
 static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
 {
-	if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
-				!hw_read_otgsc(ci, OTGSC_ID)) {
+	if ((ci->otg.state == OTG_STATE_A_IDLE) &&
+	    !hw_read_otgsc(ci, OTGSC_ID)) {
 		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
 								PORTSC_PP);
 		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN,
@@ -1097,13 +1097,13 @@ static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
 /* Handle SRP when wakeup by data pulse */
 static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
 {
-	if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
-		(ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
+	if ((ci->otg.state == OTG_STATE_A_IDLE) &&
+	    (ci->otg.fsm.a_bus_drop == 1) && (ci->otg.fsm.a_bus_req == 0)) {
 		if (!hw_read_otgsc(ci, OTGSC_ID)) {
-			ci->fsm.a_srp_det = 1;
-			ci->fsm.a_bus_drop = 0;
+			ci->otg.fsm.a_srp_det = 1;
+			ci->otg.fsm.a_bus_drop = 0;
 		} else {
-			ci->fsm.id = 1;
+			ci->otg.fsm.id = 1;
 		}
 		ci_otg_queue_work(ci);
 	}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 6d23eed..374cdaa 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -224,7 +224,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
 	if (!ci || !ci_otg_is_fsm_mode(ci))
 		return 0;
 
-	fsm = &ci->fsm;
+	fsm = &ci->otg.fsm;
 
 	/* ------ State ----- */
 	seq_printf(s, "OTG state: %s\n\n",
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index de8e22e..1c0c750 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -40,7 +40,7 @@ get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.a_bus_req);
 	size -= t;
 	next += t;
 
@@ -56,25 +56,25 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0') {
-		ci->fsm.a_bus_req = 0;
+		ci->otg.fsm.a_bus_req = 0;
 	} else if (buf[0] == '1') {
 		/* If a_bus_drop is TRUE, a_bus_req can't be set */
-		if (ci->fsm.a_bus_drop) {
-			mutex_unlock(&ci->fsm.lock);
+		if (ci->otg.fsm.a_bus_drop) {
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
-		ci->fsm.a_bus_req = 1;
-		if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+		ci->otg.fsm.a_bus_req = 1;
+		if (ci->otg.state == OTG_STATE_A_PERIPHERAL) {
 			ci->gadget.host_request_flag = 1;
-			mutex_unlock(&ci->fsm.lock);
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -89,7 +89,7 @@ get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.a_bus_drop);
 	size -= t;
 	next += t;
 
@@ -105,16 +105,16 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0') {
-		ci->fsm.a_bus_drop = 0;
+		ci->otg.fsm.a_bus_drop = 0;
 	} else if (buf[0] == '1') {
-		ci->fsm.a_bus_drop = 1;
-		ci->fsm.a_bus_req = 0;
+		ci->otg.fsm.a_bus_drop = 1;
+		ci->otg.fsm.a_bus_req = 0;
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -130,7 +130,7 @@ get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
 
 	next = buf;
 	size = PAGE_SIZE;
-	t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req);
+	t = scnprintf(next, size, "%d\n", ci->otg.fsm.b_bus_req);
 	size -= t;
 	next += t;
 
@@ -146,20 +146,20 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '0')
-		ci->fsm.b_bus_req = 0;
+		ci->otg.fsm.b_bus_req = 0;
 	else if (buf[0] == '1') {
-		ci->fsm.b_bus_req = 1;
-		if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+		ci->otg.fsm.b_bus_req = 1;
+		if (ci->otg.state == OTG_STATE_B_PERIPHERAL) {
 			ci->gadget.host_request_flag = 1;
-			mutex_unlock(&ci->fsm.lock);
+			mutex_unlock(&ci->otg.fsm.lock);
 			return count;
 		}
 	}
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -174,12 +174,12 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
 	if (count > 2)
 		return -1;
 
-	mutex_lock(&ci->fsm.lock);
+	mutex_lock(&ci->otg.fsm.lock);
 	if (buf[0] == '1')
-		ci->fsm.a_clr_err = 1;
+		ci->otg.fsm.a_clr_err = 1;
 
 	ci_otg_queue_work(ci);
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 
 	return count;
 }
@@ -287,64 +287,64 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
 /* OTG FSM timer handlers */
 static int a_wait_vrise_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_vrise_tmout = 1;
+	ci->otg.fsm.a_wait_vrise_tmout = 1;
 	return 0;
 }
 
 static int a_wait_vfall_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_vfall_tmout = 1;
+	ci->otg.fsm.a_wait_vfall_tmout = 1;
 	return 0;
 }
 
 static int a_wait_bcon_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_wait_bcon_tmout = 1;
+	ci->otg.fsm.a_wait_bcon_tmout = 1;
 	return 0;
 }
 
 static int a_aidl_bdis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_aidl_bdis_tmout = 1;
+	ci->otg.fsm.a_aidl_bdis_tmout = 1;
 	return 0;
 }
 
 static int b_ase0_brst_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_ase0_brst_tmout = 1;
+	ci->otg.fsm.b_ase0_brst_tmout = 1;
 	return 0;
 }
 
 static int a_bidl_adis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_bidl_adis_tmout = 1;
+	ci->otg.fsm.a_bidl_adis_tmout = 1;
 	return 0;
 }
 
 static int b_aidl_bdis_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.a_bus_suspend = 1;
+	ci->otg.fsm.a_bus_suspend = 1;
 	return 0;
 }
 
 static int b_se0_srp_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_se0_srp = 1;
+	ci->otg.fsm.b_se0_srp = 1;
 	return 0;
 }
 
 static int b_srp_fail_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_srp_done = 1;
+	ci->otg.fsm.b_srp_done = 1;
 	return 1;
 }
 
 static int b_data_pls_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_srp_done = 1;
-	ci->fsm.b_bus_req = 0;
-	if (ci->fsm.power_up)
-		ci->fsm.power_up = 0;
+	ci->otg.fsm.b_srp_done = 1;
+	ci->otg.fsm.b_bus_req = 0;
+	if (ci->otg.fsm.power_up)
+		ci->otg.fsm.power_up = 0;
 	hw_write_otgsc(ci, OTGSC_HABA, 0);
 	pm_runtime_put(ci->dev);
 	return 0;
@@ -352,9 +352,9 @@ static int b_data_pls_tmout(struct ci_hdrc *ci)
 
 static int b_ssend_srp_tmout(struct ci_hdrc *ci)
 {
-	ci->fsm.b_ssend_srp = 1;
+	ci->otg.fsm.b_ssend_srp = 1;
 	/* only vbus fall below B_sess_vld in b_idle state */
-	if (ci->fsm.otg->state == OTG_STATE_B_IDLE)
+	if (ci->otg.state == OTG_STATE_B_IDLE)
 		return 0;
 	else
 		return 1;
@@ -435,18 +435,18 @@ static int ci_otg_init_timers(struct ci_hdrc *ci)
 /* -------------------------------------------------------------*/
 /* Operations that will be called from OTG Finite State Machine */
 /* -------------------------------------------------------------*/
-static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void ci_otg_fsm_add_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (t < NUM_OTG_FSM_TIMERS)
 		ci_otg_add_timer(ci, t);
 	return;
 }
 
-static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void ci_otg_fsm_del_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (t < NUM_OTG_FSM_TIMERS)
 		ci_otg_del_timer(ci, t);
@@ -457,10 +457,10 @@ static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
  * A-device drive vbus: turn on vbus regulator and enable port power
  * Data pulse irq should be disabled while vbus is on.
  */
-static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
+static void ci_otg_drv_vbus(struct usb_otg *otg, int on)
 {
 	int ret;
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on) {
 		/* Enable power power */
@@ -478,23 +478,23 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
 		/* Disable data pulse irq */
 		hw_write_otgsc(ci, OTGSC_DPIE, 0);
 
-		fsm->a_srp_det = 0;
-		fsm->power_up = 0;
+		otg->fsm.a_srp_det = 0;
+		otg->fsm.power_up = 0;
 	} else {
 		if (ci->platdata->reg_vbus)
 			regulator_disable(ci->platdata->reg_vbus);
 
-		fsm->a_bus_drop = 1;
-		fsm->a_bus_req = 0;
+		otg->fsm.a_bus_drop = 1;
+		otg->fsm.a_bus_req = 0;
 	}
 }
 
 /*
  * Control data line by Run Stop bit.
  */
-static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
+static void ci_otg_loc_conn(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on)
 		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
@@ -511,14 +511,14 @@ static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
  * so the usb device class driver need support autosuspend,
  * otherwise the bus suspend will not happen.
  */
-static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
+static void ci_otg_loc_sof(struct usb_otg *otg, int on)
 {
 	struct usb_device *udev;
 
-	if (!fsm->otg->host)
+	if (!otg->host)
 		return;
 
-	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+	udev = usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev)
 		return;
 
@@ -534,9 +534,9 @@ static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
  * Start SRP pulsing by data-line pulsing,
  * no v-bus pulsing followed
  */
-static void ci_otg_start_pulse(struct otg_fsm *fsm)
+static void ci_otg_start_pulse(struct usb_otg *otg)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	/* Hardware Assistant Data pulse */
 	hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP);
@@ -545,9 +545,9 @@ static void ci_otg_start_pulse(struct otg_fsm *fsm)
 	ci_otg_add_timer(ci, B_DATA_PLS);
 }
 
-static int ci_otg_start_host(struct otg_fsm *fsm, int on)
+static int ci_otg_start_host(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on) {
 		ci_role_stop(ci);
@@ -559,9 +559,9 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
 	return 0;
 }
 
-static int ci_otg_start_gadget(struct otg_fsm *fsm, int on)
+static int ci_otg_start_gadget(struct usb_otg *otg, int on)
 {
-	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm);
+	struct ci_hdrc	*ci = container_of(otg, struct ci_hdrc, otg);
 
 	if (on)
 		usb_gadget_vbus_connect(&ci->gadget);
@@ -588,13 +588,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 	 * Don't do fsm transition for B device
 	 * when there is no gadget class driver
 	 */
-	if (ci->fsm.id && !(ci->driver) &&
-		ci->fsm.otg->state < OTG_STATE_A_IDLE)
+	if (ci->otg.fsm.id && !(ci->driver) &&
+	    ci->otg.state < OTG_STATE_A_IDLE)
 		return 0;
 
 	pm_runtime_get_sync(ci->dev);
-	if (otg_statemachine(&ci->fsm)) {
-		if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
+	if (otg_statemachine(&ci->otg)) {
+		if (ci->otg.state == OTG_STATE_A_IDLE) {
 			/*
 			 * Further state change for cases:
 			 * a_idle to b_idle; or
@@ -603,8 +603,8 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 			 * consequently; or
 			 * a_idle to a_wait_vrise when power up
 			 */
-			if ((ci->fsm.id) || (ci->id_event) ||
-						(ci->fsm.power_up)) {
+			if ((ci->otg.fsm.id) || (ci->id_event) ||
+			    (ci->otg.fsm.power_up)) {
 				ci_otg_queue_work(ci);
 			} else {
 				/* Enable data pulse irq */
@@ -615,16 +615,16 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 			}
 			if (ci->id_event)
 				ci->id_event = false;
-		} else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
-			if (ci->fsm.b_sess_vld) {
-				ci->fsm.power_up = 0;
+		} else if (ci->otg.state == OTG_STATE_B_IDLE) {
+			if (ci->otg.fsm.b_sess_vld) {
+				ci->otg.fsm.power_up = 0;
 				/*
 				 * Further transite to b_periphearl state
 				 * when register gadget driver with vbus on
 				 */
 				ci_otg_queue_work(ci);
 			}
-		} else if (ci->fsm.otg->state == OTG_STATE_A_HOST) {
+		} else if (ci->otg.state == OTG_STATE_A_HOST) {
 			pm_runtime_mark_last_busy(ci->dev);
 			pm_runtime_put_autosuspend(ci->dev);
 			return 0;
@@ -641,13 +641,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
 static void ci_otg_fsm_event(struct ci_hdrc *ci)
 {
 	u32 intr_sts, otg_bsess_vld, port_conn;
-	struct otg_fsm *fsm = &ci->fsm;
+	struct otg_fsm *fsm = &ci->otg.fsm;
 
 	intr_sts = hw_read_intr_status(ci);
 	otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV);
 	port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS);
 
-	switch (ci->fsm.otg->state) {
+	switch (ci->otg.state) {
 	case OTG_STATE_A_WAIT_BCON:
 		if (port_conn) {
 			fsm->b_conn = 1;
@@ -737,7 +737,7 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci)
 {
 	irqreturn_t retval =  IRQ_NONE;
 	u32 otgsc, otg_int_src = 0;
-	struct otg_fsm *fsm = &ci->fsm;
+	struct otg_fsm *fsm = &ci->otg.fsm;
 
 	otgsc = hw_read_otgsc(ci, ~0);
 	otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8);
@@ -800,17 +800,16 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 		ci->otg.usb_phy = ci->usb_phy;
 
 	ci->otg.gadget = &ci->gadget;
-	ci->fsm.otg = &ci->otg;
-	ci->fsm.power_up = 1;
-	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->otg.fsm.power_up = 1;
+	ci->otg.fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
+	ci->otg.state = OTG_STATE_UNDEFINED;
+	ci->otg.fsm.ops = &ci_otg_ops;
 	ci->gadget.hnp_polling_support = 1;
-	ci->fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
-	if (!ci->fsm.host_req_flag)
+	ci->otg.fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
+	if (!ci->otg.fsm.host_req_flag)
 		return -ENOMEM;
 
-	mutex_init(&ci->fsm.lock);
+	mutex_init(&ci->otg.fsm.lock);
 
 	retval = ci_otg_init_timers(ci);
 	if (retval) {
@@ -830,10 +829,10 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 	/* Enable A vbus valid irq */
 	hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE);
 
-	if (ci->fsm.id) {
-		ci->fsm.b_ssend_srp =
+	if (ci->otg.fsm.id) {
+		ci->otg.fsm.b_ssend_srp =
 			hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1;
-		ci->fsm.b_sess_vld =
+		ci->otg.fsm.b_sess_vld =
 			hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0;
 		/* Enable BSV irq */
 		hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 065f5d9..7a6b0b5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -20,6 +20,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 #include <linux/usb/chipidea.h>
 
@@ -1739,7 +1740,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
 	ci->driver = driver;
 
 	/* Start otg fsm for B-device */
-	if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) {
+	if (ci_otg_is_fsm_mode(ci) && ci->otg.fsm.id) {
 		ci_hdrc_otg_fsm_start(ci);
 		return retval;
 	}
@@ -1767,15 +1768,15 @@ static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
 	if (!ci_otg_is_fsm_mode(ci))
 		return;
 
-	mutex_lock(&ci->fsm.lock);
-	if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
-		ci->fsm.a_bidl_adis_tmout = 1;
+	mutex_lock(&ci->otg.fsm.lock);
+	if (ci->otg.state == OTG_STATE_A_PERIPHERAL) {
+		ci->otg.fsm.a_bidl_adis_tmout = 1;
 		ci_hdrc_otg_fsm_start(ci);
-	} else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
-		ci->fsm.protocol = PROTO_UNDEF;
-		ci->fsm.otg->state = OTG_STATE_UNDEFINED;
+	} else if (ci->otg.state == OTG_STATE_B_PERIPHERAL) {
+		ci->otg.fsm.protocol = PROTO_UNDEF;
+		ci->otg.state = OTG_STATE_UNDEFINED;
 	}
-	mutex_unlock(&ci->fsm.lock);
+	mutex_unlock(&ci->otg.fsm.lock);
 }
 
 /**
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 199dee0..610b5bd6 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -40,6 +40,7 @@
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
 	int ret = 0;
 
 	if (fsm->protocol != protocol) {
@@ -47,17 +48,17 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 			fsm->protocol, protocol);
 		/* stop old protocol */
 		if (fsm->protocol == PROTO_HOST)
-			ret = otg_start_host(fsm, 0);
+			ret = otg_start_host(otg, 0);
 		else if (fsm->protocol == PROTO_GADGET)
-			ret = otg_start_gadget(fsm, 0);
+			ret = otg_start_gadget(otg, 0);
 		if (ret)
 			return ret;
 
 		/* start new protocol */
 		if (protocol == PROTO_HOST)
-			ret = otg_start_host(fsm, 1);
+			ret = otg_start_host(otg, 1);
 		else if (protocol == PROTO_GADGET)
-			ret = otg_start_gadget(fsm, 1);
+			ret = otg_start_gadget(otg, 1);
 		if (ret)
 			return ret;
 
@@ -71,9 +72,11 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 /* 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)
 {
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
 	switch (old_state) {
 	case OTG_STATE_B_IDLE:
-		otg_del_timer(fsm, B_SE0_SRP);
+		otg_del_timer(otg, B_SE0_SRP);
 		fsm->b_se0_srp = 0;
 		fsm->adp_sns = 0;
 		fsm->adp_prb = 0;
@@ -83,11 +86,11 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 		fsm->b_srp_done = 0;
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		if (fsm->otg->gadget)
-			fsm->otg->gadget->host_request_flag = 0;
+		if (otg->gadget)
+			otg->gadget->host_request_flag = 0;
 		break;
 	case OTG_STATE_B_WAIT_ACON:
-		otg_del_timer(fsm, B_ASE0_BRST);
+		otg_del_timer(otg, B_ASE0_BRST);
 		fsm->b_ase0_brst_tmout = 0;
 		break;
 	case OTG_STATE_B_HOST:
@@ -96,31 +99,31 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
 		fsm->adp_prb = 0;
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
-		otg_del_timer(fsm, A_WAIT_VRISE);
+		otg_del_timer(otg, A_WAIT_VRISE);
 		fsm->a_wait_vrise_tmout = 0;
 		break;
 	case OTG_STATE_A_WAIT_BCON:
-		otg_del_timer(fsm, A_WAIT_BCON);
+		otg_del_timer(otg, A_WAIT_BCON);
 		fsm->a_wait_bcon_tmout = 0;
 		break;
 	case OTG_STATE_A_HOST:
-		otg_del_timer(fsm, A_WAIT_ENUM);
+		otg_del_timer(otg, A_WAIT_ENUM);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		otg_del_timer(fsm, A_AIDL_BDIS);
+		otg_del_timer(otg, A_AIDL_BDIS);
 		fsm->a_aidl_bdis_tmout = 0;
 		fsm->a_suspend_req_inf = 0;
 		break;
 	case OTG_STATE_A_PERIPHERAL:
-		otg_del_timer(fsm, A_BIDL_ADIS);
+		otg_del_timer(otg, A_BIDL_ADIS);
 		fsm->a_bidl_adis_tmout = 0;
-		if (fsm->otg->gadget)
-			fsm->otg->gadget->host_request_flag = 0;
+		if (otg->gadget)
+			otg->gadget->host_request_flag = 0;
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		otg_del_timer(fsm, A_WAIT_VFALL);
+		otg_del_timer(otg, A_WAIT_VFALL);
 		fsm->a_wait_vfall_tmout = 0;
-		otg_del_timer(fsm, A_WAIT_VRISE);
+		otg_del_timer(otg, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
 		break;
@@ -133,17 +136,18 @@ static void otg_hnp_polling_work(struct work_struct *work)
 {
 	struct otg_fsm *fsm = container_of(to_delayed_work(work),
 				struct otg_fsm, hnp_polling_work);
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
 	struct usb_device *udev;
-	enum usb_otg_state state = fsm->otg->state;
+	enum usb_otg_state state = otg->state;
 	u8 flag;
 	int retval;
 
 	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
 		return;
 
-	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+	udev = usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev) {
-		dev_err(fsm->otg->host->controller,
+		dev_err(otg->host->controller,
 			"no usb dev connected, can't start HNP polling\n");
 		return;
 	}
@@ -178,7 +182,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	/* Host request flag is set */
 	if (state == OTG_STATE_A_HOST) {
 		/* Set b_hnp_enable */
-		if (!fsm->otg->host->b_hnp_enable) {
+		if (!otg->host->b_hnp_enable) {
 			retval = usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_SET_FEATURE, 0,
@@ -186,14 +190,14 @@ static void otg_hnp_polling_work(struct work_struct *work)
 					0, NULL, 0,
 					USB_CTRL_SET_TIMEOUT);
 			if (retval >= 0)
-				fsm->otg->host->b_hnp_enable = 1;
+				otg->host->b_hnp_enable = 1;
 		}
 		fsm->a_bus_req = 0;
 	} else if (state == OTG_STATE_B_HOST) {
 		fsm->b_bus_req = 0;
 	}
 
-	otg_statemachine(fsm);
+	otg_statemachine(otg);
 }
 
 static void otg_start_hnp_polling(struct otg_fsm *fsm)
@@ -213,133 +217,135 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm)
 /* Called when entering a state */
 static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 {
-	if (fsm->otg->state == new_state)
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
 		return 0;
 	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
-	otg_leave_state(fsm, fsm->otg->state);
+	otg_leave_state(fsm, otg->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
-		otg_drv_vbus(fsm, 0);
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		/*
 		 * Driver is responsible for starting ADP probing
 		 * if ADP sensing times out.
 		 */
-		otg_start_adp_sns(fsm);
+		otg_start_adp_sns(otg);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, B_SE0_SRP);
+		otg_add_timer(otg, B_SE0_SRP);
 		break;
 	case OTG_STATE_B_SRP_INIT:
-		otg_start_pulse(fsm);
-		otg_loc_sof(fsm, 0);
+		otg_start_pulse(otg);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_UNDEF);
-		otg_add_timer(fsm, B_SRP_FAIL);
+		otg_add_timer(otg, B_SRP_FAIL);
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_GADGET);
-		otg_loc_conn(fsm, 1);
+		otg_loc_conn(otg, 1);
 		break;
 	case OTG_STATE_B_WAIT_ACON:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, B_ASE0_BRST);
+		otg_add_timer(otg, B_ASE0_BRST);
 		fsm->a_bus_suspend = 0;
 		break;
 	case OTG_STATE_B_HOST:
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 1);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(fsm->otg->host,
-				fsm->otg->host->otg_port);
+		usb_bus_start_enum(otg->host, otg->host->otg_port);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_IDLE:
-		otg_drv_vbus(fsm, 0);
-		otg_chrg_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
-		otg_start_adp_prb(fsm);
+		otg_drv_vbus(otg, 0);
+		otg_chrg_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
+		otg_start_adp_prb(otg);
 		otg_set_protocol(fsm, PROTO_HOST);
 		break;
 	case OTG_STATE_A_WAIT_VRISE:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_VRISE);
+		otg_add_timer(otg, A_WAIT_VRISE);
 		break;
 	case OTG_STATE_A_WAIT_BCON:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_BCON);
+		otg_add_timer(otg, A_WAIT_BCON);
 		break;
 	case OTG_STATE_A_HOST:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 1);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
 		/*
 		 * When HNP is triggered while a_bus_req = 0, a_host will
 		 * suspend too fast to complete a_set_b_hnp_en
 		 */
 		if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
-			otg_add_timer(fsm, A_WAIT_ENUM);
+			otg_add_timer(otg, A_WAIT_ENUM);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_AIDL_BDIS);
+		otg_add_timer(otg, A_AIDL_BDIS);
 
 		break;
 	case OTG_STATE_A_PERIPHERAL:
-		otg_loc_sof(fsm, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_GADGET);
-		otg_drv_vbus(fsm, 1);
-		otg_loc_conn(fsm, 1);
-		otg_add_timer(fsm, A_BIDL_ADIS);
+		otg_drv_vbus(otg, 1);
+		otg_loc_conn(otg, 1);
+		otg_add_timer(otg, A_BIDL_ADIS);
 		break;
 	case OTG_STATE_A_WAIT_VFALL:
-		otg_drv_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_HOST);
-		otg_add_timer(fsm, A_WAIT_VFALL);
+		otg_add_timer(otg, A_WAIT_VFALL);
 		break;
 	case OTG_STATE_A_VBUS_ERR:
-		otg_drv_vbus(fsm, 0);
-		otg_loc_conn(fsm, 0);
-		otg_loc_sof(fsm, 0);
+		otg_drv_vbus(otg, 0);
+		otg_loc_conn(otg, 0);
+		otg_loc_sof(otg, 0);
 		otg_set_protocol(fsm, PROTO_UNDEF);
 		break;
 	default:
 		break;
 	}
 
-	fsm->otg->state = new_state;
+	otg->state = new_state;
 	fsm->state_changed = 1;
 	return 0;
 }
 
 /* State change judgement */
-int otg_statemachine(struct otg_fsm *fsm)
+int otg_statemachine(struct usb_otg *otg)
 {
 	enum usb_otg_state state;
+	struct otg_fsm *fsm = &otg->fsm;
 
 	mutex_lock(&fsm->lock);
 
-	state = fsm->otg->state;
+	state = otg->state;
 	fsm->state_changed = 0;
 	/* State machine state change judgement */
 
@@ -354,7 +360,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_B_IDLE:
 		if (!fsm->id)
 			otg_set_state(fsm, OTG_STATE_A_IDLE);
-		else if (fsm->b_sess_vld && fsm->otg->gadget)
+		else if (fsm->b_sess_vld && otg->gadget)
 			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
 		else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
 				fsm->b_ssend_srp && fsm->b_se0_srp)
@@ -367,8 +373,8 @@ int otg_statemachine(struct otg_fsm *fsm)
 	case OTG_STATE_B_PERIPHERAL:
 		if (!fsm->id || !fsm->b_sess_vld)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
-		else if (fsm->b_bus_req && fsm->otg->
-				gadget->b_hnp_enable && fsm->a_bus_suspend)
+		else if (fsm->b_bus_req && otg->gadget->b_hnp_enable &&
+			 fsm->a_bus_suspend)
 			otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
 		break;
 	case OTG_STATE_B_WAIT_ACON:
@@ -413,7 +419,7 @@ int otg_statemachine(struct otg_fsm *fsm)
 		if (fsm->id || fsm->a_bus_drop)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
 		else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
-				fsm->otg->host->b_hnp_enable)
+			 otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_SUSPEND);
 		else if (!fsm->b_conn)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
@@ -421,9 +427,9 @@ int otg_statemachine(struct otg_fsm *fsm)
 			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
 		break;
 	case OTG_STATE_A_SUSPEND:
-		if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
+		if (!fsm->b_conn && otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
-		else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
+		else if (!fsm->b_conn && !otg->host->b_hnp_enable)
 			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
 		else if (fsm->a_bus_req || fsm->b_bus_resume)
 			otg_set_state(fsm, OTG_STATE_A_HOST);
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index a8784ec..3ffa4c6 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -127,7 +127,7 @@ int write_ulpi(u8 addr, u8 data)
 /* Operations that will be called from OTG Finite State Machine */
 
 /* Charge vbus for vbus pulsing in SRP */
-void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
+void fsl_otg_chrg_vbus(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -163,7 +163,7 @@ void fsl_otg_dischrg_vbus(int on)
 }
 
 /* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
+void fsl_otg_drv_vbus(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -181,7 +181,7 @@ void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
  * Pull-up D+, signalling connect by periperal. Also used in
  * data-line pulsing in SRP
  */
-void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
+void fsl_otg_loc_conn(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -200,7 +200,7 @@ void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
  * port.  In host mode, controller will automatically send SOF.
  * Suspend will block the data on the port.
  */
-void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
+void fsl_otg_loc_sof(struct usb_otg *otg, int on)
 {
 	u32 tmp;
 
@@ -215,7 +215,7 @@ void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
 }
 
 /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
-void fsl_otg_start_pulse(struct otg_fsm *fsm)
+void fsl_otg_start_pulse(struct usb_otg *otg)
 {
 	u32 tmp;
 
@@ -228,7 +228,7 @@ void fsl_otg_start_pulse(struct otg_fsm *fsm)
 	fsl_otg_loc_conn(1);
 #endif
 
-	fsl_otg_add_timer(fsm, b_data_pulse_tmr);
+	fsl_otg_add_timer(&otg->fsm, b_data_pulse_tmr);
 }
 
 void b_data_pulse_end(unsigned long foo)
@@ -245,14 +245,14 @@ void b_data_pulse_end(unsigned long foo)
 void fsl_otg_pulse_vbus(void)
 {
 	srp_wait_done = 0;
-	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->otg, 1);
 	/* start the timer to end vbus charge */
-	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, b_vbus_pulse_tmr);
 }
 
 void b_vbus_pulse_end(unsigned long foo)
 {
-	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0);
+	fsl_otg_chrg_vbus(&fsl_otg_dev->otg, 0);
 
 	/*
 	 * As USB3300 using the same a_sess_vld and b_sess_vld voltage
@@ -260,7 +260,7 @@ void b_vbus_pulse_end(unsigned long foo)
 	 * residual voltage of vbus pulsing and A device pull up
 	 */
 	fsl_otg_dischrg_vbus(1);
-	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr);
+	fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, b_srp_wait_tmr);
 }
 
 void b_srp_end(unsigned long foo)
@@ -269,8 +269,8 @@ void b_srp_end(unsigned long foo)
 	srp_wait_done = 1;
 
 	if ((fsl_otg_dev->phy.otg->state == OTG_STATE_B_SRP_INIT) &&
-	    fsl_otg_dev->fsm.b_sess_vld)
-		fsl_otg_dev->fsm.b_srp_done = 1;
+	    fsl_otg_dev->otg.fsm.b_sess_vld)
+		fsl_otg_dev->otg.fsm.b_srp_done = 1;
 }
 
 /*
@@ -282,9 +282,9 @@ 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);
+		fsl_otg_add_timer(&fsl_otg_dev->otg.fsm, a_wait_enum_tmr);
 	else
-		otg_statemachine(&fsl_otg_dev->fsm);
+		otg_statemachine(&fsl_otg_dev->otg);
 }
 
 /* The timeout callback function to set time out bit */
@@ -421,7 +421,7 @@ void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)
 	list_add_tail(&timer->list, &active_timers);
 }
 
-static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void fsl_otg_fsm_add_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
 	struct fsl_otg_timer *timer;
 
@@ -429,7 +429,7 @@ static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
 	if (!timer)
 		return;
 
-	fsl_otg_add_timer(fsm, timer);
+	fsl_otg_add_timer(&otg->fsm, timer);
 }
 
 /* Remove timer from the timer list; clear timeout status */
@@ -443,7 +443,7 @@ void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)
 			list_del(&timer->list);
 }
 
-static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
+static void fsl_otg_fsm_del_timer(struct usb_otg *otg, enum otg_fsm_timer t)
 {
 	struct fsl_otg_timer *timer;
 
@@ -451,7 +451,7 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
 	if (!timer)
 		return;
 
-	fsl_otg_del_timer(fsm, timer);
+	fsl_otg_del_timer(&otg->fsm, timer);
 }
 
 /* Reset controller, not reset the bus */
@@ -467,9 +467,9 @@ void otg_reset_controller(void)
 }
 
 /* Call suspend/resume routines in host driver */
-int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+int fsl_otg_start_host(struct usb_otg *otg, int on)
 {
-	struct usb_otg *otg = fsm->otg;
+	struct otg_fsm *fsm = &otg->fsm;
 	struct device *dev;
 	struct fsl_otg *otg_dev =
 		container_of(otg->usb_phy, struct fsl_otg, phy);
@@ -496,7 +496,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 				retval = dev->driver->pm->resume(dev);
 				if (fsm->id) {
 					/* default-b */
-					fsl_otg_drv_vbus(fsm, 1);
+					fsl_otg_drv_vbus(otg, 1);
 					/*
 					 * Workaround: b_host can't driver
 					 * vbus, but PP in PORTSC needs to
@@ -521,7 +521,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
 					retval = dev->driver->pm->suspend(dev);
 				if (fsm->id)
 					/* default-b */
-					fsl_otg_drv_vbus(fsm, 0);
+					fsl_otg_drv_vbus(otg, 0);
 			}
 			otg_dev->host_working = 0;
 		}
@@ -534,9 +534,8 @@ end:
  * Call suspend and resume function in udc driver
  * to stop and start udc driver.
  */
-int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
+int fsl_otg_start_gadget(struct usb_otg *otg, int on)
 {
-	struct usb_otg *otg = fsm->otg;
 	struct device *dev;
 
 	if (!otg->gadget || !otg->gadget->dev.parent)
@@ -573,14 +572,14 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 	otg->host = host;
 
-	otg_dev->fsm.a_bus_drop = 0;
-	otg_dev->fsm.a_bus_req = 1;
+	otg->fsm.a_bus_drop = 0;
+	otg->fsm.a_bus_req = 1;
 
 	if (host) {
 		VDBG("host off......\n");
 
 		otg->host->otg_port = fsl_otg_initdata.otg_port;
-		otg->host->is_b_host = otg_dev->fsm.id;
+		otg->host->is_b_host = otg->fsm.id;
 		/*
 		 * must leave time for hub_wq to finish its thing
 		 * before yanking the host driver out from under it,
@@ -594,7 +593,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 		if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) &
 		      OTGSC_STS_USB_ID)) {
 			/* Mini-A cable connected */
-			struct otg_fsm *fsm = &otg_dev->fsm;
+			struct otg_fsm *fsm = &otg->fsm;
 
 			otg->state = OTG_STATE_UNDEFINED;
 			fsm->protocol = PROTO_UNDEF;
@@ -603,7 +602,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 	otg_dev->host_working = 0;
 
-	otg_statemachine(&otg_dev->fsm);
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -628,22 +627,22 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg,
 			otg->gadget->ops->vbus_draw(otg->gadget, 0);
 		usb_gadget_vbus_disconnect(otg->gadget);
 		otg->gadget = 0;
-		otg_dev->fsm.b_bus_req = 0;
-		otg_statemachine(&otg_dev->fsm);
+		otg->fsm.b_bus_req = 0;
+		otg_statemachine(otg);
 		return 0;
 	}
 
 	otg->gadget = gadget;
-	otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
+	otg->gadget->is_a_peripheral = !otg->fsm.id;
 
-	otg_dev->fsm.b_bus_req = 1;
+	otg->fsm.b_bus_req = 1;
 
 	/* start the gadget right away if the ID pin says Mini-B */
-	pr_debug("ID pin=%d\n", otg_dev->fsm.id);
-	if (otg_dev->fsm.id == 1) {
-		fsl_otg_start_host(&otg_dev->fsm, 0);
-		otg_drv_vbus(&otg_dev->fsm, 0);
-		fsl_otg_start_gadget(&otg_dev->fsm, 1);
+	pr_debug("ID pin=%d\n", otg->fsm.id);
+	if (otg->fsm.id == 1) {
+		fsl_otg_start_host(otg, 0);
+		otg_drv_vbus(otg, 0);
+		fsl_otg_start_gadget(otg, 1);
 	}
 
 	return 0;
@@ -672,13 +671,14 @@ static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
  */
 static void fsl_otg_event(struct work_struct *work)
 {
-	struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
-	struct otg_fsm *fsm = &og->fsm;
-
-	if (fsm->id) {		/* switch to gadget */
-		fsl_otg_start_host(fsm, 0);
-		otg_drv_vbus(fsm, 0);
-		fsl_otg_start_gadget(fsm, 1);
+	struct fsl_otg *fotg = container_of(work, struct fsl_otg,
+					    otg_event.work);
+	struct usb_otg *otg = &fotg->otg;
+
+	if (otg->fsm.id) {		/* switch to gadget */
+		fsl_otg_start_host(otg, 0);
+		otg_drv_vbus(otg, 0);
+		fsl_otg_start_gadget(otg, 1);
 	}
 }
 
@@ -694,8 +694,8 @@ static int fsl_otg_start_srp(struct usb_otg *otg)
 	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
-	otg_dev->fsm.b_bus_req = 1;
-	otg_statemachine(&otg_dev->fsm);
+	otg->fsm.b_bus_req = 1;
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -715,8 +715,8 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
 	pr_debug("start_hnp...\n");
 
 	/* clear a_bus_req to enter a_suspend state */
-	otg_dev->fsm.a_bus_req = 0;
-	otg_statemachine(&otg_dev->fsm);
+	otg->fsm.a_bus_req = 0;
+	otg_statemachine(otg);
 
 	return 0;
 }
@@ -729,8 +729,8 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
  */
 irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 {
-	struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
-	struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
+	struct usb_otg *otg = &((struct fsl_otg *)dev_id)->otg;
+	struct otg_fsm *fsm = &otg->fsm;
 	u32 otg_int_src, otg_sc;
 
 	otg_sc = fsl_readl(&usb_dr_regs->otgsc);
@@ -768,9 +768,9 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id)
 				cancel_delayed_work(&
 						    ((struct fsl_otg *)dev_id)->
 						    otg_event);
-				fsl_otg_start_gadget(fsm, 0);
-				otg_drv_vbus(fsm, 1);
-				fsl_otg_start_host(fsm, 1);
+				fsl_otg_start_gadget(otg, 0);
+				otg_drv_vbus(otg, 1);
+				fsl_otg_start_host(otg, 1);
 			}
 			return IRQ_HANDLED;
 		}
@@ -806,24 +806,20 @@ static int fsl_otg_conf(struct platform_device *pdev)
 	if (!fsl_otg_tc)
 		return -ENOMEM;
 
-	fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
-	if (!fsl_otg_tc->phy.otg) {
-		kfree(fsl_otg_tc);
-		return -ENOMEM;
-	}
+	fsl_otg_tc->phy.otg = &fsl_otg_tc->otg;
 
 	INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
 
 	INIT_LIST_HEAD(&active_timers);
-	status = fsl_otg_init_timers(&fsl_otg_tc->fsm);
+	status = fsl_otg_init_timers(&fsl_otg_tc->otg.fsm);
 	if (status) {
 		pr_info("Couldn't init OTG timers\n");
 		goto err;
 	}
-	mutex_init(&fsl_otg_tc->fsm.lock);
+	mutex_init(&fsl_otg_tc->otg.fsm.lock);
 
 	/* Set OTG state machine operations */
-	fsl_otg_tc->fsm.ops = &fsl_otg_ops;
+	fsl_otg_tc->otg.fsm.ops = &fsl_otg_ops;
 
 	/* initialize the otg structure */
 	fsl_otg_tc->phy.label = DRIVER_DESC;
@@ -858,18 +854,15 @@ int usb_otg_start(struct platform_device *pdev)
 {
 	struct fsl_otg *p_otg;
 	struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
-	struct otg_fsm *fsm;
 	int status;
 	struct resource *res;
 	u32 temp;
 	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	p_otg = container_of(otg_trans, struct fsl_otg, phy);
-	fsm = &p_otg->fsm;
 
 	/* Initialize the state machine structure with default values */
 	SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
-	fsm->otg = p_otg->phy.otg;
 
 	/* We don't require predefined MEM/IRQ resource index */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -963,13 +956,13 @@ int usb_otg_start(struct platform_device *pdev)
 	 */
 	if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
 		p_otg->phy.otg->state = OTG_STATE_UNDEFINED;
-		p_otg->fsm.id = 1;
+		p_otg->otg.fsm.id = 1;
 	} else {
 		p_otg->phy.otg->state = OTG_STATE_A_IDLE;
-		p_otg->fsm.id = 0;
+		p_otg->otg.fsm.id = 0;
 	}
 
-	pr_debug("initial ID pin=%d\n", p_otg->fsm.id);
+	pr_debug("initial ID pin=%d\n", p_otg->otg.fsm.id);
 
 	/* enable OTG ID pin interrupt */
 	temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
@@ -986,7 +979,7 @@ int usb_otg_start(struct platform_device *pdev)
 static int show_fsl_usb2_otg_state(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct otg_fsm *fsm = &fsl_otg_dev->fsm;
+	struct otg_fsm *fsm = &fsl_otg_dev->otg.fsm;
 	char *next = buf;
 	unsigned size = PAGE_SIZE;
 	int t;
@@ -1084,26 +1077,26 @@ static long fsl_otg_ioctl(struct file *file, unsigned int cmd,
 		break;
 
 	case SET_A_SUSPEND_REQ:
-		fsl_otg_dev->fsm.a_suspend_req_inf = arg;
+		fsl_otg_dev->otg.fsm.a_suspend_req_inf = arg;
 		break;
 
 	case SET_A_BUS_DROP:
-		fsl_otg_dev->fsm.a_bus_drop = arg;
+		fsl_otg_dev->otg.fsm.a_bus_drop = arg;
 		break;
 
 	case SET_A_BUS_REQ:
-		fsl_otg_dev->fsm.a_bus_req = arg;
+		fsl_otg_dev->otg.fsm.a_bus_req = arg;
 		break;
 
 	case SET_B_BUS_REQ:
-		fsl_otg_dev->fsm.b_bus_req = arg;
+		fsl_otg_dev->otg.fsm.b_bus_req = arg;
 		break;
 
 	default:
 		break;
 	}
 
-	otg_statemachine(&fsl_otg_dev->fsm);
+	otg_statemachine(&fsl_otg_dev->otg);
 
 	return retval;
 }
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index 2314995..e207cfb 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -15,7 +15,6 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/usb/otg-fsm.h>
 #include <linux/usb/otg.h>
 #include <linux/ioctl.h>
 
@@ -370,7 +369,7 @@ inline struct fsl_otg_timer *otg_timer_initializer
 
 struct fsl_otg {
 	struct usb_phy phy;
-	struct otg_fsm fsm;
+	struct usb_otg otg;
 	struct usb_dr_mmap *dr_mem_map;
 	struct delayed_work otg_event;
 
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index a0a8f87..26e6531 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -188,7 +188,6 @@ struct otg_fsm {
 	int a_bidl_adis_tmout;
 
 	struct otg_fsm_ops *ops;
-	struct usb_otg *otg;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
 	int protocol;
@@ -198,126 +197,23 @@ struct otg_fsm {
 	bool state_changed;
 };
 
+struct usb_otg;
+
 struct otg_fsm_ops {
-	void	(*chrg_vbus)(struct otg_fsm *fsm, int on);
-	void	(*drv_vbus)(struct otg_fsm *fsm, int on);
-	void	(*loc_conn)(struct otg_fsm *fsm, int on);
-	void	(*loc_sof)(struct otg_fsm *fsm, int on);
-	void	(*start_pulse)(struct otg_fsm *fsm);
-	void	(*start_adp_prb)(struct otg_fsm *fsm);
-	void	(*start_adp_sns)(struct otg_fsm *fsm);
-	void	(*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer);
-	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);
+	void	(*chrg_vbus)(struct usb_otg *otg, int on);
+	void	(*drv_vbus)(struct usb_otg *otg, int on);
+	void	(*loc_conn)(struct usb_otg *otg, int on);
+	void	(*loc_sof)(struct usb_otg *otg, int on);
+	void	(*start_pulse)(struct usb_otg *otg);
+	void	(*start_adp_prb)(struct usb_otg *otg);
+	void	(*start_adp_sns)(struct usb_otg *otg);
+	void	(*add_timer)(struct usb_otg *otg, enum otg_fsm_timer timer);
+	void	(*del_timer)(struct usb_otg *otg, enum otg_fsm_timer timer);
+	int	(*start_host)(struct usb_otg *otg, int on);
+	int	(*start_gadget)(struct usb_otg *otg, int on);
 };
 
 
-static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->chrg_vbus)
-		return -EOPNOTSUPP;
-	fsm->ops->chrg_vbus(fsm, on);
-	return 0;
-}
-
-static inline int otg_drv_vbus(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->drv_vbus)
-		return -EOPNOTSUPP;
-	if (fsm->drv_vbus != on) {
-		fsm->drv_vbus = on;
-		fsm->ops->drv_vbus(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_loc_conn(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->loc_conn)
-		return -EOPNOTSUPP;
-	if (fsm->loc_conn != on) {
-		fsm->loc_conn = on;
-		fsm->ops->loc_conn(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_loc_sof(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->loc_sof)
-		return -EOPNOTSUPP;
-	if (fsm->loc_sof != on) {
-		fsm->loc_sof = on;
-		fsm->ops->loc_sof(fsm, on);
-	}
-	return 0;
-}
-
-static inline int otg_start_pulse(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_pulse)
-		return -EOPNOTSUPP;
-	if (!fsm->data_pulse) {
-		fsm->data_pulse = 1;
-		fsm->ops->start_pulse(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_start_adp_prb(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_adp_prb)
-		return -EOPNOTSUPP;
-	if (!fsm->adp_prb) {
-		fsm->adp_sns = 0;
-		fsm->adp_prb = 1;
-		fsm->ops->start_adp_prb(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_start_adp_sns(struct otg_fsm *fsm)
-{
-	if (!fsm->ops->start_adp_sns)
-		return -EOPNOTSUPP;
-	if (!fsm->adp_sns) {
-		fsm->adp_sns = 1;
-		fsm->ops->start_adp_sns(fsm);
-	}
-	return 0;
-}
-
-static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
-{
-	if (!fsm->ops->add_timer)
-		return -EOPNOTSUPP;
-	fsm->ops->add_timer(fsm, timer);
-	return 0;
-}
-
-static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer)
-{
-	if (!fsm->ops->del_timer)
-		return -EOPNOTSUPP;
-	fsm->ops->del_timer(fsm, timer);
-	return 0;
-}
-
-static inline int otg_start_host(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->start_host)
-		return -EOPNOTSUPP;
-	return fsm->ops->start_host(fsm, on);
-}
-
-static inline int otg_start_gadget(struct otg_fsm *fsm, int on)
-{
-	if (!fsm->ops->start_gadget)
-		return -EOPNOTSUPP;
-	return fsm->ops->start_gadget(fsm, on);
-}
-
-int otg_statemachine(struct otg_fsm *fsm);
+int otg_statemachine(struct usb_otg *otg);
 
 #endif /* __LINUX_USB_OTG_FSM_H */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 67929df..e8a14dc 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -11,6 +11,7 @@
 
 #include <linux/phy/phy.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/otg-fsm.h>
 
 struct usb_otg {
 	u8			default_a;
@@ -22,6 +23,7 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct otg_fsm fsm;
 
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
@@ -128,4 +130,109 @@ enum usb_dr_mode {
  */
 extern enum usb_dr_mode usb_get_dr_mode(struct device *dev);
 
+static inline int otg_chrg_vbus(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->chrg_vbus)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->chrg_vbus(otg, on);
+	return 0;
+}
+
+static inline int otg_drv_vbus(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->drv_vbus)
+		return -EOPNOTSUPP;
+	if (otg->fsm.drv_vbus != on) {
+		otg->fsm.drv_vbus = on;
+		otg->fsm.ops->drv_vbus(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_loc_conn(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->loc_conn)
+		return -EOPNOTSUPP;
+	if (otg->fsm.loc_conn != on) {
+		otg->fsm.loc_conn = on;
+		otg->fsm.ops->loc_conn(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_loc_sof(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->loc_sof)
+		return -EOPNOTSUPP;
+	if (otg->fsm.loc_sof != on) {
+		otg->fsm.loc_sof = on;
+		otg->fsm.ops->loc_sof(otg, on);
+	}
+	return 0;
+}
+
+static inline int otg_start_pulse(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_pulse)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.data_pulse) {
+		otg->fsm.data_pulse = 1;
+		otg->fsm.ops->start_pulse(otg);
+	}
+	return 0;
+}
+
+static inline int otg_start_adp_prb(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_adp_prb)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.adp_prb) {
+		otg->fsm.adp_sns = 0;
+		otg->fsm.adp_prb = 1;
+		otg->fsm.ops->start_adp_prb(otg);
+	}
+	return 0;
+}
+
+static inline int otg_start_adp_sns(struct usb_otg *otg)
+{
+	if (!otg->fsm.ops->start_adp_sns)
+		return -EOPNOTSUPP;
+	if (!otg->fsm.adp_sns) {
+		otg->fsm.adp_sns = 1;
+		otg->fsm.ops->start_adp_sns(otg);
+	}
+	return 0;
+}
+
+static inline int otg_add_timer(struct usb_otg *otg, enum otg_fsm_timer timer)
+{
+	if (!otg->fsm.ops->add_timer)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->add_timer(otg, timer);
+	return 0;
+}
+
+static inline int otg_del_timer(struct usb_otg *otg, enum otg_fsm_timer timer)
+{
+	if (!otg->fsm.ops->del_timer)
+		return -EOPNOTSUPP;
+	otg->fsm.ops->del_timer(otg, timer);
+	return 0;
+}
+
+static inline int otg_start_host(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->start_host)
+		return -EOPNOTSUPP;
+	return otg->fsm.ops->start_host(otg, on);
+}
+
+static inline int otg_start_gadget(struct usb_otg *otg, int on)
+{
+	if (!otg->fsm.ops->start_gadget)
+		return -EOPNOTSUPP;
+	return otg->fsm.ops->start_gadget(otg, on);
+}
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

* [PATCH v10 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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@nxp.com>
---
 drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
 drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
 drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
 include/linux/usb/otg.h          |  2 ++
 4 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 1c0c750..2d8d659 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
 	.start_gadget = ci_otg_start_gadget,
 };
 
+static struct otg_hcd_ops ci_hcd_ops = {
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
 int ci_otg_fsm_work(struct ci_hdrc *ci)
 {
 	/*
@@ -804,6 +810,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 	ci->otg.fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
 	ci->otg.state = OTG_STATE_UNDEFINED;
 	ci->otg.fsm.ops = &ci_otg_ops;
+	ci->otg.hcd_ops = &ci_hcd_ops;
 	ci->gadget.hnp_polling_support = 1;
 	ci->otg.fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
 	if (!ci->otg.fsm.host_req_flag)
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 610b5bd6..482d4c9 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -141,11 +141,16 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	enum usb_otg_state state = otg->state;
 	u8 flag;
 	int retval;
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
 
 	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
 		return;
 
-	udev = usb_hub_find_child(otg->host->root_hub, 1);
+	if (!hcd_ops || !hcd_ops->usb_control_msg ||
+	    !hcd_ops->usb_hub_find_child)
+		return;
+
+	udev = hcd_ops->usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev) {
 		dev_err(otg->host->controller,
 			"no usb dev connected, can't start HNP polling\n");
@@ -154,7 +159,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 
 	*fsm->host_req_flag = 0;
 	/* Get host request flag from connected USB device */
-	retval = usb_control_msg(udev,
+	retval = hcd_ops->usb_control_msg(udev,
 				usb_rcvctrlpipe(udev, 0),
 				USB_REQ_GET_STATUS,
 				USB_DIR_IN | USB_RECIP_DEVICE,
@@ -183,7 +188,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	if (state == OTG_STATE_A_HOST) {
 		/* Set b_hnp_enable */
 		if (!otg->host->b_hnp_enable) {
-			retval = usb_control_msg(udev,
+			retval = hcd_ops->usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_SET_FEATURE, 0,
 					USB_DEVICE_B_HNP_ENABLE,
@@ -262,7 +267,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_conn(otg, 0);
 		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(otg->host, otg->host->otg_port);
+		if (otg->hcd_ops && otg->hcd_ops->usb_bus_start_enum)
+			otg->hcd_ops->usb_bus_start_enum(otg->host,
+							 otg->host->otg_port);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_IDLE:
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 3ffa4c6..011d36e 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -792,6 +792,12 @@ static struct otg_fsm_ops fsl_otg_ops = {
 	.start_gadget = fsl_otg_start_gadget,
 };
 
+static struct otg_hcd_ops fsl_hcd_ops = {
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
 /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
 static int fsl_otg_conf(struct platform_device *pdev)
 {
@@ -820,6 +826,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
 
 	/* Set OTG state machine operations */
 	fsl_otg_tc->otg.fsm.ops = &fsl_otg_ops;
+	fsl_otg_tc->otg.hcd_ops = &fsl_hcd_ops;
 
 	/* initialize the otg structure */
 	fsl_otg_tc->phy.label = DRIVER_DESC;
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index e8a14dc..85b8fb5 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -12,6 +12,7 @@
 #include <linux/phy/phy.h>
 #include <linux/usb/phy.h>
 #include <linux/usb/otg-fsm.h>
+#include <linux/usb/hcd.h>
 
 struct usb_otg {
 	u8			default_a;
@@ -24,6 +25,7 @@ struct usb_otg {
 
 	enum usb_otg_state	state;
 	struct otg_fsm fsm;
+	struct otg_hcd_ops	*hcd_ops;
 
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
-- 
2.7.4

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

* [PATCH v10 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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@nxp.com>
---
 drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
 drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
 drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
 include/linux/usb/otg.h          |  2 ++
 4 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 1c0c750..2d8d659 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
 	.start_gadget = ci_otg_start_gadget,
 };
 
+static struct otg_hcd_ops ci_hcd_ops = {
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
 int ci_otg_fsm_work(struct ci_hdrc *ci)
 {
 	/*
@@ -804,6 +810,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
 	ci->otg.fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
 	ci->otg.state = OTG_STATE_UNDEFINED;
 	ci->otg.fsm.ops = &ci_otg_ops;
+	ci->otg.hcd_ops = &ci_hcd_ops;
 	ci->gadget.hnp_polling_support = 1;
 	ci->otg.fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
 	if (!ci->otg.fsm.host_req_flag)
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 610b5bd6..482d4c9 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -141,11 +141,16 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	enum usb_otg_state state = otg->state;
 	u8 flag;
 	int retval;
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
 
 	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
 		return;
 
-	udev = usb_hub_find_child(otg->host->root_hub, 1);
+	if (!hcd_ops || !hcd_ops->usb_control_msg ||
+	    !hcd_ops->usb_hub_find_child)
+		return;
+
+	udev = hcd_ops->usb_hub_find_child(otg->host->root_hub, 1);
 	if (!udev) {
 		dev_err(otg->host->controller,
 			"no usb dev connected, can't start HNP polling\n");
@@ -154,7 +159,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 
 	*fsm->host_req_flag = 0;
 	/* Get host request flag from connected USB device */
-	retval = usb_control_msg(udev,
+	retval = hcd_ops->usb_control_msg(udev,
 				usb_rcvctrlpipe(udev, 0),
 				USB_REQ_GET_STATUS,
 				USB_DIR_IN | USB_RECIP_DEVICE,
@@ -183,7 +188,7 @@ static void otg_hnp_polling_work(struct work_struct *work)
 	if (state == OTG_STATE_A_HOST) {
 		/* Set b_hnp_enable */
 		if (!otg->host->b_hnp_enable) {
-			retval = usb_control_msg(udev,
+			retval = hcd_ops->usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_SET_FEATURE, 0,
 					USB_DEVICE_B_HNP_ENABLE,
@@ -262,7 +267,9 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 		otg_loc_conn(otg, 0);
 		otg_loc_sof(otg, 1);
 		otg_set_protocol(fsm, PROTO_HOST);
-		usb_bus_start_enum(otg->host, otg->host->otg_port);
+		if (otg->hcd_ops && otg->hcd_ops->usb_bus_start_enum)
+			otg->hcd_ops->usb_bus_start_enum(otg->host,
+							 otg->host->otg_port);
 		otg_start_hnp_polling(fsm);
 		break;
 	case OTG_STATE_A_IDLE:
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 3ffa4c6..011d36e 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -792,6 +792,12 @@ static struct otg_fsm_ops fsl_otg_ops = {
 	.start_gadget = fsl_otg_start_gadget,
 };
 
+static struct otg_hcd_ops fsl_hcd_ops = {
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
 /* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
 static int fsl_otg_conf(struct platform_device *pdev)
 {
@@ -820,6 +826,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
 
 	/* Set OTG state machine operations */
 	fsl_otg_tc->otg.fsm.ops = &fsl_otg_ops;
+	fsl_otg_tc->otg.hcd_ops = &fsl_hcd_ops;
 
 	/* initialize the otg structure */
 	fsl_otg_tc->phy.label = DRIVER_DESC;
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index e8a14dc..85b8fb5 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -12,6 +12,7 @@
 #include <linux/phy/phy.h>
 #include <linux/usb/phy.h>
 #include <linux/usb/otg-fsm.h>
+#include <linux/usb/hcd.h>
 
 struct usb_otg {
 	u8			default_a;
@@ -24,6 +25,7 @@ struct usb_otg {
 
 	enum usb_otg_state	state;
 	struct otg_fsm fsm;
+	struct otg_hcd_ops	*hcd_ops;
 
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
-- 
2.7.4

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

* [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, 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>
---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 2dd9e6b..f4fc0aa 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -639,6 +639,22 @@ 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
+ * @connect_control: function to connect/disconnect from the bus
+ */
+struct otg_gadget_ops {
+	int (*start)(struct usb_gadget *gadget);
+	int (*stop)(struct usb_gadget *gadget);
+	int (*connect_control)(struct usb_gadget *gadget, bool connect);
+};
 
 /*-------------------------------------------------------------------------*/
 
-- 
2.7.4

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

* [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, 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-l0cyMroinI0@public.gmane.org>
---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 2dd9e6b..f4fc0aa 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -639,6 +639,22 @@ 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
+ * @connect_control: function to connect/disconnect from the bus
+ */
+struct otg_gadget_ops {
+	int (*start)(struct usb_gadget *gadget);
+	int (*stop)(struct usb_gadget *gadget);
+	int (*connect_control)(struct usb_gadget *gadget, bool connect);
+};
 
 /*-------------------------------------------------------------------------*/
 
-- 
2.7.4

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

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

* [PATCH v10 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Let's use CONFIG_USB_OTG as a single config option to enable
USB OTG and the OTG FSM. This makes things a lot less confusing.

Update all users of CONFIG_USB_OTG_FSM to CONFIG_USB_OTG.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.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/common/Makefile    | 3 ++-
 drivers/usb/core/Kconfig       | 8 --------
 drivers/usb/phy/Kconfig        | 2 +-
 7 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt
index edf7cdf..580d157 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
 ---------------------------------------
-1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
+1.1.1 Select CONFIG_USB_OTG in menuconfig, rebuild kernel
 Image and modules. If you want to check some internal
 variables for otg fsm, mount debugfs, 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 518e445..45aa24d 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 ci_hdrc-y				:= core.o otg.o debug.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.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 c523975..1a32b8c 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -406,7 +406,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 6366fe3..2d451bb 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -64,7 +64,7 @@
 
 #define TB_AIDL_BDIS         (20)	/* 4ms ~ 150ms, section 5.2.1 */
 
-#if IS_ENABLED(CONFIG_USB_OTG_FSM)
+#if IS_ENABLED(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/common/Makefile b/drivers/usb/common/Makefile
index 6bbb3ec..f8f2c88 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-fsm.o
+obj-$(CONFIG_USB_OTG)	+= usbotg.o
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index dd28010..ae228d0 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -75,14 +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 && 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/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index ca50944..66a79d3 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 && USB_OTG && PM
 	select USB_PHY
 	help
 	  Enable this to support Freescale USB OTG transceiver.
-- 
2.7.4

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

* [PATCH v10 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Let's use CONFIG_USB_OTG as a single config option to enable
USB OTG and the OTG FSM. This makes things a lot less confusing.

Update all users of CONFIG_USB_OTG_FSM to CONFIG_USB_OTG.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.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/common/Makefile    | 3 ++-
 drivers/usb/core/Kconfig       | 8 --------
 drivers/usb/phy/Kconfig        | 2 +-
 7 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt
index edf7cdf..580d157 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
 ---------------------------------------
-1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
+1.1.1 Select CONFIG_USB_OTG in menuconfig, rebuild kernel
 Image and modules. If you want to check some internal
 variables for otg fsm, mount debugfs, 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 518e445..45aa24d 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 ci_hdrc-y				:= core.o otg.o debug.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.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 c523975..1a32b8c 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -406,7 +406,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 6366fe3..2d451bb 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -64,7 +64,7 @@
 
 #define TB_AIDL_BDIS         (20)	/* 4ms ~ 150ms, section 5.2.1 */
 
-#if IS_ENABLED(CONFIG_USB_OTG_FSM)
+#if IS_ENABLED(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/common/Makefile b/drivers/usb/common/Makefile
index 6bbb3ec..f8f2c88 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-fsm.o
+obj-$(CONFIG_USB_OTG)	+= usbotg.o
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index dd28010..ae228d0 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -75,14 +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 && 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/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index ca50944..66a79d3 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 && USB_OTG && PM
 	select USB_PHY
 	help
 	  Enable this to support Freescale USB OTG transceiver.
-- 
2.7.4

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

* [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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/Kconfig          |  18 +
 drivers/usb/Makefile         |   1 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 906 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 180 ++++++++-
 10 files changed, 1106 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca7856..03f7204 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= common/
+obj-$(CONFIG_USB_OTG_CORE)	+= common/
 
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..4185954
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,906 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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;
+}
+
+/**
+ * usb_otg_get_data() - get usb_otg data structa
+ * @otg_dev:	OTG controller device
+ *
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ *
+ * Return: usb_otg data on success, NULL otherwise.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host() - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		/* start host */
+		ret = hcd_ops->add(otg->primary_hcd.hcd,
+				   otg->primary_hcd.irqnum,
+				   otg->primary_hcd.irqflags);
+		if (ret) {
+			dev_err(otg->dev, "otg: host add failed %d\n", ret);
+			return ret;
+		}
+
+		if (otg->shared_hcd.hcd) {
+			ret = hcd_ops->add(otg->shared_hcd.hcd,
+					   otg->shared_hcd.irqnum,
+					   otg->shared_hcd.irqflags);
+			if (ret) {
+				dev_err(otg->dev, "otg: shared host add failed %d\n",
+					ret);
+				hcd_ops->remove(otg->primary_hcd.hcd);
+				return ret;
+			}
+		}
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget() - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		ret = otg->gadget_ops->start(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget start failed: %d\n",
+				ret);
+			return ret;
+		}
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		ret = otg->gadget_ops->stop(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
+				ret);
+			return ret;
+		}
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * drd_set_protocol() -  Set USB protocol if possible
+ * @fsm:	DRD FSM instance
+ * @protocol:	USB protocol to set the state machine to
+ *
+ * Sets the OTG FSM protocol to @protocol if it changed.
+ * fsm->lock must be held.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * drd_set_state() - Set the DRD state machine state.
+ * @fsm:	DRD FSM instance
+ * @new_state:	the new state the DRD FSM must be set to
+ *
+ * Sets the state of the DRD state machine.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * drd_statemachine() - DRD state change judgement
+ * @otg:	usb_otg instance
+ *
+ * Checks the state machine inputs and state and makes a state change
+ * if required.
+ *
+ * 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
+ *
+ * Return: 0 if state wasn't changed, 1 if state changed.
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * usb_drd_work() - Dual-role state machine work function
+ * @work: work_struct context
+ *
+ * Runs the DRD state machine. Scheduled whenever there is a change
+ * in FSM inputs.
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+		;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() otherwise.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * usb_otg_start_fsm() - Start the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
+ * must be ready for the OTG FSM to start.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * usb_otg_stop_fsm() - Stop the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Stops the HCD, UDC and the OTG FSM.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 0);
+	}
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
+ * @otg:	usb_otg 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm() - Kick the OTG state machine
+ * @otg_dev:	OTG controller device
+ *
+ * Used by USB host/gadget stack to sync OTG related
+ * events to the OTG state machine.
+ * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(otg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd() - Register the host controller to OTG core
+ * @hcd:	host controller
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * Return: 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd() - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget() - Register the gadget controller to OTG core
+ * @gadget:	gadget controller instance
+ * @ops:	gadget interface ops
+ *
+ * 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.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget() - Unregister the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
+ * @gadget:	gadget controller
+ * @ready:	0: function driver ready, 1: function driver not ready
+ *
+ * Notify the OTG core about status of the gadget function driver.
+ * As OTG core is responsible to start/stop the gadget controller, it
+ * must be aware when the gadget function driver is available or not.
+ * This function is used by the Gadget core to inform the OTG core
+ * about the gadget function driver readyness.
+ *
+ * Return: 0 on sucess, error value otherwise.
+ */
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3c3f31c..5fc9095 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f4fc0aa..1d74fb8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -328,6 +328,7 @@ struct usb_gadget_ops {
  * @in_epnum: last used in ep number
  * @mA: last set mA value
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -385,6 +386,7 @@ struct usb_gadget {
 	unsigned			in_epnum;
 	unsigned			mA;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..2175fb7 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,67 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @otg_dev: OTG controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of OTG controllers
+ * @work: OTG state machine work
+ * @wq: OTG state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +81,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +115,101 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - OTG controller configuration
+ * @caps: OTG capabilities of the controller
+ * @ops: OTG FSM operations
+ * @otg_work: optional custom OTG state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_kick_fsm(struct device *otg_dev);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +261,8 @@ 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);
 
@@ -237,4 +387,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

* [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/Kconfig          |  18 +
 drivers/usb/Makefile         |   1 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 906 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 180 ++++++++-
 10 files changed, 1106 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca7856..03f7204 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= common/
+obj-$(CONFIG_USB_OTG_CORE)	+= common/
 
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..4185954
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,906 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
+ *
+ * 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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;
+}
+
+/**
+ * usb_otg_get_data() - get usb_otg data structa
+ * @otg_dev:	OTG controller device
+ *
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ *
+ * Return: usb_otg data on success, NULL otherwise.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host() - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		/* start host */
+		ret = hcd_ops->add(otg->primary_hcd.hcd,
+				   otg->primary_hcd.irqnum,
+				   otg->primary_hcd.irqflags);
+		if (ret) {
+			dev_err(otg->dev, "otg: host add failed %d\n", ret);
+			return ret;
+		}
+
+		if (otg->shared_hcd.hcd) {
+			ret = hcd_ops->add(otg->shared_hcd.hcd,
+					   otg->shared_hcd.irqnum,
+					   otg->shared_hcd.irqflags);
+			if (ret) {
+				dev_err(otg->dev, "otg: shared host add failed %d\n",
+					ret);
+				hcd_ops->remove(otg->primary_hcd.hcd);
+				return ret;
+			}
+		}
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget() - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		ret = otg->gadget_ops->start(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget start failed: %d\n",
+				ret);
+			return ret;
+		}
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		ret = otg->gadget_ops->stop(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
+				ret);
+			return ret;
+		}
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * drd_set_protocol() -  Set USB protocol if possible
+ * @fsm:	DRD FSM instance
+ * @protocol:	USB protocol to set the state machine to
+ *
+ * Sets the OTG FSM protocol to @protocol if it changed.
+ * fsm->lock must be held.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * drd_set_state() - Set the DRD state machine state.
+ * @fsm:	DRD FSM instance
+ * @new_state:	the new state the DRD FSM must be set to
+ *
+ * Sets the state of the DRD state machine.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * drd_statemachine() - DRD state change judgement
+ * @otg:	usb_otg instance
+ *
+ * Checks the state machine inputs and state and makes a state change
+ * if required.
+ *
+ * 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
+ *
+ * Return: 0 if state wasn't changed, 1 if state changed.
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * usb_drd_work() - Dual-role state machine work function
+ * @work: work_struct context
+ *
+ * Runs the DRD state machine. Scheduled whenever there is a change
+ * in FSM inputs.
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+		;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() otherwise.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * usb_otg_start_fsm() - Start the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
+ * must be ready for the OTG FSM to start.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * usb_otg_stop_fsm() - Stop the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Stops the HCD, UDC and the OTG FSM.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 0);
+	}
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
+ * @otg:	usb_otg 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm() - Kick the OTG state machine
+ * @otg_dev:	OTG controller device
+ *
+ * Used by USB host/gadget stack to sync OTG related
+ * events to the OTG state machine.
+ * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(otg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd() - Register the host controller to OTG core
+ * @hcd:	host controller
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * Return: 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd() - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget() - Register the gadget controller to OTG core
+ * @gadget:	gadget controller instance
+ * @ops:	gadget interface ops
+ *
+ * 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.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget() - Unregister the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
+ * @gadget:	gadget controller
+ * @ready:	0: function driver ready, 1: function driver not ready
+ *
+ * Notify the OTG core about status of the gadget function driver.
+ * As OTG core is responsible to start/stop the gadget controller, it
+ * must be aware when the gadget function driver is available or not.
+ * This function is used by the Gadget core to inform the OTG core
+ * about the gadget function driver readyness.
+ *
+ * Return: 0 on sucess, error value otherwise.
+ */
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3c3f31c..5fc9095 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f4fc0aa..1d74fb8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -328,6 +328,7 @@ struct usb_gadget_ops {
  * @in_epnum: last used in ep number
  * @mA: last set mA value
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -385,6 +386,7 @@ struct usb_gadget {
 	unsigned			in_epnum;
 	unsigned			mA;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..2175fb7 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,67 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @otg_dev: OTG controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of OTG controllers
+ * @work: OTG state machine work
+ * @wq: OTG state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +81,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +115,101 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - OTG controller configuration
+ * @caps: OTG capabilities of the controller
+ * @ops: OTG FSM operations
+ * @otg_work: optional custom OTG state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_kick_fsm(struct device *otg_dev);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +261,8 @@ 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);
 
@@ -237,4 +387,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

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

* [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

The OTG controller and the USB controller can be linked via the
'otg-controller' property in the USB controller's device node.

of_usb_get_otg() can be used to get the OTG controller device
from the USB controller's device node.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/common.c                       | 27 +++++++++++++++++++++++
 include/linux/usb/of.h                            |  9 ++++++++
 3 files changed, 39 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index bba8257..f6866c1 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -24,6 +24,9 @@ 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.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index e3d0161..d7ec471 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
 
+#ifdef CONFIG_USB_OTG
+/**
+ * of_usb_get_otg - get the OTG controller linked to the USB controller
+ * @np: Pointer to the device_node of the USB controller
+ * @otg_caps: Pointer to the target usb_otg_caps to be set
+ *
+ * Returns the OTG controller device or NULL on error.
+ */
+struct device *of_usb_get_otg(struct device_node *np)
+{
+	struct device_node *otg_np;
+	struct platform_device *pdev;
+
+	otg_np = of_parse_phandle(np, "otg-controller", 0);
+	if (!otg_np)
+		return NULL;
+
+	pdev = of_find_device_by_node(otg_np);
+	of_node_put(otg_np);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_otg);
+#endif
+
 #endif
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index de3237f..499a4e8 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -40,6 +40,15 @@ static inline struct device_node *usb_of_get_child_node
 }
 #endif
 
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG)
+struct device *of_usb_get_otg(struct device_node *np);
+#else
+static inline struct device *of_usb_get_otg(struct device_node *np)
+{
+	return NULL;
+}
+#endif
+
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
-- 
2.7.4

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

* [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

The OTG controller and the USB controller can be linked via the
'otg-controller' property in the USB controller's device node.

of_usb_get_otg() can be used to get the OTG controller device
from the USB controller's device node.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/common.c                       | 27 +++++++++++++++++++++++
 include/linux/usb/of.h                            |  9 ++++++++
 3 files changed, 39 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index bba8257..f6866c1 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -24,6 +24,9 @@ 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.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index e3d0161..d7ec471 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
 
+#ifdef CONFIG_USB_OTG
+/**
+ * of_usb_get_otg - get the OTG controller linked to the USB controller
+ * @np: Pointer to the device_node of the USB controller
+ * @otg_caps: Pointer to the target usb_otg_caps to be set
+ *
+ * Returns the OTG controller device or NULL on error.
+ */
+struct device *of_usb_get_otg(struct device_node *np)
+{
+	struct device_node *otg_np;
+	struct platform_device *pdev;
+
+	otg_np = of_parse_phandle(np, "otg-controller", 0);
+	if (!otg_np)
+		return NULL;
+
+	pdev = of_find_device_by_node(otg_np);
+	of_node_put(otg_np);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_otg);
+#endif
+
 #endif
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index de3237f..499a4e8 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -40,6 +40,15 @@ static inline struct device_node *usb_of_get_child_node
 }
 #endif
 
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG)
+struct device *of_usb_get_otg(struct device_node *np);
+#else
+static inline struct device *of_usb_get_otg(struct device_node *np)
+{
+	return NULL;
+}
+#endif
+
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
-- 
2.7.4

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

* [PATCH v10 10/14] usb: otg: add hcd companion support
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

Since some host controller (e.g. EHCI) needs a companion host controller
(e.g. OHCI), this patch adds such a configuration to use it in the OTG
core.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/usb-otg.c                      | 31 ++++++++++++++++-------
 include/linux/usb/otg.h                           |  7 ++++-
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index f6866c1..1db1c33 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -27,6 +27,9 @@ Optional properties:
  - otg-controller: phandle to otg controller. Host or gadget controllers can
 			contain this property to link it to a particular OTG
 			controller.
+ - hcd-needs-companion: must be present if otg controller is dealing with
+			EHCI host controller that needs a companion OHCI host
+			controller.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 4185954..c663f4a 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -402,6 +402,10 @@ struct usb_otg *usb_otg_register(struct device *dev,
 	else
 		INIT_WORK(&otg->work, usb_drd_work);
 
+	if (of_find_property(dev->of_node, "hcd-needs-companion", NULL) ||
+	    config->hcd_needs_companion)	/* needs companion ? */
+		otg->flags |= OTG_FLAG_HCD_NEEDS_COMPANION;
+
 	otg->wq = create_freezable_workqueue("usb_otg");
 	if (!otg->wq) {
 		dev_err(dev, "otg: %s: can't create workqueue\n",
@@ -626,15 +630,18 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 	/* HCD will be started by OTG fsm when needed */
 	mutex_lock(&otg->fsm.lock);
 	if (otg->primary_hcd.hcd) {
-		/* probably a shared HCD ? */
-		if (usb_otg_hcd_is_primary_hcd(hcd)) {
+		/* probably a shared HCD or a companion OHCI HCD ? */
+		if (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+		    usb_otg_hcd_is_primary_hcd(hcd)) {
 			dev_err(otg_dev, "otg: primary host already registered\n");
 			goto err;
 		}
 
-		if (hcd->shared_hcd == otg->primary_hcd.hcd) {
+		if (otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION ||
+		    (hcd->shared_hcd == otg->primary_hcd.hcd)) {
 			if (otg->shared_hcd.hcd) {
-				dev_err(otg_dev, "otg: shared host already registered\n");
+				dev_err(otg_dev,
+					"otg: shared/companion host already registered\n");
 				goto err;
 			}
 
@@ -642,10 +649,12 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 			otg->shared_hcd.irqnum = irqnum;
 			otg->shared_hcd.irqflags = irqflags;
 			otg->shared_hcd.ops = ops;
-			dev_info(otg_dev, "otg: shared host %s registered\n",
+			dev_info(otg_dev,
+				 "otg: shared/companion host %s registered\n",
 				 dev_name(hcd->self.controller));
 		} else {
-			dev_err(otg_dev, "otg: invalid shared host %s\n",
+			dev_err(otg_dev,
+				"otg: invalid shared/companion host %s\n",
 				dev_name(hcd->self.controller));
 			goto err;
 		}
@@ -668,14 +677,17 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 	 * we're ready only if we have shared HCD
 	 * or we don't need shared HCD.
 	 */
-	if (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+	if (otg->shared_hcd.hcd ||
+	    (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+	     !otg->primary_hcd.hcd->shared_hcd)) {
 		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(otg);
 	} else {
-		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+		dev_dbg(otg_dev,
+			"otg: can't start till shared/companion host registers\n");
 	}
 
 	mutex_unlock(&otg->fsm.lock);
@@ -723,7 +735,8 @@ int usb_otg_unregister_hcd(struct usb_hcd *hcd)
 			 dev_name(hcd_dev));
 	} else if (hcd == otg->shared_hcd.hcd) {
 		otg->shared_hcd.hcd = NULL;
-		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+		dev_info(otg_dev,
+			 "otg: shared/companion host %s unregistered\n",
 			 dev_name(hcd_dev));
 	} else {
 		mutex_unlock(&otg->fsm.lock);
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 2175fb7..61d524e 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -69,7 +69,8 @@ struct usb_otg_caps {
  * @list: list of OTG controllers
  * @work: OTG state machine work
  * @wq: OTG state machine work queue
- * @flags: to track if host/gadget is running
+ * @flags: to track if host/gadget is running, or to indicate if hcd needs
+ *	   companion
  */
 struct usb_otg {
 	u8			default_a;
@@ -97,6 +98,7 @@ struct usb_otg {
 	u32 flags;
 #define OTG_FLAG_GADGET_RUNNING (1 << 0)
 #define OTG_FLAG_HOST_RUNNING (1 << 1)
+#define OTG_FLAG_HCD_NEEDS_COMPANION (1 << 2)
 	/* use otg->fsm.lock for serializing access */
 
 /*------------- deprecated interface -----------------------------*/
@@ -123,11 +125,14 @@ struct usb_otg {
  * @caps: OTG capabilities of the controller
  * @ops: OTG FSM operations
  * @otg_work: optional custom OTG state machine work function
+ * @hcd_needs_companion: Indicates if host controller needs a companion
+ *			 controller
  */
 struct usb_otg_config {
 	struct usb_otg_caps *otg_caps;
 	struct otg_fsm_ops *fsm_ops;
 	void (*otg_work)(struct work_struct *work);
+	bool hcd_needs_companion;
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
-- 
2.7.4

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

* [PATCH v10 10/14] usb: otg: add hcd companion support
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

Since some host controller (e.g. EHCI) needs a companion host controller
(e.g. OHCI), this patch adds such a configuration to use it in the OTG
core.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/usb-otg.c                      | 31 ++++++++++++++++-------
 include/linux/usb/otg.h                           |  7 ++++-
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index f6866c1..1db1c33 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -27,6 +27,9 @@ Optional properties:
  - otg-controller: phandle to otg controller. Host or gadget controllers can
 			contain this property to link it to a particular OTG
 			controller.
+ - hcd-needs-companion: must be present if otg controller is dealing with
+			EHCI host controller that needs a companion OHCI host
+			controller.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 4185954..c663f4a 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -402,6 +402,10 @@ struct usb_otg *usb_otg_register(struct device *dev,
 	else
 		INIT_WORK(&otg->work, usb_drd_work);
 
+	if (of_find_property(dev->of_node, "hcd-needs-companion", NULL) ||
+	    config->hcd_needs_companion)	/* needs companion ? */
+		otg->flags |= OTG_FLAG_HCD_NEEDS_COMPANION;
+
 	otg->wq = create_freezable_workqueue("usb_otg");
 	if (!otg->wq) {
 		dev_err(dev, "otg: %s: can't create workqueue\n",
@@ -626,15 +630,18 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 	/* HCD will be started by OTG fsm when needed */
 	mutex_lock(&otg->fsm.lock);
 	if (otg->primary_hcd.hcd) {
-		/* probably a shared HCD ? */
-		if (usb_otg_hcd_is_primary_hcd(hcd)) {
+		/* probably a shared HCD or a companion OHCI HCD ? */
+		if (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+		    usb_otg_hcd_is_primary_hcd(hcd)) {
 			dev_err(otg_dev, "otg: primary host already registered\n");
 			goto err;
 		}
 
-		if (hcd->shared_hcd == otg->primary_hcd.hcd) {
+		if (otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION ||
+		    (hcd->shared_hcd == otg->primary_hcd.hcd)) {
 			if (otg->shared_hcd.hcd) {
-				dev_err(otg_dev, "otg: shared host already registered\n");
+				dev_err(otg_dev,
+					"otg: shared/companion host already registered\n");
 				goto err;
 			}
 
@@ -642,10 +649,12 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 			otg->shared_hcd.irqnum = irqnum;
 			otg->shared_hcd.irqflags = irqflags;
 			otg->shared_hcd.ops = ops;
-			dev_info(otg_dev, "otg: shared host %s registered\n",
+			dev_info(otg_dev,
+				 "otg: shared/companion host %s registered\n",
 				 dev_name(hcd->self.controller));
 		} else {
-			dev_err(otg_dev, "otg: invalid shared host %s\n",
+			dev_err(otg_dev,
+				"otg: invalid shared/companion host %s\n",
 				dev_name(hcd->self.controller));
 			goto err;
 		}
@@ -668,14 +677,17 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
 	 * we're ready only if we have shared HCD
 	 * or we don't need shared HCD.
 	 */
-	if (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+	if (otg->shared_hcd.hcd ||
+	    (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+	     !otg->primary_hcd.hcd->shared_hcd)) {
 		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(otg);
 	} else {
-		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+		dev_dbg(otg_dev,
+			"otg: can't start till shared/companion host registers\n");
 	}
 
 	mutex_unlock(&otg->fsm.lock);
@@ -723,7 +735,8 @@ int usb_otg_unregister_hcd(struct usb_hcd *hcd)
 			 dev_name(hcd_dev));
 	} else if (hcd == otg->shared_hcd.hcd) {
 		otg->shared_hcd.hcd = NULL;
-		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+		dev_info(otg_dev,
+			 "otg: shared/companion host %s unregistered\n",
 			 dev_name(hcd_dev));
 	} else {
 		mutex_unlock(&otg->fsm.lock);
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 2175fb7..61d524e 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -69,7 +69,8 @@ struct usb_otg_caps {
  * @list: list of OTG controllers
  * @work: OTG state machine work
  * @wq: OTG state machine work queue
- * @flags: to track if host/gadget is running
+ * @flags: to track if host/gadget is running, or to indicate if hcd needs
+ *	   companion
  */
 struct usb_otg {
 	u8			default_a;
@@ -97,6 +98,7 @@ struct usb_otg {
 	u32 flags;
 #define OTG_FLAG_GADGET_RUNNING (1 << 0)
 #define OTG_FLAG_HOST_RUNNING (1 << 1)
+#define OTG_FLAG_HCD_NEEDS_COMPANION (1 << 2)
 	/* use otg->fsm.lock for serializing access */
 
 /*------------- deprecated interface -----------------------------*/
@@ -123,11 +125,14 @@ struct usb_otg {
  * @caps: OTG capabilities of the controller
  * @ops: OTG FSM operations
  * @otg_work: optional custom OTG state machine work function
+ * @hcd_needs_companion: Indicates if host controller needs a companion
+ *			 controller
  */
 struct usb_otg_config {
 	struct usb_otg_caps *otg_caps;
 	struct otg_fsm_ops *fsm_ops;
 	void (*otg_work)(struct work_struct *work);
+	bool hcd_needs_companion;
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
-- 
2.7.4

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

* [PATCH v10 11/14] usb: otg: use dev_vdbg() instead of VDBG()
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Now that we have a device reference in struct usb_otg
let's use dev_vdbg() for debug messages instead of VDBG().

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/common/usb-otg-fsm.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 482d4c9..e6e58c2 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -30,13 +30,6 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 
-#ifdef VERBOSE
-#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
-				 __func__, ## args)
-#else
-#define VDBG(stuff...)	do {} while (0)
-#endif
-
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
@@ -44,8 +37,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(otg->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(otg, 0);
@@ -226,7 +220,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
 	if (otg->state == new_state)
 		return 0;
-	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
+	dev_vdbg(otg->dev, "Set state: %s\n", usb_otg_state_string(new_state));
 	otg_leave_state(fsm, otg->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
@@ -358,7 +352,7 @@ int otg_statemachine(struct usb_otg *otg)
 
 	switch (state) {
 	case OTG_STATE_UNDEFINED:
-		VDBG("fsm->id = %d\n", fsm->id);
+		dev_vdbg(otg->dev, "fsm->id = %d\n", fsm->id);
 		if (fsm->id)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
 		else
@@ -466,7 +460,8 @@ int otg_statemachine(struct usb_otg *otg)
 	}
 	mutex_unlock(&fsm->lock);
 
-	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
+	dev_vdbg(otg->dev, "quit statemachine, changed = %d\n",
+		 fsm->state_changed);
 	return fsm->state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
-- 
2.7.4

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

* [PATCH v10 11/14] usb: otg: use dev_vdbg() instead of VDBG()
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Now that we have a device reference in struct usb_otg
let's use dev_vdbg() for debug messages instead of VDBG().

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/common/usb-otg-fsm.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 482d4c9..e6e58c2 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -30,13 +30,6 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 
-#ifdef VERBOSE
-#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
-				 __func__, ## args)
-#else
-#define VDBG(stuff...)	do {} while (0)
-#endif
-
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
@@ -44,8 +37,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(otg->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(otg, 0);
@@ -226,7 +220,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
 
 	if (otg->state == new_state)
 		return 0;
-	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
+	dev_vdbg(otg->dev, "Set state: %s\n", usb_otg_state_string(new_state));
 	otg_leave_state(fsm, otg->state);
 	switch (new_state) {
 	case OTG_STATE_B_IDLE:
@@ -358,7 +352,7 @@ int otg_statemachine(struct usb_otg *otg)
 
 	switch (state) {
 	case OTG_STATE_UNDEFINED:
-		VDBG("fsm->id = %d\n", fsm->id);
+		dev_vdbg(otg->dev, "fsm->id = %d\n", fsm->id);
 		if (fsm->id)
 			otg_set_state(fsm, OTG_STATE_B_IDLE);
 		else
@@ -466,7 +460,8 @@ int otg_statemachine(struct usb_otg *otg)
 	}
 	mutex_unlock(&fsm->lock);
 
-	VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
+	dev_vdbg(otg->dev, "quit statemachine, changed = %d\n",
+		 fsm->state_changed);
 	return fsm->state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
-- 
2.7.4

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

* [PATCH v10 12/14] usb: hcd: Adapt to OTG core
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Introduce usb_otg_add/remove_hcd() for use by host
controllers that are part of OTG/dual-role port.

Non device tree platforms can use the otg_dev argument
to specify the OTG controller device. If otg_dev is NULL
then the device tree node's otg-controller property is used to
get the otg_dev device.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/hcd.h |  4 ++++
 2 files changed, 59 insertions(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index ae6c76d..c6f4155 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -46,6 +46,11 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "usb.h"
 
@@ -3025,6 +3030,56 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
+static struct otg_hcd_ops otg_hcd_intf = {
+	.add = usb_add_hcd,
+	.remove = usb_remove_hcd,
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
+/**
+ * usb_otg_add_hcd - Register the HCD with OTG core.
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ * @otg_dev: OTG controller device managing this HCD
+ *
+ * Registers the HCD with OTG core. OTG core will call usb_add_hcd()
+ * or usb_remove_hcd() as necessary.
+ * If otg_dev is NULL then device tree node is checked for OTG
+ * controller device via the otg-controller property.
+ */
+int usb_otg_add_hcd(struct usb_hcd *hcd,
+		    unsigned int irqnum, unsigned long irqflags,
+		    struct device *otg_dev)
+{
+	struct device *dev = hcd->self.controller;
+
+	if (!otg_dev) {
+		hcd->otg_dev = of_usb_get_otg(dev->of_node);
+		if (!hcd->otg_dev)
+			return -ENODEV;
+	} else {
+		hcd->otg_dev = otg_dev;
+	}
+
+	return usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf);
+}
+EXPORT_SYMBOL_GPL(usb_otg_add_hcd);
+
+/**
+ * usb_otg_remove_hcd - Unregister the HCD with OTG core.
+ * @hcd: the usb_hcd structure to remove
+ *
+ * Unregisters the HCD from the OTG core.
+ */
+void usb_otg_remove_hcd(struct usb_hcd *hcd)
+{
+	usb_otg_unregister_hcd(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_otg_remove_hcd);
+
 void
 usb_hcd_platform_shutdown(struct platform_device *dev)
 {
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 36bd54f..0c70282 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -473,6 +473,10 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
 extern int usb_add_hcd(struct usb_hcd *hcd,
 		unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
+extern int usb_otg_add_hcd(struct usb_hcd *hcd,
+			   unsigned int irqnum, unsigned long irqflags,
+			   struct device *otg_dev);
+extern void usb_otg_remove_hcd(struct usb_hcd *hcd);
 extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 struct platform_device;
-- 
2.7.4

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

* [PATCH v10 12/14] usb: hcd: Adapt to OTG core
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Introduce usb_otg_add/remove_hcd() for use by host
controllers that are part of OTG/dual-role port.

Non device tree platforms can use the otg_dev argument
to specify the OTG controller device. If otg_dev is NULL
then the device tree node's otg-controller property is used to
get the otg_dev device.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/hcd.h |  4 ++++
 2 files changed, 59 insertions(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index ae6c76d..c6f4155 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -46,6 +46,11 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/phy.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "usb.h"
 
@@ -3025,6 +3030,56 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
+static struct otg_hcd_ops otg_hcd_intf = {
+	.add = usb_add_hcd,
+	.remove = usb_remove_hcd,
+	.usb_bus_start_enum = usb_bus_start_enum,
+	.usb_control_msg = usb_control_msg,
+	.usb_hub_find_child = usb_hub_find_child,
+};
+
+/**
+ * usb_otg_add_hcd - Register the HCD with OTG core.
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqflags: Interrupt type flags
+ * @otg_dev: OTG controller device managing this HCD
+ *
+ * Registers the HCD with OTG core. OTG core will call usb_add_hcd()
+ * or usb_remove_hcd() as necessary.
+ * If otg_dev is NULL then device tree node is checked for OTG
+ * controller device via the otg-controller property.
+ */
+int usb_otg_add_hcd(struct usb_hcd *hcd,
+		    unsigned int irqnum, unsigned long irqflags,
+		    struct device *otg_dev)
+{
+	struct device *dev = hcd->self.controller;
+
+	if (!otg_dev) {
+		hcd->otg_dev = of_usb_get_otg(dev->of_node);
+		if (!hcd->otg_dev)
+			return -ENODEV;
+	} else {
+		hcd->otg_dev = otg_dev;
+	}
+
+	return usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf);
+}
+EXPORT_SYMBOL_GPL(usb_otg_add_hcd);
+
+/**
+ * usb_otg_remove_hcd - Unregister the HCD with OTG core.
+ * @hcd: the usb_hcd structure to remove
+ *
+ * Unregisters the HCD from the OTG core.
+ */
+void usb_otg_remove_hcd(struct usb_hcd *hcd)
+{
+	usb_otg_unregister_hcd(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_otg_remove_hcd);
+
 void
 usb_hcd_platform_shutdown(struct platform_device *dev)
 {
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 36bd54f..0c70282 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -473,6 +473,10 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
 extern int usb_add_hcd(struct usb_hcd *hcd,
 		unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
+extern int usb_otg_add_hcd(struct usb_hcd *hcd,
+			   unsigned int irqnum, unsigned long irqflags,
+			   struct device *otg_dev);
+extern void usb_otg_remove_hcd(struct usb_hcd *hcd);
 extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 struct platform_device;
-- 
2.7.4

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

* [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

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

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..9d8a1d0 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_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",
@@ -1222,10 +1377,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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		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;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			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;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		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);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

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

* [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

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

Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..9d8a1d0 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_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",
@@ -1222,10 +1377,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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		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;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			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;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		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);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

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

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

* [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-10 13:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Host controllers that are part of an OTG/dual-role instance
need to somehow pass the OTG controller device information
to the HCD core.

We use platform data to pass the OTG controller device.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/host/xhci-plat.c     | 35 ++++++++++++++++++++++++++++-------
 include/linux/usb/xhci_pdriver.h |  3 +++
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 676ea45..24d030a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -239,11 +239,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
 			goto put_usb3_hcd;
 	}
 
-	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (pdata && pdata->otg_dev)
+		ret = usb_otg_add_hcd(hcd, irq, IRQF_SHARED, pdata->otg_dev);
+	else
+		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+
 	if (ret)
 		goto disable_usb_phy;
 
-	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+	if (pdata && pdata->otg_dev)
+		ret = usb_otg_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED,
+				      pdata->otg_dev);
+	else
+		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+
 	if (ret)
 		goto dealloc_usb2_hcd;
 
@@ -251,7 +260,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
 
 
 dealloc_usb2_hcd:
-	usb_remove_hcd(hcd);
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(hcd);
+	else
+		usb_remove_hcd(hcd);
 
 disable_usb_phy:
 	usb_phy_shutdown(hcd->usb_phy);
@@ -269,16 +281,25 @@ put_hcd:
 	return ret;
 }
 
-static int xhci_plat_remove(struct platform_device *dev)
+static int xhci_plat_remove(struct platform_device *pdev)
 {
-	struct usb_hcd	*hcd = platform_get_drvdata(dev);
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
 	struct clk *clk = xhci->clk;
+	struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(xhci->shared_hcd);
+	else
+		usb_remove_hcd(xhci->shared_hcd);
 
-	usb_remove_hcd(xhci->shared_hcd);
 	usb_phy_shutdown(hcd->usb_phy);
 
-	usb_remove_hcd(hcd);
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(hcd);
+	else
+		usb_remove_hcd(hcd);
+
 	usb_put_hcd(xhci->shared_hcd);
 
 	if (!IS_ERR(clk))
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
index 376654b..5c68b83 100644
--- a/include/linux/usb/xhci_pdriver.h
+++ b/include/linux/usb/xhci_pdriver.h
@@ -18,10 +18,13 @@
  *
  * @usb3_lpm_capable:	determines if this xhci platform supports USB3
  *			LPM capability
+ * @otg_dev:		OTG controller device. Only requied if part of
+ *			OTG/dual-role.
  *
  */
 struct usb_xhci_pdata {
 	unsigned	usb3_lpm_capable:1;
+	struct device	*otg_dev;
 };
 
 #endif /* __USB_CORE_XHCI_PDRIVER_H */
-- 
2.7.4

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

* [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data
@ 2016-06-10 13:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 13:07 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

Host controllers that are part of an OTG/dual-role instance
need to somehow pass the OTG controller device information
to the HCD core.

We use platform data to pass the OTG controller device.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@nxp.com>
---
 drivers/usb/host/xhci-plat.c     | 35 ++++++++++++++++++++++++++++-------
 include/linux/usb/xhci_pdriver.h |  3 +++
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 676ea45..24d030a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -239,11 +239,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
 			goto put_usb3_hcd;
 	}
 
-	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (pdata && pdata->otg_dev)
+		ret = usb_otg_add_hcd(hcd, irq, IRQF_SHARED, pdata->otg_dev);
+	else
+		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+
 	if (ret)
 		goto disable_usb_phy;
 
-	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+	if (pdata && pdata->otg_dev)
+		ret = usb_otg_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED,
+				      pdata->otg_dev);
+	else
+		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+
 	if (ret)
 		goto dealloc_usb2_hcd;
 
@@ -251,7 +260,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
 
 
 dealloc_usb2_hcd:
-	usb_remove_hcd(hcd);
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(hcd);
+	else
+		usb_remove_hcd(hcd);
 
 disable_usb_phy:
 	usb_phy_shutdown(hcd->usb_phy);
@@ -269,16 +281,25 @@ put_hcd:
 	return ret;
 }
 
-static int xhci_plat_remove(struct platform_device *dev)
+static int xhci_plat_remove(struct platform_device *pdev)
 {
-	struct usb_hcd	*hcd = platform_get_drvdata(dev);
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
 	struct clk *clk = xhci->clk;
+	struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(xhci->shared_hcd);
+	else
+		usb_remove_hcd(xhci->shared_hcd);
 
-	usb_remove_hcd(xhci->shared_hcd);
 	usb_phy_shutdown(hcd->usb_phy);
 
-	usb_remove_hcd(hcd);
+	if (pdata && pdata->otg_dev)
+		usb_otg_remove_hcd(hcd);
+	else
+		usb_remove_hcd(hcd);
+
 	usb_put_hcd(xhci->shared_hcd);
 
 	if (!IS_ERR(clk))
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
index 376654b..5c68b83 100644
--- a/include/linux/usb/xhci_pdriver.h
+++ b/include/linux/usb/xhci_pdriver.h
@@ -18,10 +18,13 @@
  *
  * @usb3_lpm_capable:	determines if this xhci platform supports USB3
  *			LPM capability
+ * @otg_dev:		OTG controller device. Only requied if part of
+ *			OTG/dual-role.
  *
  */
 struct usb_xhci_pdata {
 	unsigned	usb3_lpm_capable:1;
+	struct device	*otg_dev;
 };
 
 #endif /* __USB_CORE_XHCI_PDRIVER_H */
-- 
2.7.4

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
  2016-06-10 13:07   ` Roger Quadros
  (?)
@ 2016-06-12  9:13   ` Peter Chen
  -1 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-12  9:13 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Fri, Jun 10, 2016 at 04:07:15PM +0300, Roger Quadros wrote:
> 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>

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

> ---
>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index 2dd9e6b..f4fc0aa 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -639,6 +639,22 @@ 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
> + * @connect_control: function to connect/disconnect from the bus
> + */
> +struct otg_gadget_ops {
> +	int (*start)(struct usb_gadget *gadget);
> +	int (*stop)(struct usb_gadget *gadget);
> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
> +};
>  
>  /*-------------------------------------------------------------------------*/
>  
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-12 11:21     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-12 11:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Fri, Jun 10, 2016 at 04:07:17PM +0300, Roger Quadros wrote:
> index dca7856..03f7204 100644
> --- a/drivers/usb/Makefile
> +++ b/drivers/usb/Makefile
> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
>  obj-$(CONFIG_USB_GADGET)	+= gadget/
>  
>  obj-$(CONFIG_USB_COMMON)	+= common/
> +obj-$(CONFIG_USB_OTG_CORE)	+= common/

I don't think you need to make above change, why you do it?

> +
> +/**
> + * usb_otg_get_data() - get usb_otg data structa

%s/structa/structure

> +
> +/**
> + * usb_otg_kick_fsm() - Kick the OTG state machine
> + * @otg_dev:	OTG controller device
> + *
> + * Used by USB host/gadget stack to sync OTG related
> + * events to the OTG state machine.
> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_kick_fsm(struct device *otg_dev)
> +{
> +	struct usb_otg *otg;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
> +			__func__);
> +		return -ENODEV;
> +	}
> +
> +	usb_otg_sync_inputs(otg);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);

Do you have any users for this API? If no, please delete it in this
version.

> +
> +/**
> + * usb_otg_register_hcd() - Register the host controller to OTG core
> + * @hcd:	host controller
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to interface with 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.

%s/upto/up to

> +
> +/**
> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
> + * @gadget:	gadget controller instance
> + * @ops:	gadget interface ops
> + *
> + * 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.
> + *

%s/upto/up to

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-12 11:21     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-12 11:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jun 10, 2016 at 04:07:17PM +0300, Roger Quadros wrote:
> index dca7856..03f7204 100644
> --- a/drivers/usb/Makefile
> +++ b/drivers/usb/Makefile
> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
>  obj-$(CONFIG_USB_GADGET)	+= gadget/
>  
>  obj-$(CONFIG_USB_COMMON)	+= common/
> +obj-$(CONFIG_USB_OTG_CORE)	+= common/

I don't think you need to make above change, why you do it?

> +
> +/**
> + * usb_otg_get_data() - get usb_otg data structa

%s/structa/structure

> +
> +/**
> + * usb_otg_kick_fsm() - Kick the OTG state machine
> + * @otg_dev:	OTG controller device
> + *
> + * Used by USB host/gadget stack to sync OTG related
> + * events to the OTG state machine.
> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_kick_fsm(struct device *otg_dev)
> +{
> +	struct usb_otg *otg;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
> +			__func__);
> +		return -ENODEV;
> +	}
> +
> +	usb_otg_sync_inputs(otg);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);

Do you have any users for this API? If no, please delete it in this
version.

> +
> +/**
> + * usb_otg_register_hcd() - Register the host controller to OTG core
> + * @hcd:	host controller
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to interface with 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.

%s/upto/up to

> +
> +/**
> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
> + * @gadget:	gadget controller instance
> + * @ops:	gadget interface ops
> + *
> + * 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.
> + *

%s/upto/up to

-- 

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

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-12 11:36     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-12 11:36 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>  
> +/**
> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> + * @parent: the parent device to this udc. Usually the controller
> + * driver's device.

It seems it should be udc device

> +/* udc_lock must be held */
>  static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
>  {
>  	int ret;
> @@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
> +	if (udc->gadget->otg_dev) {
> +		mutex_unlock(&udc_lock);
> +		usb_otg_gadget_ready(udc->gadget, true);
> +		mutex_lock(&udc_lock);
> +	} else {
> +		ret = usb_gadget_udc_start(udc);
> +		if (ret) {
> +			mutex_unlock(&udc_lock);
> +			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;
>  err1:
> -	if (ret != -EISNAM)
> +	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))

It seems it will not introduce -EPROBE_DEFER with your changes
in udc_bind_to_driver

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-12 11:36     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-12 11:36 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>  
> +/**
> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> + * @parent: the parent device to this udc. Usually the controller
> + * driver's device.

It seems it should be udc device

> +/* udc_lock must be held */
>  static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
>  {
>  	int ret;
> @@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
> +	if (udc->gadget->otg_dev) {
> +		mutex_unlock(&udc_lock);
> +		usb_otg_gadget_ready(udc->gadget, true);
> +		mutex_lock(&udc_lock);
> +	} else {
> +		ret = usb_gadget_udc_start(udc);
> +		if (ret) {
> +			mutex_unlock(&udc_lock);
> +			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;
>  err1:
> -	if (ret != -EISNAM)
> +	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))

It seems it will not introduce -EPROBE_DEFER with your changes
in udc_bind_to_driver

-- 

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

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
  2016-06-12 11:36     ` Peter Chen
@ 2016-06-13  7:14       ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:14 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 12/06/16 14:36, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>>  
>> +/**
>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>> + * @parent: the parent device to this udc. Usually the controller
>> + * driver's device.
> 
> It seems it should be udc device

Parent and udc->dev are not the same right?

I guess i'll omit the second statement to avoid confusion. So.

@parent: the parent device to this udc.

> 
>> +/* udc_lock must be held */
>>  static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
>>  {
>>  	int ret;
>> @@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
>> +	if (udc->gadget->otg_dev) {
>> +		mutex_unlock(&udc_lock);
>> +		usb_otg_gadget_ready(udc->gadget, true);
>> +		mutex_lock(&udc_lock);
>> +	} else {
>> +		ret = usb_gadget_udc_start(udc);
>> +		if (ret) {
>> +			mutex_unlock(&udc_lock);
>> +			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;
>>  err1:
>> -	if (ret != -EISNAM)
>> +	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))
> 
> It seems it will not introduce -EPROBE_DEFER with your changes
> in udc_bind_to_driver
> 

Good catch. Left over bit when I moved defer probing out of here.

--
cheers,
-roger

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:14       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:14 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 12/06/16 14:36, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>>  
>> +/**
>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>> + * @parent: the parent device to this udc. Usually the controller
>> + * driver's device.
> 
> It seems it should be udc device

Parent and udc->dev are not the same right?

I guess i'll omit the second statement to avoid confusion. So.

@parent: the parent device to this udc.

> 
>> +/* udc_lock must be held */
>>  static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
>>  {
>>  	int ret;
>> @@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
>> +	if (udc->gadget->otg_dev) {
>> +		mutex_unlock(&udc_lock);
>> +		usb_otg_gadget_ready(udc->gadget, true);
>> +		mutex_lock(&udc_lock);
>> +	} else {
>> +		ret = usb_gadget_udc_start(udc);
>> +		if (ret) {
>> +			mutex_unlock(&udc_lock);
>> +			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;
>>  err1:
>> -	if (ret != -EISNAM)
>> +	if ((ret != -EISNAM) && (ret != -EPROBE_DEFER))
> 
> It seems it will not introduce -EPROBE_DEFER with your changes
> in udc_bind_to_driver
> 

Good catch. Left over bit when I moved defer probing out of here.

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

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:20         ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:20 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
> On 12/06/16 14:36, Peter Chen wrote:
> > On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
> >>  
> >> +/**
> >> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >> + * @parent: the parent device to this udc. Usually the controller
> >> + * driver's device.
> > 
> > It seems it should be udc device
> 
> Parent and udc->dev are not the same right?

Sure, udc's parent is otg device.

> 
> I guess i'll omit the second statement to avoid confusion. So.
> 
> @parent: the parent device to this udc.

Where you call below APIs? It seems to be a udc driver, right?
So, when you try to get "otg-controller" from the node, this node
should be udc.

/**
 * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 * @otg_dev: the OTG controller device
 *
 * If otg_dev is NULL then device tree node is checked
 * for OTG controller via the otg-controller property.
 * Returns zero on success, negative errno otherwise.
 */
int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
			   struct device *otg_dev)
{
	if (!otg_dev) {
		gadget->otg_dev = of_usb_get_otg(parent->of_node);
		if (!gadget->otg_dev)
			return -ENODEV;
	} else {
		gadget->otg_dev = otg_dev;
	}

	return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:20         ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:20 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
> On 12/06/16 14:36, Peter Chen wrote:
> > On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
> >>  
> >> +/**
> >> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >> + * @parent: the parent device to this udc. Usually the controller
> >> + * driver's device.
> > 
> > It seems it should be udc device
> 
> Parent and udc->dev are not the same right?

Sure, udc's parent is otg device.

> 
> I guess i'll omit the second statement to avoid confusion. So.
> 
> @parent: the parent device to this udc.

Where you call below APIs? It seems to be a udc driver, right?
So, when you try to get "otg-controller" from the node, this node
should be udc.

/**
 * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 * @otg_dev: the OTG controller device
 *
 * If otg_dev is NULL then device tree node is checked
 * for OTG controller via the otg-controller property.
 * Returns zero on success, negative errno otherwise.
 */
int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
			   struct device *otg_dev)
{
	if (!otg_dev) {
		gadget->otg_dev = of_usb_get_otg(parent->of_node);
		if (!gadget->otg_dev)
			return -ENODEV;
	} else {
		gadget->otg_dev = otg_dev;
	}

	return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
-- 

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

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
  2016-06-13  7:20         ` Peter Chen
@ 2016-06-13  7:37           ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:37 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 13/06/16 10:20, Peter Chen wrote:
> On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
>> On 12/06/16 14:36, Peter Chen wrote:
>>> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>>>>  
>>>> +/**
>>>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>>>> + * @parent: the parent device to this udc. Usually the controller
>>>> + * driver's device.
>>>
>>> It seems it should be udc device
>>
>> Parent and udc->dev are not the same right?
> 
> Sure, udc's parent is otg device.
> 
>>
>> I guess i'll omit the second statement to avoid confusion. So.
>>
>> @parent: the parent device to this udc.
> 
> Where you call below APIs? It seems to be a udc driver, right?
> So, when you try to get "otg-controller" from the node, this node
> should be udc.

@parent is actually the device that represents the USB Device controller
in the device tree. When you call usb_add_gadget_udc_release() a new
udc->dev device is created as it's child.

See explanation for the @parent argument in usb_add_gadget_udc_release().
As we want to keep the parent argument identical to that I will not make
any changes then.

> 
> /**
>  * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>  * @parent: the parent device to this udc. Usually the controller
>  * driver's device.
>  * @gadget: the gadget to be added to the list
>  * @otg_dev: the OTG controller device
>  *
>  * If otg_dev is NULL then device tree node is checked
>  * for OTG controller via the otg-controller property.
>  * Returns zero on success, negative errno otherwise.
>  */
> int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
> 			   struct device *otg_dev)
> {
> 	if (!otg_dev) {
> 		gadget->otg_dev = of_usb_get_otg(parent->of_node);
> 		if (!gadget->otg_dev)
> 			return -ENODEV;
> 	} else {
> 		gadget->otg_dev = otg_dev;
> 	}
> 
> 	return usb_add_gadget_udc_release(parent, gadget, NULL);
> }
> EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
> 

--
cheers,
-roger

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:37           ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:37 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 13/06/16 10:20, Peter Chen wrote:
> On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
>> On 12/06/16 14:36, Peter Chen wrote:
>>> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
>>>>  
>>>> +/**
>>>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>>>> + * @parent: the parent device to this udc. Usually the controller
>>>> + * driver's device.
>>>
>>> It seems it should be udc device
>>
>> Parent and udc->dev are not the same right?
> 
> Sure, udc's parent is otg device.
> 
>>
>> I guess i'll omit the second statement to avoid confusion. So.
>>
>> @parent: the parent device to this udc.
> 
> Where you call below APIs? It seems to be a udc driver, right?
> So, when you try to get "otg-controller" from the node, this node
> should be udc.

@parent is actually the device that represents the USB Device controller
in the device tree. When you call usb_add_gadget_udc_release() a new
udc->dev device is created as it's child.

See explanation for the @parent argument in usb_add_gadget_udc_release().
As we want to keep the parent argument identical to that I will not make
any changes then.

> 
> /**
>  * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
>  * @parent: the parent device to this udc. Usually the controller
>  * driver's device.
>  * @gadget: the gadget to be added to the list
>  * @otg_dev: the OTG controller device
>  *
>  * If otg_dev is NULL then device tree node is checked
>  * for OTG controller via the otg-controller property.
>  * Returns zero on success, negative errno otherwise.
>  */
> int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
> 			   struct device *otg_dev)
> {
> 	if (!otg_dev) {
> 		gadget->otg_dev = of_usb_get_otg(parent->of_node);
> 		if (!gadget->otg_dev)
> 			return -ENODEV;
> 	} else {
> 		gadget->otg_dev = otg_dev;
> 	}
> 
> 	return usb_add_gadget_udc_release(parent, gadget, NULL);
> }
> EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
> 

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

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:40             ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:40 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Mon, Jun 13, 2016 at 10:37:59AM +0300, Roger Quadros wrote:
> On 13/06/16 10:20, Peter Chen wrote:
> > On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
> >> On 12/06/16 14:36, Peter Chen wrote:
> >>> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
> >>>>  
> >>>> +/**
> >>>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >>>> + * @parent: the parent device to this udc. Usually the controller
> >>>> + * driver's device.
> >>>
> >>> It seems it should be udc device
> >>
> >> Parent and udc->dev are not the same right?
> > 
> > Sure, udc's parent is otg device.
> > 
> >>
> >> I guess i'll omit the second statement to avoid confusion. So.
> >>
> >> @parent: the parent device to this udc.
> > 
> > Where you call below APIs? It seems to be a udc driver, right?
> > So, when you try to get "otg-controller" from the node, this node
> > should be udc.
> 
> @parent is actually the device that represents the USB Device controller
> in the device tree. When you call usb_add_gadget_udc_release() a new
> udc->dev device is created as it's child.
> 
> See explanation for the @parent argument in usb_add_gadget_udc_release().
> As we want to keep the parent argument identical to that I will not make
> any changes then.

Oh, yes. The parent should be glue layer udc device or the dual-role controller
device.

Peter
> 
> > 
> > /**
> >  * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >  * @parent: the parent device to this udc. Usually the controller
> >  * driver's device.
> >  * @gadget: the gadget to be added to the list
> >  * @otg_dev: the OTG controller device
> >  *
> >  * If otg_dev is NULL then device tree node is checked
> >  * for OTG controller via the otg-controller property.
> >  * Returns zero on success, negative errno otherwise.
> >  */
> > int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
> > 			   struct device *otg_dev)
> > {
> > 	if (!otg_dev) {
> > 		gadget->otg_dev = of_usb_get_otg(parent->of_node);
> > 		if (!gadget->otg_dev)
> > 			return -ENODEV;
> > 	} else {
> > 		gadget->otg_dev = otg_dev;
> > 	}
> > 
> > 	return usb_add_gadget_udc_release(parent, gadget, NULL);
> > }
> > EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
> > 
> 
> --
> cheers,
> -roger

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:40             ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:40 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Mon, Jun 13, 2016 at 10:37:59AM +0300, Roger Quadros wrote:
> On 13/06/16 10:20, Peter Chen wrote:
> > On Mon, Jun 13, 2016 at 10:14:31AM +0300, Roger Quadros wrote:
> >> On 12/06/16 14:36, Peter Chen wrote:
> >>> On Fri, Jun 10, 2016 at 04:07:22PM +0300, Roger Quadros wrote:
> >>>>  
> >>>> +/**
> >>>> + * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >>>> + * @parent: the parent device to this udc. Usually the controller
> >>>> + * driver's device.
> >>>
> >>> It seems it should be udc device
> >>
> >> Parent and udc->dev are not the same right?
> > 
> > Sure, udc's parent is otg device.
> > 
> >>
> >> I guess i'll omit the second statement to avoid confusion. So.
> >>
> >> @parent: the parent device to this udc.
> > 
> > Where you call below APIs? It seems to be a udc driver, right?
> > So, when you try to get "otg-controller" from the node, this node
> > should be udc.
> 
> @parent is actually the device that represents the USB Device controller
> in the device tree. When you call usb_add_gadget_udc_release() a new
> udc->dev device is created as it's child.
> 
> See explanation for the @parent argument in usb_add_gadget_udc_release().
> As we want to keep the parent argument identical to that I will not make
> any changes then.

Oh, yes. The parent should be glue layer udc device or the dual-role controller
device.

Peter
> 
> > 
> > /**
> >  * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
> >  * @parent: the parent device to this udc. Usually the controller
> >  * driver's device.
> >  * @gadget: the gadget to be added to the list
> >  * @otg_dev: the OTG controller device
> >  *
> >  * If otg_dev is NULL then device tree node is checked
> >  * for OTG controller via the otg-controller property.
> >  * Returns zero on success, negative errno otherwise.
> >  */
> > int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
> > 			   struct device *otg_dev)
> > {
> > 	if (!otg_dev) {
> > 		gadget->otg_dev = of_usb_get_otg(parent->of_node);
> > 		if (!gadget->otg_dev)
> > 			return -ENODEV;
> > 	} else {
> > 		gadget->otg_dev = otg_dev;
> > 	}
> > 
> > 	return usb_add_gadget_udc_release(parent, gadget, NULL);
> > }
> > EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
> > 
> 
> --
> cheers,
> -roger

-- 

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

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-12 11:21     ` Peter Chen
@ 2016-06-13  7:42       ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:42 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 12/06/16 14:21, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:17PM +0300, Roger Quadros wrote:
>> index dca7856..03f7204 100644
>> --- a/drivers/usb/Makefile
>> +++ b/drivers/usb/Makefile
>> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
>>  obj-$(CONFIG_USB_GADGET)	+= gadget/
>>  
>>  obj-$(CONFIG_USB_COMMON)	+= common/
>> +obj-$(CONFIG_USB_OTG_CORE)	+= common/
> 
> I don't think you need to make above change, why you do it?

You are right. I no longer get undefined symbol errors during build.
I'll remove this change.
> 
>> +
>> +/**
>> + * usb_otg_get_data() - get usb_otg data structa
> 
> %s/structa/structure

OK.
> 
>> +
>> +/**
>> + * usb_otg_kick_fsm() - Kick the OTG state machine
>> + * @otg_dev:	OTG controller device
>> + *
>> + * Used by USB host/gadget stack to sync OTG related
>> + * events to the OTG state machine.
>> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_kick_fsm(struct device *otg_dev)
>> +{
>> +	struct usb_otg *otg;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
>> +			__func__);
>> +		return -ENODEV;
>> +	}
>> +
>> +	usb_otg_sync_inputs(otg);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
> 
> Do you have any users for this API? If no, please delete it in this
> version.

I'll remove it.
> 
>> +
>> +/**
>> + * usb_otg_register_hcd() - Register the host controller to OTG core
>> + * @hcd:	host controller
>> + * @irqnum:	interrupt number
>> + * @irqflags:	interrupt flags
>> + * @ops:	HCD ops to interface with 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.
> 
> %s/upto/up to
> 
>> +
>> +/**
>> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
>> + * @gadget:	gadget controller instance
>> + * @ops:	gadget interface ops
>> + *
>> + * 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.
>> + *
> 
> %s/upto/up to
> 

OK for both.

--
cheers,
-roger

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-13  7:42       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:42 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 12/06/16 14:21, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:17PM +0300, Roger Quadros wrote:
>> index dca7856..03f7204 100644
>> --- a/drivers/usb/Makefile
>> +++ b/drivers/usb/Makefile
>> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
>>  obj-$(CONFIG_USB_GADGET)	+= gadget/
>>  
>>  obj-$(CONFIG_USB_COMMON)	+= common/
>> +obj-$(CONFIG_USB_OTG_CORE)	+= common/
> 
> I don't think you need to make above change, why you do it?

You are right. I no longer get undefined symbol errors during build.
I'll remove this change.
> 
>> +
>> +/**
>> + * usb_otg_get_data() - get usb_otg data structa
> 
> %s/structa/structure

OK.
> 
>> +
>> +/**
>> + * usb_otg_kick_fsm() - Kick the OTG state machine
>> + * @otg_dev:	OTG controller device
>> + *
>> + * Used by USB host/gadget stack to sync OTG related
>> + * events to the OTG state machine.
>> + * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_kick_fsm(struct device *otg_dev)
>> +{
>> +	struct usb_otg *otg;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
>> +			__func__);
>> +		return -ENODEV;
>> +	}
>> +
>> +	usb_otg_sync_inputs(otg);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
> 
> Do you have any users for this API? If no, please delete it in this
> version.

I'll remove it.
> 
>> +
>> +/**
>> + * usb_otg_register_hcd() - Register the host controller to OTG core
>> + * @hcd:	host controller
>> + * @irqnum:	interrupt number
>> + * @irqflags:	interrupt flags
>> + * @ops:	HCD ops to interface with 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.
> 
> %s/upto/up to
> 
>> +
>> +/**
>> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
>> + * @gadget:	gadget controller instance
>> + * @ops:	gadget interface ops
>> + *
>> + * 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.
>> + *
> 
> %s/upto/up to
> 

OK for both.

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

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

* [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-13  7:55     ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:55 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

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

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v11:
- removed left over -EPROBE_DEFER in udc_bind_to_driver().

 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..1290f03 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to the UDC. Usually the Gadget controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_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",
@@ -1222,10 +1377,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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		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;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			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;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		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);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

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

* [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  7:55     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:55 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

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

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v11:
- removed left over -EPROBE_DEFER in udc_bind_to_driver().

 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..1290f03 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to the UDC. Usually the Gadget controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_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",
@@ -1222,10 +1377,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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		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;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ 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/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			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;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		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);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

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

* [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-13  7:56     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:56 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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>
---
v11:
- remove usb_otg_kick_fsm().
- typo fixes: structa/structure, upto/up to.
- remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.

 drivers/usb/Kconfig          |  18 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 174 ++++++++-
 9 files changed, 1070 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..a23ab1e
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,877 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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;
+}
+
+/**
+ * usb_otg_get_data() - get usb_otg data structure
+ * @otg_dev:	OTG controller device
+ *
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ *
+ * Return: usb_otg data on success, NULL otherwise.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host() - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		/* start host */
+		ret = hcd_ops->add(otg->primary_hcd.hcd,
+				   otg->primary_hcd.irqnum,
+				   otg->primary_hcd.irqflags);
+		if (ret) {
+			dev_err(otg->dev, "otg: host add failed %d\n", ret);
+			return ret;
+		}
+
+		if (otg->shared_hcd.hcd) {
+			ret = hcd_ops->add(otg->shared_hcd.hcd,
+					   otg->shared_hcd.irqnum,
+					   otg->shared_hcd.irqflags);
+			if (ret) {
+				dev_err(otg->dev, "otg: shared host add failed %d\n",
+					ret);
+				hcd_ops->remove(otg->primary_hcd.hcd);
+				return ret;
+			}
+		}
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget() - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		ret = otg->gadget_ops->start(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget start failed: %d\n",
+				ret);
+			return ret;
+		}
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		ret = otg->gadget_ops->stop(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
+				ret);
+			return ret;
+		}
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * drd_set_protocol() -  Set USB protocol if possible
+ * @fsm:	DRD FSM instance
+ * @protocol:	USB protocol to set the state machine to
+ *
+ * Sets the OTG FSM protocol to @protocol if it changed.
+ * fsm->lock must be held.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * drd_set_state() - Set the DRD state machine state.
+ * @fsm:	DRD FSM instance
+ * @new_state:	the new state the DRD FSM must be set to
+ *
+ * Sets the state of the DRD state machine.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * drd_statemachine() - DRD state change judgement
+ * @otg:	usb_otg instance
+ *
+ * Checks the state machine inputs and state and makes a state change
+ * if required.
+ *
+ * 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
+ *
+ * Return: 0 if state wasn't changed, 1 if state changed.
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * usb_drd_work() - Dual-role state machine work function
+ * @work: work_struct context
+ *
+ * Runs the DRD state machine. Scheduled whenever there is a change
+ * in FSM inputs.
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+		;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() otherwise.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * usb_otg_start_fsm() - Start the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
+ * must be ready for the OTG FSM to start.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * usb_otg_stop_fsm() - Stop the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Stops the HCD, UDC and the OTG FSM.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 0);
+	}
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
+ * @otg:	usb_otg 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_register_hcd() - Register the host controller to OTG core
+ * @hcd:	host controller
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * Return: 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd() - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget() - Register the gadget controller to OTG core
+ * @gadget:	gadget controller instance
+ * @ops:	gadget interface ops
+ *
+ * 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 up to the OTG state machine to do so.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget() - Unregister the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
+ * @gadget:	gadget controller
+ * @ready:	0: function driver ready, 1: function driver not ready
+ *
+ * Notify the OTG core about status of the gadget function driver.
+ * As OTG core is responsible to start/stop the gadget controller, it
+ * must be aware when the gadget function driver is available or not.
+ * This function is used by the Gadget core to inform the OTG core
+ * about the gadget function driver readyness.
+ *
+ * Return: 0 on sucess, error value otherwise.
+ */
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3c3f31c..5fc9095 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f4fc0aa..1d74fb8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -328,6 +328,7 @@ struct usb_gadget_ops {
  * @in_epnum: last used in ep number
  * @mA: last set mA value
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -385,6 +386,7 @@ struct usb_gadget {
 	unsigned			in_epnum;
 	unsigned			mA;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..9d72951 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,67 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @otg_dev: OTG controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of OTG controllers
+ * @work: OTG state machine work
+ * @wq: OTG state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +81,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +115,95 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - OTG controller configuration
+ * @caps: OTG capabilities of the controller
+ * @ops: OTG FSM operations
+ * @otg_work: optional custom OTG state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +255,8 @@ 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);
 
@@ -237,4 +381,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

* [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-13  7:56     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  7:56 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, rogerq-l0cyMroinI0

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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-l0cyMroinI0@public.gmane.org>
---
v11:
- remove usb_otg_kick_fsm().
- typo fixes: structa/structure, upto/up to.
- remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.

 drivers/usb/Kconfig          |  18 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 174 ++++++++-
 9 files changed, 1070 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..a23ab1e
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,877 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
+ *
+ * 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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;
+}
+
+/**
+ * usb_otg_get_data() - get usb_otg data structure
+ * @otg_dev:	OTG controller device
+ *
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ *
+ * Return: usb_otg data on success, NULL otherwise.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host() - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		/* start host */
+		ret = hcd_ops->add(otg->primary_hcd.hcd,
+				   otg->primary_hcd.irqnum,
+				   otg->primary_hcd.irqflags);
+		if (ret) {
+			dev_err(otg->dev, "otg: host add failed %d\n", ret);
+			return ret;
+		}
+
+		if (otg->shared_hcd.hcd) {
+			ret = hcd_ops->add(otg->shared_hcd.hcd,
+					   otg->shared_hcd.irqnum,
+					   otg->shared_hcd.irqflags);
+			if (ret) {
+				dev_err(otg->dev, "otg: shared host add failed %d\n",
+					ret);
+				hcd_ops->remove(otg->primary_hcd.hcd);
+				return ret;
+			}
+		}
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget() - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+	int ret;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		ret = otg->gadget_ops->start(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget start failed: %d\n",
+				ret);
+			return ret;
+		}
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		ret = otg->gadget_ops->stop(otg->gadget);
+		if (ret) {
+			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
+				ret);
+			return ret;
+		}
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * drd_set_protocol() -  Set USB protocol if possible
+ * @fsm:	DRD FSM instance
+ * @protocol:	USB protocol to set the state machine to
+ *
+ * Sets the OTG FSM protocol to @protocol if it changed.
+ * fsm->lock must be held.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * drd_set_state() - Set the DRD state machine state.
+ * @fsm:	DRD FSM instance
+ * @new_state:	the new state the DRD FSM must be set to
+ *
+ * Sets the state of the DRD state machine.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * drd_statemachine() - DRD state change judgement
+ * @otg:	usb_otg instance
+ *
+ * Checks the state machine inputs and state and makes a state change
+ * if required.
+ *
+ * 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
+ *
+ * Return: 0 if state wasn't changed, 1 if state changed.
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * usb_drd_work() - Dual-role state machine work function
+ * @work: work_struct context
+ *
+ * Runs the DRD state machine. Scheduled whenever there is a change
+ * in FSM inputs.
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+		;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() otherwise.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * usb_otg_start_fsm() - Start the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
+ * must be ready for the OTG FSM to start.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * usb_otg_stop_fsm() - Stop the OTG FSM
+ * @otg:	usb_otg instance
+ *
+ * Stops the HCD, UDC and the OTG FSM.
+ *
+ * fsm->lock must be held.
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 0);
+	}
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
+ * @otg:	usb_otg 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_register_hcd() - Register the host controller to OTG core
+ * @hcd:	host controller
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * Return: 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd() - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget() - Register the gadget controller to OTG core
+ * @gadget:	gadget controller instance
+ * @ops:	gadget interface ops
+ *
+ * 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 up to the OTG state machine to do so.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget() - Unregister the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
+ * @gadget:	gadget controller
+ * @ready:	0: function driver ready, 1: function driver not ready
+ *
+ * Notify the OTG core about status of the gadget function driver.
+ * As OTG core is responsible to start/stop the gadget controller, it
+ * must be aware when the gadget function driver is available or not.
+ * This function is used by the Gadget core to inform the OTG core
+ * about the gadget function driver readyness.
+ *
+ * Return: 0 on sucess, error value otherwise.
+ */
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3c3f31c..5fc9095 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f4fc0aa..1d74fb8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -328,6 +328,7 @@ struct usb_gadget_ops {
  * @in_epnum: last used in ep number
  * @mA: last set mA value
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -385,6 +386,7 @@ struct usb_gadget {
 	unsigned			in_epnum;
 	unsigned			mA;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..9d72951 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,67 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @otg_dev: OTG controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of OTG controllers
+ * @work: OTG state machine work
+ * @wq: OTG state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +81,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +115,95 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - OTG controller configuration
+ * @caps: OTG capabilities of the controller
+ * @ops: OTG FSM operations
+ * @otg_work: optional custom OTG state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +255,8 @@ 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);
 
@@ -237,4 +381,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4


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

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

* Re: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
  2016-06-13  7:55     ` Roger Quadros
  (?)
@ 2016-06-13  7:56     ` Peter Chen
  2016-06-13  8:06         ` Roger Quadros
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:56 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Mon, Jun 13, 2016 at 10:55:12AM +0300, Roger Quadros wrote:
>  err1:
> -	if (ret != -EISNAM)
> +	if ((ret != -EISNAM))

Since you do not need above change.

Expect above, I am ok with this patch.

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

>  		dev_err(&udc->dev, "failed to start %s: %d\n",
>  			udc->driver->function, ret);
>  	udc->driver = NULL;
> @@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
>  		return -EOPNOTSUPP;
>  	}
>  
> +	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
> +	if (udc->gadget->otg_dev) {
> +		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);
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index 1d74fb8..8c6880d 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
>  extern void usb_del_gadget_udc(struct usb_gadget *gadget);
>  extern char *usb_get_gadget_udc_name(void);
>  
> +extern int usb_otg_add_gadget_udc(struct device *parent,
> +				  struct usb_gadget *gadget,
> +				  struct device *otg_dev);
> +
>  /*-------------------------------------------------------------------------*/
>  
>  /* utility to simplify dealing with string descriptors */
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-13  7:56     ` Roger Quadros
  (?)
@ 2016-06-13  7:58     ` Peter Chen
  -1 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-13  7:58 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Mon, Jun 13, 2016 at 10:56:30AM +0300, Roger Quadros wrote:
> It provides APIs for the following tasks
> 
> - Registering an OTG/dual-role capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine
> 
> Provide a dual-role device (DRD) state machine.
> 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>
> ---
> v11:
> - remove usb_otg_kick_fsm().
> - typo fixes: structa/structure, upto/up to.
> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.

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

> 
>  drivers/usb/Kconfig          |  18 +
>  drivers/usb/common/Makefile  |   6 +-
>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/core/Kconfig     |  14 -
>  drivers/usb/gadget/Kconfig   |   1 +
>  include/linux/usb/gadget.h   |   2 +
>  include/linux/usb/hcd.h      |   1 +
>  include/linux/usb/otg-fsm.h  |   7 +
>  include/linux/usb/otg.h      | 174 ++++++++-
>  9 files changed, 1070 insertions(+), 30 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
> 
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 8689dcb..ed596ec 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -32,6 +32,23 @@ if USB_SUPPORT
>  config USB_COMMON
>  	tristate
>  
> +config USB_OTG_CORE
> +	tristate
> +
> +config USB_OTG
> +	bool "OTG/Dual-role support"
> +	depends on PM && USB && USB_GADGET
> +	default n
> +	---help---
> +	  The most notable feature of USB OTG is support for a
> +	  "Dual-Role" device, which can act as either a device
> +	  or a host. The initial role is decided by the type of
> +	  plug inserted and can be changed later when two dual
> +	  role devices talk to each other.
> +
> +	  Select this only if your board has Mini-AB/Micro-AB
> +	  connector.
> +
>  config USB_ARCH_HAS_HCD
>  	def_bool y
>  
> @@ -40,6 +57,7 @@ config USB
>  	tristate "Support for Host-side USB"
>  	depends on USB_ARCH_HAS_HCD
>  	select USB_COMMON
> +	select USB_OTG_CORE
>  	select NLS  # for UTF-8 strings
>  	---help---
>  	  Universal Serial Bus (USB) is a specification for a serial bus
> diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
> index f8f2c88..5122b3f 100644
> --- a/drivers/usb/common/Makefile
> +++ b/drivers/usb/common/Makefile
> @@ -7,5 +7,7 @@ usb-common-y			  += common.o
>  usb-common-$(CONFIG_USB_LED_TRIG) += led.o
>  
>  obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
> -usbotg-y		:= usb-otg-fsm.o
> -obj-$(CONFIG_USB_OTG)	+= usbotg.o
> +ifeq ($(CONFIG_USB_OTG),y)
> +usbotg-y		:= usb-otg.o usb-otg-fsm.o
> +obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
> +endif
> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> new file mode 100644
> index 0000000..a23ab1e
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.c
> @@ -0,0 +1,877 @@
> +/**
> + * drivers/usb/common/usb-otg.c - USB OTG core
> + *
> + * Copyright (C) 2016 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/list.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/usb/of.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/workqueue.h>
> +
> +/* OTG device list */
> +LIST_HEAD(otg_list);
> +static DEFINE_MUTEX(otg_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;
> +}
> +
> +/**
> + * usb_otg_get_data() - get usb_otg data structure
> + * @otg_dev:	OTG controller device
> + *
> + * Check if the OTG device is in our OTG list and return
> + * usb_otg data, else NULL.
> + *
> + * otg_list_mutex must be held.
> + *
> + * Return: usb_otg data on success, NULL otherwise.
> + */
> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
> +{
> +	struct usb_otg *otg;
> +
> +	if (!otg_dev)
> +		return NULL;
> +
> +	list_for_each_entry(otg, &otg_list, list) {
> +		if (otg->dev == otg_dev)
> +			return otg;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * usb_otg_start_host() - start/stop the host controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB host controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_host(struct usb_otg *otg, int on)
> +{
> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!otg->host) {
> +		WARN_ONCE(1, "otg: fsm running without host\n");
> +		return 0;
> +	}
> +
> +	if (on) {
> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
> +			return 0;
> +
> +		/* start host */
> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> +				   otg->primary_hcd.irqnum,
> +				   otg->primary_hcd.irqflags);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: host add failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		if (otg->shared_hcd.hcd) {
> +			ret = hcd_ops->add(otg->shared_hcd.hcd,
> +					   otg->shared_hcd.irqnum,
> +					   otg->shared_hcd.irqflags);
> +			if (ret) {
> +				dev_err(otg->dev, "otg: shared host add failed %d\n",
> +					ret);
> +				hcd_ops->remove(otg->primary_hcd.hcd);
> +				return ret;
> +			}
> +		}
> +		otg->flags |= OTG_FLAG_HOST_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
> +			return 0;
> +
> +		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
> +
> +		/* stop host */
> +		if (otg->shared_hcd.hcd)
> +			hcd_ops->remove(otg->shared_hcd.hcd);
> +
> +		hcd_ops->remove(otg->primary_hcd.hcd);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
> +
> +/**
> + * usb_otg_start_gadget() - start/stop the gadget controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB gadget controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_gadget(struct usb_otg *otg, int on)
> +{
> +	struct usb_gadget *gadget = otg->gadget;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!gadget) {
> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
> +		return 0;
> +	}
> +
> +	if (on) {
> +		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
> +			return 0;
> +
> +		ret = otg->gadget_ops->start(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget start failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		otg->flags |= OTG_FLAG_GADGET_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
> +			return 0;
> +
> +		ret = otg->gadget_ops->stop(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
> +
> +/**
> + * drd_set_protocol() -  Set USB protocol if possible
> + * @fsm:	DRD FSM instance
> + * @protocol:	USB protocol to set the state machine to
> + *
> + * Sets the OTG FSM protocol to @protocol if it changed.
> + * fsm->lock must be held.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +	int ret = 0;
> +
> +	if (fsm->protocol != protocol) {
> +		dev_dbg(otg->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(otg, 0);
> +		} else if (fsm->protocol == PROTO_GADGET) {
> +			otg->gadget_ops->connect_control(otg->gadget, false);
> +			ret = otg_start_gadget(otg, 0);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		/* start new protocol */
> +		if (protocol == PROTO_HOST) {
> +			ret = otg_start_host(otg, 1);
> +		} else if (protocol == PROTO_GADGET) {
> +			ret = otg_start_gadget(otg, 1);
> +			otg->gadget_ops->connect_control(otg->gadget, true);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		fsm->protocol = protocol;
> +		return 0;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * drd_set_state() - Set the DRD state machine state.
> + * @fsm:	DRD FSM instance
> + * @new_state:	the new state the DRD FSM must be set to
> + *
> + * Sets the state of the DRD state machine.
> + * fsm->lock must be held.
> + */
> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +
> +	if (otg->state == new_state)
> +		return;
> +
> +	fsm->state_changed = 1;
> +	dev_dbg(otg->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);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_B_PERIPHERAL:
> +		drd_set_protocol(fsm, PROTO_GADGET);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_A_HOST:
> +		drd_set_protocol(fsm, PROTO_HOST);
> +		otg_drv_vbus(otg, 1);
> +		break;
> +	default:
> +		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
> +			 __func__, usb_otg_state_string(new_state));
> +		break;
> +	}
> +
> +	otg->state = new_state;
> +}
> +
> +/**
> + * drd_statemachine() - DRD state change judgement
> + * @otg:	usb_otg instance
> + *
> + * Checks the state machine inputs and state and makes a state change
> + * if required.
> + *
> + * 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
> + *
> + * Return: 0 if state wasn't changed, 1 if state changed.
> + */
> +int drd_statemachine(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +	enum usb_otg_state state;
> +	int ret;
> +
> +	mutex_lock(&fsm->lock);
> +
> +	fsm->state_changed = 0;
> +	state = 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;
> +
> +	default:
> +		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
> +			__func__, usb_otg_state_string(state));
> +		break;
> +	}
> +
> +	ret = fsm->state_changed;
> +	mutex_unlock(&fsm->lock);
> +	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
> +		fsm->state_changed);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(drd_statemachine);
> +
> +/**
> + * usb_drd_work() - Dual-role state machine work function
> + * @work: work_struct context
> + *
> + * Runs the DRD state machine. Scheduled whenever there is a change
> + * in FSM inputs.
> + */
> +static void usb_drd_work(struct work_struct *work)
> +{
> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
> +
> +	pm_runtime_get_sync(otg->dev);
> +	while (drd_statemachine(otg))
> +		;
> +	pm_runtime_put_sync(otg->dev);
> +}
> +
> +/**
> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
> + * @dev: OTG/dual-role controller device.
> + * @config: OTG configuration.
> + *
> + * Registers the OTG/dual-role controller device with the USB OTG core.
> + *
> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
> + */
> +struct usb_otg *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config)
> +{
> +	struct usb_otg *otg;
> +	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 */
> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
> +	if (!otg) {
> +		ret = -ENOMEM;
> +		goto unlock;
> +	}
> +
> +	otg->dev = dev;
> +	/* otg->caps is controller caps + DT overrides */
> +	otg->caps = *config->otg_caps;
> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
> +	if (ret)
> +		goto err_wq;
> +
> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
> +	     otg->caps.adp_support) && !config->otg_work) {
> +		dev_err(dev,
> +			"otg: otg_work must be provided for OTG support\n");
> +		ret = -EINVAL;
> +		goto err_wq;
> +	}
> +
> +	if (config->otg_work)	/* custom otg_work ? */
> +		INIT_WORK(&otg->work, config->otg_work);
> +	else
> +		INIT_WORK(&otg->work, usb_drd_work);
> +
> +	otg->wq = create_freezable_workqueue("usb_otg");
> +	if (!otg->wq) {
> +		dev_err(dev, "otg: %s: can't create workqueue\n",
> +			__func__);
> +		ret = -ENOMEM;
> +		goto err_wq;
> +	}
> +
> +	/* set otg ops */
> +	otg->fsm.ops = config->fsm_ops;
> +
> +	mutex_init(&otg->fsm.lock);
> +
> +	list_add_tail(&otg->list, &otg_list);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return otg;
> +
> +err_wq:
> +	kfree(otg);
> +unlock:
> +	mutex_unlock(&otg_list_mutex);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register);
> +
> +/**
> + * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
> + * @dev: OTG controller device.
> + *
> + * Unregisters the OTG/dual-role 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 *otg;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(dev);
> +	if (!otg) {
> +		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 (otg->host || otg->gadget) {
> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
> +			__func__);
> +		mutex_unlock(&otg_list_mutex);
> +		return -EBUSY;
> +	}
> +
> +	/* OTG FSM is halted when host/gadget unregistered */
> +	destroy_workqueue(otg->wq);
> +
> +	/* remove from otg list */
> +	list_del(&otg->list);
> +	kfree(otg);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
> +
> +/**
> + * usb_otg_start_fsm() - Start the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
> + * must be ready for the OTG FSM to start.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_start_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (fsm->running)
> +		goto kick_fsm;
> +
> +	if (!otg->host) {
> +		dev_info(otg->dev, "otg: can't start till host registers\n");
> +		return;
> +	}
> +
> +	if (!otg->gadget) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget UDC registers\n");
> +		return;
> +	}
> +
> +	if (!otg->gadget_ready) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget function registers\n");
> +		return;
> +	}
> +
> +	fsm->running = true;
> +kick_fsm:
> +	queue_work(otg->wq, &otg->work);
> +}
> +
> +/**
> + * usb_otg_stop_fsm() - Stop the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Stops the HCD, UDC and the OTG FSM.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_stop_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (!fsm->running)
> +		return;
> +
> +	/* no more new events queued */
> +	fsm->running = false;
> +
> +	flush_workqueue(otg->wq);
> +	otg->state = OTG_STATE_UNDEFINED;
> +
> +	/* stop host/gadget immediately */
> +	if (fsm->protocol == PROTO_HOST) {
> +		otg_start_host(otg, 0);
> +	} else if (fsm->protocol == PROTO_GADGET) {
> +		otg->gadget_ops->connect_control(otg->gadget, false);
> +		otg_start_gadget(otg, 0);
> +	}
> +	fsm->protocol = PROTO_UNDEF;
> +}
> +
> +/**
> + * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
> + * @otg:	usb_otg 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 usb_otg *otg)
> +{
> +	/* Don't kick FSM till it has started */
> +	if (!otg->fsm.running)
> +		return;
> +
> +	/* Kick FSM */
> +	queue_work(otg->wq, &otg->work);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
> +
> +/**
> + * usb_otg_register_hcd() - Register the host controller to OTG core
> + * @hcd:	host controller
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
> + * hcd->otg_dev must contain the related otg controller device.
> + *
> + * Return: 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 *otg;
> +	struct device *hcd_dev = hcd->self.controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(hcd_dev,
> +			"otg: controller not yet registered. deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	/* HCD will be started by OTG fsm when needed */
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->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 == otg->primary_hcd.hcd) {
> +			if (otg->shared_hcd.hcd) {
> +				dev_err(otg_dev, "otg: shared host already registered\n");
> +				goto err;
> +			}
> +
> +			otg->shared_hcd.hcd = hcd;
> +			otg->shared_hcd.irqnum = irqnum;
> +			otg->shared_hcd.irqflags = irqflags;
> +			otg->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;
> +		}
> +
> +		otg->primary_hcd.hcd = hcd;
> +		otg->primary_hcd.irqnum = irqnum;
> +		otg->primary_hcd.irqflags = irqflags;
> +		otg->primary_hcd.ops = ops;
> +		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
> +		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(otg);
> +	} else {
> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> +	}
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +
> +err:
> +	mutex_unlock(&otg->fsm.lock);
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> +
> +/**
> + * usb_otg_unregister_hcd() - Unregister the 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 *otg;
> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (hcd == otg->primary_hcd.hcd) {
> +		otg->primary_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else if (hcd == otg->shared_hcd.hcd) {
> +		otg->shared_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	/* stop FSM & Host */
> +	usb_otg_stop_fsm(otg);
> +	otg->host = NULL;
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> +
> +/**
> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
> + * @gadget:	gadget controller instance
> + * @ops:	gadget interface ops
> + *
> + * 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 up to the OTG state machine to do so.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_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);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(gadget_dev,
> +			"otg: controller not yet registered, deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget) {
> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> +		mutex_unlock(&otg->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	otg->gadget = gadget;
> +	otg->gadget_ops = ops;
> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> +		 dev_name(&gadget->dev));
> +
> +	/* FSM will be started in usb_otg_gadget_ready() */
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> +
> +/**
> + * usb_otg_unregister_gadget() - Unregister the 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 *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* FSM must be stopped in usb_otg_gadget_ready() */
> +	if (otg->gadget_ready) {
> +		dev_err(otg_dev,
> +			"otg: gadget %s unregistered before being unready, forcing stop\n",
> +			dev_name(&gadget->dev));
> +		usb_otg_stop_fsm(otg);
> +	}
> +
> +	otg->gadget = NULL;
> +	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
> + * @gadget:	gadget controller
> + * @ready:	0: function driver ready, 1: function driver not ready
> + *
> + * Notify the OTG core about status of the gadget function driver.
> + * As OTG core is responsible to start/stop the gadget controller, it
> + * must be aware when the gadget function driver is available or not.
> + * This function is used by the Gadget core to inform the OTG core
> + * about the gadget function driver readyness.
> + *
> + * Return: 0 on sucess, error value otherwise.
> + */
> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* Start/stop FSM & gadget */
> +	otg->gadget_ready = ready;
> +	if (ready)
> +		usb_otg_start_fsm(otg);
> +	else
> +		usb_otg_stop_fsm(otg);
> +
> +	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
> +		ready ? "" : "not ");
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
> index ae228d0..37f8c54 100644
> --- a/drivers/usb/core/Kconfig
> +++ b/drivers/usb/core/Kconfig
> @@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
>  
>  	  If you are unsure about this, say N here.
>  
> -config USB_OTG
> -	bool "OTG support"
> -	depends on PM
> -	default n
> -	help
> -	  The most notable feature of USB OTG is support for a
> -	  "Dual-Role" device, which can act as either a device
> -	  or a host. The initial role is decided by the type of
> -	  plug inserted and can be changed later when two dual
> -	  role devices talk to each other.
> -
> -	  Select this only if your board has Mini-AB/Micro-AB
> -	  connector.
> -
>  config USB_OTG_WHITELIST
>  	bool "Rely on OTG and EH Targeted Peripherals List"
>  	depends on USB
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index 3c3f31c..5fc9095 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -16,6 +16,7 @@
>  menuconfig USB_GADGET
>  	tristate "USB Gadget Support"
>  	select USB_COMMON
> +	select USB_OTG_CORE
>  	select NLS
>  	help
>  	   USB is a master/slave protocol, organized with one master
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index f4fc0aa..1d74fb8 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>   * @in_epnum: last used in ep number
>   * @mA: last set mA value
>   * @otg_caps: OTG capabilities of this gadget.
> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>   * @sg_supported: true if we can handle scatter-gather
>   * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
>   *	gadget driver must provide a USB OTG descriptor.
> @@ -385,6 +386,7 @@ struct usb_gadget {
>  	unsigned			in_epnum;
>  	unsigned			mA;
>  	struct usb_otg_caps		*otg_caps;
> +	struct device			*otg_dev;
>  
>  	unsigned			sg_supported:1;
>  	unsigned			is_otg:1;
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 7729c1f..36bd54f 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -185,6 +185,7 @@ struct usb_hcd {
>  	struct mutex		*bandwidth_mutex;
>  	struct usb_hcd		*shared_hcd;
>  	struct usb_hcd		*primary_hcd;
> +	struct device		*otg_dev;	/* OTG controller device */
>  
>  
>  #define HCD_BUFFER_POOLS	4
> diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
> index 26e6531..943714a 100644
> --- a/include/linux/usb/otg-fsm.h
> +++ b/include/linux/usb/otg-fsm.h
> @@ -60,6 +60,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
> @@ -132,6 +137,7 @@ enum otg_fsm_timer {
>   * 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
> + * running:	state machine running/stopped indicator
>   */
>  struct otg_fsm {
>  	/* Input */
> @@ -187,6 +193,7 @@ struct otg_fsm {
>  	int b_ase0_brst_tmout;
>  	int a_bidl_adis_tmout;
>  
> +	bool running;
>  	struct otg_fsm_ops *ops;
>  
>  	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index 85b8fb5..9d72951 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -10,10 +10,67 @@
>  #define __LINUX_USB_OTG_H
>  
>  #include <linux/phy/phy.h>
> -#include <linux/usb/phy.h>
> -#include <linux/usb/otg-fsm.h>
> +#include <linux/device.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
> + * @otg_dev: OTG controller device
> + */
> +struct otg_hcd {
> +	struct usb_hcd *hcd;
> +	unsigned int irqnum;
> +	unsigned long irqflags;
> +	struct otg_hcd_ops *ops;
> +	struct device *otg_dev;
> +};
> +
> +/**
> + * struct usb_otg_caps - describes the otg capabilities of the device
> + * @otg_rev: The OTG revision number the device is compliant with, it's
> + *		in binary-coded decimal (i.e. 2.0 is 0200H).
> + * @hnp_support: Indicates if the device supports HNP.
> + * @srp_support: Indicates if the device supports SRP.
> + * @adp_support: Indicates if the device supports ADP.
> + */
> +struct usb_otg_caps {
> +	u16 otg_rev;
> +	bool hnp_support;
> +	bool srp_support;
> +	bool adp_support;
> +};
>  
> +/**
> + * 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
> + * @hcd_ops: host controller interface
> + * ------- internal use only -------
> + * @primary_hcd: primary host state and interface
> + * @shared_hcd: shared host state and interface
> + * @gadget_ops: gadget controller interface
> + * @list: list of OTG controllers
> + * @work: OTG state machine work
> + * @wq: OTG state machine work queue
> + * @flags: to track if host/gadget is running
> + */
>  struct usb_otg {
>  	u8			default_a;
>  
> @@ -24,9 +81,25 @@ struct usb_otg {
>  	struct usb_gadget	*gadget;
>  
>  	enum usb_otg_state	state;
> +	struct device *dev;
> +	struct usb_otg_caps	caps;
>  	struct otg_fsm fsm;
>  	struct otg_hcd_ops	*hcd_ops;
>  
> +	/* internal use only */
> +	struct otg_hcd primary_hcd;
> +	struct otg_hcd shared_hcd;
> +	struct otg_gadget_ops *gadget_ops;
> +	bool gadget_ready;
> +	struct list_head list;
> +	struct work_struct work;
> +	struct workqueue_struct *wq;
> +	u32 flags;
> +#define OTG_FLAG_GADGET_RUNNING (1 << 0)
> +#define OTG_FLAG_HOST_RUNNING (1 << 1)
> +	/* 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);
>  
> @@ -42,26 +115,95 @@ struct usb_otg {
>  
>  	/* start or continue HNP role switch */
>  	int	(*start_hnp)(struct usb_otg *otg);
> -
> +/*---------------------------------------------------------------*/
>  };
>  
>  /**
> - * struct usb_otg_caps - describes the otg capabilities of the device
> - * @otg_rev: The OTG revision number the device is compliant with, it's
> - *		in binary-coded decimal (i.e. 2.0 is 0200H).
> - * @hnp_support: Indicates if the device supports HNP.
> - * @srp_support: Indicates if the device supports SRP.
> - * @adp_support: Indicates if the device supports ADP.
> + * struct usb_otg_config - OTG controller configuration
> + * @caps: OTG capabilities of the controller
> + * @ops: OTG FSM operations
> + * @otg_work: optional custom OTG state machine work function
>   */
> -struct usb_otg_caps {
> -	u16 otg_rev;
> -	bool hnp_support;
> -	bool srp_support;
> -	bool adp_support;
> +struct usb_otg_config {
> +	struct usb_otg_caps *otg_caps;
> +	struct otg_fsm_ops *fsm_ops;
> +	void (*otg_work)(struct work_struct *work);
>  };
>  
>  extern const char *usb_otg_state_string(enum usb_otg_state state);
>  
> +#if IS_ENABLED(CONFIG_USB_OTG)
> +struct usb_otg *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 usb_otg *otg);
> +int usb_otg_start_host(struct usb_otg *otg, int on);
> +int usb_otg_start_gadget(struct usb_otg *otg, int on);
> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
> +
> +#else /* CONFIG_USB_OTG */
> +
> +static inline struct usb_otg *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 usb_otg *otg)
> +{
> +}
> +
> +static inline int usb_otg_start_host(struct usb_otg *otg, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> +{
> +	return -ENOTSUPP;
> +}
> +#endif /* CONFIG_USB_OTG */
> +
> +/*------------- deprecated interface -----------------------------*/
>  /* Context: can sleep */
>  static inline int
>  otg_start_hnp(struct usb_otg *otg)
> @@ -113,6 +255,8 @@ 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);
>  
> @@ -237,4 +381,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
>  	return otg->fsm.ops->start_gadget(otg, on);
>  }
>  
> +int drd_statemachine(struct usb_otg *otg);
> +
>  #endif /* __LINUX_USB_OTG_H */
> -- 
> 2.7.4
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
  2016-06-13  7:56     ` Peter Chen
@ 2016-06-13  8:06         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:06 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 13/06/16 10:56, Peter Chen wrote:
> On Mon, Jun 13, 2016 at 10:55:12AM +0300, Roger Quadros wrote:
>>  err1:
>> -	if (ret != -EISNAM)
>> +	if ((ret != -EISNAM))
> 
> Since you do not need above change.

Ah :P, will fix it.
> 
> Expect above, I am ok with this patch.
> 
> Acked-by: Peter Chen <peter.chen@nxp.com>

Thanks for the patient review of this entire series :).

cheers,
-roger

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

* Re: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
@ 2016-06-13  8:06         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:06 UTC (permalink / raw)
  To: Peter Chen
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 13/06/16 10:56, Peter Chen wrote:
> On Mon, Jun 13, 2016 at 10:55:12AM +0300, Roger Quadros wrote:
>>  err1:
>> -	if (ret != -EISNAM)
>> +	if ((ret != -EISNAM))
> 
> Since you do not need above change.

Ah :P, will fix it.
> 
> Expect above, I am ok with this patch.
> 
> Acked-by: Peter Chen <peter.chen-3arQi8VN3Tc@public.gmane.org>

Thanks for the patient review of this entire series :).

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

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

* RE: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-13  8:13     ` Jun Li
  0 siblings, 0 replies; 172+ messages in thread
From: Jun Li @ 2016-06-13  8:13 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

Hi

> diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
> index e3d0161..d7ec471 100644
> --- a/drivers/usb/common/common.c
> +++ b/drivers/usb/common/common.c
> @@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,  }
> EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
> 
> +#ifdef CONFIG_USB_OTG
> +/**
> + * of_usb_get_otg - get the OTG controller linked to the USB controller
> + * @np: Pointer to the device_node of the USB controller
> + * @otg_caps: Pointer to the target usb_otg_caps to be set

Remove otg_caps.

Li Jun

> + *
> + * Returns the OTG controller device or NULL on error.
> + */
> +struct device *of_usb_get_otg(struct device_node *np) {
> +	struct device_node *otg_np;
> +	struct platform_device *pdev;
> +
> +	otg_np = of_parse_phandle(np, "otg-controller", 0);
> +	if (!otg_np)
> +		return NULL;
> +
> +	pdev = of_find_device_by_node(otg_np);
> +	of_node_put(otg_np);
> +	if (!pdev)
> +		return NULL;
> +
> +	return &pdev->dev;
> +}
> +EXPORT_SYMBOL_GPL(of_usb_get_otg);
> +#endif
> +
>  #endif
> 
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index
> de3237f..499a4e8 100644
> --- a/include/linux/usb/of.h
> +++ b/include/linux/usb/of.h
> @@ -40,6 +40,15 @@ static inline struct device_node
> *usb_of_get_child_node  }  #endif
> 
> +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG) struct device
> +*of_usb_get_otg(struct device_node *np); #else static inline struct
> +device *of_usb_get_otg(struct device_node *np) {
> +	return NULL;
> +}
> +#endif
> +
>  #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)  enum
> usb_phy_interface of_usb_get_phy_mode(struct device_node *np);  #else
> --
> 2.7.4

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

* RE: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-13  8:13     ` Jun Li
  0 siblings, 0 replies; 172+ messages in thread
From: Jun Li @ 2016-06-13  8:13 UTC (permalink / raw)
  To: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi

> diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
> index e3d0161..d7ec471 100644
> --- a/drivers/usb/common/common.c
> +++ b/drivers/usb/common/common.c
> @@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,  }
> EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
> 
> +#ifdef CONFIG_USB_OTG
> +/**
> + * of_usb_get_otg - get the OTG controller linked to the USB controller
> + * @np: Pointer to the device_node of the USB controller
> + * @otg_caps: Pointer to the target usb_otg_caps to be set

Remove otg_caps.

Li Jun

> + *
> + * Returns the OTG controller device or NULL on error.
> + */
> +struct device *of_usb_get_otg(struct device_node *np) {
> +	struct device_node *otg_np;
> +	struct platform_device *pdev;
> +
> +	otg_np = of_parse_phandle(np, "otg-controller", 0);
> +	if (!otg_np)
> +		return NULL;
> +
> +	pdev = of_find_device_by_node(otg_np);
> +	of_node_put(otg_np);
> +	if (!pdev)
> +		return NULL;
> +
> +	return &pdev->dev;
> +}
> +EXPORT_SYMBOL_GPL(of_usb_get_otg);
> +#endif
> +
>  #endif
> 
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index
> de3237f..499a4e8 100644
> --- a/include/linux/usb/of.h
> +++ b/include/linux/usb/of.h
> @@ -40,6 +40,15 @@ static inline struct device_node
> *usb_of_get_child_node  }  #endif
> 
> +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG) struct device
> +*of_usb_get_otg(struct device_node *np); #else static inline struct
> +device *of_usb_get_otg(struct device_node *np) {
> +	return NULL;
> +}
> +#endif
> +
>  #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)  enum
> usb_phy_interface of_usb_get_phy_mode(struct device_node *np);  #else
> --
> 2.7.4

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

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

* Re: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-13  8:16       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:16 UTC (permalink / raw)
  To: Jun Li, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

On 13/06/16 11:13, Jun Li wrote:
> Hi
> 
>> diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
>> index e3d0161..d7ec471 100644
>> --- a/drivers/usb/common/common.c
>> +++ b/drivers/usb/common/common.c
>> @@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,  }
>> EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
>>
>> +#ifdef CONFIG_USB_OTG
>> +/**
>> + * of_usb_get_otg - get the OTG controller linked to the USB controller
>> + * @np: Pointer to the device_node of the USB controller
>> + * @otg_caps: Pointer to the target usb_otg_caps to be set
> 
> Remove otg_caps.

Sure.

> 
>> + *
>> + * Returns the OTG controller device or NULL on error.
>> + */
>> +struct device *of_usb_get_otg(struct device_node *np) {
>> +	struct device_node *otg_np;
>> +	struct platform_device *pdev;
>> +
>> +	otg_np = of_parse_phandle(np, "otg-controller", 0);
>> +	if (!otg_np)
>> +		return NULL;
>> +
>> +	pdev = of_find_device_by_node(otg_np);
>> +	of_node_put(otg_np);
>> +	if (!pdev)
>> +		return NULL;
>> +
>> +	return &pdev->dev;
>> +}
>> +EXPORT_SYMBOL_GPL(of_usb_get_otg);
>> +#endif
>> +
>>  #endif
>>
>>  MODULE_LICENSE("GPL");
>> diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index
>> de3237f..499a4e8 100644
>> --- a/include/linux/usb/of.h
>> +++ b/include/linux/usb/of.h
>> @@ -40,6 +40,15 @@ static inline struct device_node
>> *usb_of_get_child_node  }  #endif
>>
>> +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG) struct device
>> +*of_usb_get_otg(struct device_node *np); #else static inline struct
>> +device *of_usb_get_otg(struct device_node *np) {
>> +	return NULL;
>> +}
>> +#endif
>> +
>>  #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)  enum
>> usb_phy_interface of_usb_get_phy_mode(struct device_node *np);  #else
>> --
>> 2.7.4
> 

--
cheers,
-roger

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

* Re: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-13  8:16       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:16 UTC (permalink / raw)
  To: Jun Li, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On 13/06/16 11:13, Jun Li wrote:
> Hi
> 
>> diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
>> index e3d0161..d7ec471 100644
>> --- a/drivers/usb/common/common.c
>> +++ b/drivers/usb/common/common.c
>> @@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,  }
>> EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
>>
>> +#ifdef CONFIG_USB_OTG
>> +/**
>> + * of_usb_get_otg - get the OTG controller linked to the USB controller
>> + * @np: Pointer to the device_node of the USB controller
>> + * @otg_caps: Pointer to the target usb_otg_caps to be set
> 
> Remove otg_caps.

Sure.

> 
>> + *
>> + * Returns the OTG controller device or NULL on error.
>> + */
>> +struct device *of_usb_get_otg(struct device_node *np) {
>> +	struct device_node *otg_np;
>> +	struct platform_device *pdev;
>> +
>> +	otg_np = of_parse_phandle(np, "otg-controller", 0);
>> +	if (!otg_np)
>> +		return NULL;
>> +
>> +	pdev = of_find_device_by_node(otg_np);
>> +	of_node_put(otg_np);
>> +	if (!pdev)
>> +		return NULL;
>> +
>> +	return &pdev->dev;
>> +}
>> +EXPORT_SYMBOL_GPL(of_usb_get_otg);
>> +#endif
>> +
>>  #endif
>>
>>  MODULE_LICENSE("GPL");
>> diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index
>> de3237f..499a4e8 100644
>> --- a/include/linux/usb/of.h
>> +++ b/include/linux/usb/of.h
>> @@ -40,6 +40,15 @@ static inline struct device_node
>> *usb_of_get_child_node  }  #endif
>>
>> +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG) struct device
>> +*of_usb_get_otg(struct device_node *np); #else static inline struct
>> +device *of_usb_get_otg(struct device_node *np) {
>> +	return NULL;
>> +}
>> +#endif
>> +
>>  #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)  enum
>> usb_phy_interface of_usb_get_phy_mode(struct device_node *np);  #else
>> --
>> 2.7.4
> 

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

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

* [PATCH v11 09/14] usb: of: add an API to get OTG device from USB controller node
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-13  8:23     ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:23 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

The OTG controller and the USB controller can be linked via the
'otg-controller' property in the USB controller's device node.

of_usb_get_otg() can be used to get the OTG controller device
from the USB controller's device node.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v11:
- removed unnecessary @otg_caps from documentation of of_usb_get_otg()

 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/common.c                       | 26 +++++++++++++++++++++++
 include/linux/usb/of.h                            |  9 ++++++++
 3 files changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index bba8257..f6866c1 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -24,6 +24,9 @@ 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.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index e3d0161..d0c104c 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -238,6 +238,32 @@ int of_usb_update_otg_caps(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
 
+#ifdef CONFIG_USB_OTG
+/**
+ * of_usb_get_otg - get the OTG controller linked to the USB controller
+ * @np: Pointer to the device_node of the USB controller
+ *
+ * Return: The OTG controller device or NULL on error.
+ */
+struct device *of_usb_get_otg(struct device_node *np)
+{
+	struct device_node *otg_np;
+	struct platform_device *pdev;
+
+	otg_np = of_parse_phandle(np, "otg-controller", 0);
+	if (!otg_np)
+		return NULL;
+
+	pdev = of_find_device_by_node(otg_np);
+	of_node_put(otg_np);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_otg);
+#endif
+
 #endif
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index de3237f..499a4e8 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -40,6 +40,15 @@ static inline struct device_node *usb_of_get_child_node
 }
 #endif
 
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG)
+struct device *of_usb_get_otg(struct device_node *np);
+#else
+static inline struct device *of_usb_get_otg(struct device_node *np)
+{
+	return NULL;
+}
+#endif
+
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
-- 
2.7.4

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

* [PATCH v11 09/14] usb: of: add an API to get OTG device from USB controller node
@ 2016-06-13  8:23     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-13  8:23 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

The OTG controller and the USB controller can be linked via the
'otg-controller' property in the USB controller's device node.

of_usb_get_otg() can be used to get the OTG controller device
from the USB controller's device node.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
v11:
- removed unnecessary @otg_caps from documentation of of_usb_get_otg()

 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/common.c                       | 26 +++++++++++++++++++++++
 include/linux/usb/of.h                            |  9 ++++++++
 3 files changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index bba8257..f6866c1 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -24,6 +24,9 @@ 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.
 
 This is an attribute to a USB controller such as:
 
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index e3d0161..d0c104c 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -238,6 +238,32 @@ int of_usb_update_otg_caps(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
 
+#ifdef CONFIG_USB_OTG
+/**
+ * of_usb_get_otg - get the OTG controller linked to the USB controller
+ * @np: Pointer to the device_node of the USB controller
+ *
+ * Return: The OTG controller device or NULL on error.
+ */
+struct device *of_usb_get_otg(struct device_node *np)
+{
+	struct device_node *otg_np;
+	struct platform_device *pdev;
+
+	otg_np = of_parse_phandle(np, "otg-controller", 0);
+	if (!otg_np)
+		return NULL;
+
+	pdev = of_find_device_by_node(otg_np);
+	of_node_put(otg_np);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_otg);
+#endif
+
 #endif
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index de3237f..499a4e8 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -40,6 +40,15 @@ static inline struct device_node *usb_of_get_child_node
 }
 #endif
 
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_OTG)
+struct device *of_usb_get_otg(struct device_node *np);
+#else
+static inline struct device *of_usb_get_otg(struct device_node *np)
+{
+	return NULL;
+}
+#endif
+
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
-- 
2.7.4

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
  2016-06-10 13:07 ` Roger Quadros
                   ` (14 preceding siblings ...)
  (?)
@ 2016-06-14  2:17 ` Peter Chen
  2016-06-14  8:12     ` Roger Quadros
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-14  2:17 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Fri, Jun 10, 2016 at 04:07:09PM +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 TI platform related patches will be sent separately.
> 
> Series is based on v4.7-rc1 + balbi/usb.git testing/next
> commit 4a2786c10462df650965785462ca82c185164d98.
> 

Roger, I have acked for all your patches. You can send v11 for all
patches. When you get Felipe's ack for gadget part, Alan's ack
for hcd part, and your dwc3 and platform related patches ack,
you can let Felipe help to queue this patch set since some of
the code based on his tree. Thank you for your hard work for it.

Peter

> Why?:
> ----
> 
> Currently there is no central location where OTG/dual-role functionality is
> implemented in the Linux USB stack and every USB controller driver is
> doing their own thing for OTG/dual-role. We can benefit from code-reuse
> and simplicity by adding the OTG/dual-role core driver.
> 
> 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 controllers in dual-role mode. i.e. to stop and start them
> from a central location. This central location should be the
> USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG/dual-role core consists of a set of APIs that allow
> registration of OTG controller device and OTG capable host and gadget
> controllers.
> 
> - The OTG controller driver can provide the OTG capabilities and the
> Finite State Machine work function via 'struct usb_otg_config'
> at the time of registration i.e. usb_otg_register();
> 
> 	struct usb_otg *usb_otg_register(struct device *dev,
>         	                         struct usb_otg_config *config);
> 	int usb_otg_unregister(struct device *dev);
> 	/**
> 	 * struct usb_otg_config - otg controller configuration
> 	 * @caps: otg capabilities of the controller
> 	 * @ops: otg fsm operations
> 	 * @otg_work: optional custom otg state machine work function
> 	 */
> 	struct usb_otg_config {
> 	        struct usb_otg_caps *otg_caps;
> 	        struct otg_fsm_ops *fsm_ops;
> 	        void (*otg_work)(struct work_struct *work);
> 	};
> 
> The dual-role state machine is built-into the OTG core so nothing
> special needs to be provided if only dual-role functionality is desired.
> The low level OTG controller driver ops are povided via
> 'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.
> 
> After registration, the OTG core waits for host, gadget controller
> and the gadget function driver to be registered. Once all resources are
> available it instantiates the Finite State Machine (FSM).
> The host/gadget controllers are started/stopped according to the FSM.
> 
> - Host and gadget controllers that are a part of OTG/dual-role port must
> use the OTG core provided APIs to add/remove the host/gadget.
> i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
> gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
> This ensures that the host and gadget controllers are not started till
> the state machine is ready and the right bus conditions are met.
> It also allows the host and gadget controllers to provide the OTG
> controller device to link them together. For Device tree boots
> the related OTG controller is automatically picked up via the
> 'otg-controller' property in the Host/Gadget controller nodes.
> 
> 	int usb_otg_add_hcd(struct usb_hcd *hcd,
> 			    unsigned int irqnum, unsigned long irqflags,
> 			    struct device *otg_dev);
> 	void usb_otg_remove_hcd(struct usb_hcd *hcd);
> 
> 	int usb_otg_add_gadget_udc(struct device *parent,
> 				   struct usb_gadget *gadget,
> 				   struct device *otg_dev);
> 	usb_del_gadget_udc() must be used for removal.
> 
> 
> - During the lifetime of the FSM, the OTG controller driver can provide
> inputs event changes using usb_otg_sync_inputs(). The OTG core will
> then schedule the FSM work function (or internal dual-role state machine)
> to update the FSM state. The FSM then calls the OTG controller
> operations (fsm_ops) as necessary.
> 	void usb_otg_sync_inputs(struct usb_otg *otg);
> 
> - The following 2 functions are provided as helpers for use by the
> OTG controller driver to start/stop the host/gadget controllers.
> 	int usb_otg_start_host(struct usb_otg *otg, int on);
> 	int usb_otg_start_gadget(struct usb_otg *otg, int on);
> 
> - The following function is provided for use by the USB host stack
> to sync OTG related events to the OTG state machine.
> e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> 	int usb_otg_kick_fsm(struct device *otg_device);
> 
> - The following function is provided for use by the USB gadget stack
> to notify OTG/DRD about gadget function driver being ready/not-ready
> 	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> 
> Changelog:
> ---------
> v10:
> - added missing mutex_unlock in failure path in usb_otg_unregister()
> - removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
> - comment fixes: urb->URB.
> - fix commit log: say dev_vdbg() instead of dev_dbg().
> - Update comments so that HCD means Host Controller Driver.
> - rebased on Felipe's balbi/usb.git /testing/next
> - include <linux/usb/of.h> in usb-otg.c
> - in usb_otg_start_host() check if hcd_ops->add() failed and return
> error code if it did.
> - in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
> error code if it did.
> - follow kernel-doc style in usb-otg.c
> 
> v9:
> - In the DT bindings, clearly indicate which properties are for OTG controller
> and which ones are for host/device controllers
> - Removed host/gadget wait list from otg core. Use defer probing if host/gadget
> registers before dual-role/otg controller.
> - move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
> to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
> an additional mechanism to know when the gadget function driver registers.
> So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
> ready/not-ready function driver.
> - update otg->caps based on capabilities provided by the controller and the
> device tree overrides.
> - in usb_drd_work() we must keep calling the drd_statemachine() as long as
> there is a state change.
> - updated kconfig so that usbotg can be a module when both host and gadget
> are modules.
> - rebased on v4.7-rc1
> 
> v8:
> - split out start/stop gadget and connect/disconnect operations.
> - make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
> - use create_freezable_workqueue() for OTG work as per Peter's suggestion.
> - remove usb-otg.h as we're not initializing any OTG timers.
> - don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)
> 
> v7:
> - added dual-role support for host controllers requiring a companion
> controller. e.g. EHCI + OHCI.
> - added of_usb_get_otg() to get the OTG controller device
> from the USB controller's device node.
> - addressed review comments.
> 
> v6:
> - added otg specific APIs for host/gadget registration. behaviour of
> original host/gadget API remains unchanged. Platform devices can now
> pass the otg device explicitly while registering host/gadget.
> - moved hcd specific operations from struct otg_fsm to struct hcd_ops.
> - made struct usb_otg mandatory for all otg related APIs.
> - allow otg controller to provide it's own otg_work function so that
> it can implement it's own state machine.
> - removed otg fsm and timers from usb-otg.c. Only dual-role state machine
> is implemented.
> - vbus is controlled in the dual-role state machine.
> - PM runtime is used around drd_statemachine().
> - added otg_dev to xhci platform data to allow platform code to specify
> the otg controller tied to the xhci host controller.
> 
> v5: Internal version. Not sent to mailing list
> 
> 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.
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: hcd: Initialize hcd->flags to 0
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   usb: hcd.h: Add OTG to HCD interface
>   usb: otg-fsm: use usb_otg wherever possible
>   usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
>   usb: otg: add OTG/dual-role core
>   usb: of: add an API to get OTG device from USB controller node
>   usb: otg: use dev_vdbg() instead of VDBG()
>   usb: hcd: Adapt to OTG core
>   usb: gadget: udc: adapt to OTG core
>   usb: host: xhci-plat: Add otg device to platform data
> 
> Yoshihiro Shimoda (1):
>   usb: otg: add hcd companion support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |   6 +
>  Documentation/usb/chipidea.txt                    |   2 +-
>  drivers/usb/Kconfig                               |  18 +
>  drivers/usb/Makefile                              |   1 +
>  drivers/usb/chipidea/Makefile                     |   2 +-
>  drivers/usb/chipidea/ci.h                         |   3 +-
>  drivers/usb/chipidea/core.c                       |  14 +-
>  drivers/usb/chipidea/debug.c                      |   2 +-
>  drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
>  drivers/usb/chipidea/otg_fsm.h                    |   2 +-
>  drivers/usb/chipidea/udc.c                        |  17 +-
>  drivers/usb/common/Makefile                       |   5 +-
>  drivers/usb/common/common.c                       |  27 +
>  drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
>  drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
>  drivers/usb/core/Kconfig                          |  22 -
>  drivers/usb/core/hcd.c                            |  56 ++
>  drivers/usb/gadget/Kconfig                        |   1 +
>  drivers/usb/gadget/udc/core.c                     | 202 ++++-
>  drivers/usb/host/xhci-plat.c                      |  35 +-
>  drivers/usb/phy/Kconfig                           |   2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
>  drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
>  include/linux/usb/gadget.h                        |  22 +
>  include/linux/usb/hcd.h                           |  29 +
>  include/linux/usb/of.h                            |   9 +
>  include/linux/usb/otg-fsm.h                       | 154 +---
>  include/linux/usb/otg.h                           | 290 ++++++-
>  include/linux/usb/xhci_pdriver.h                  |   3 +
>  29 files changed, 1918 insertions(+), 462 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
> 
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
  2016-06-14  2:17 ` [PATCH v10 00/14] USB OTG/dual-role framework Peter Chen
@ 2016-06-14  8:12     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:12 UTC (permalink / raw)
  To: Peter Chen, Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

+Alan. (Sorry Alan, I forgot to add copy you in this series).

Hi,

On 14/06/16 05:17, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:09PM +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 TI platform related patches will be sent separately.
>>
>> Series is based on v4.7-rc1 + balbi/usb.git testing/next
>> commit 4a2786c10462df650965785462ca82c185164d98.
>>
> 
> Roger, I have acked for all your patches. You can send v11 for all
> patches. When you get Felipe's ack for gadget part, Alan's ack
> for hcd part, and your dwc3 and platform related patches ack,
> you can let Felipe help to queue this patch set since some of
> the code based on his tree. Thank you for your hard work for it.

Thanks Peter,

I'll send v11, with your Acks.

cheers,
-roger

> 
> Peter
> 
>> Why?:
>> ----
>>
>> Currently there is no central location where OTG/dual-role functionality is
>> implemented in the Linux USB stack and every USB controller driver is
>> doing their own thing for OTG/dual-role. We can benefit from code-reuse
>> and simplicity by adding the OTG/dual-role core driver.
>>
>> 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 controllers in dual-role mode. i.e. to stop and start them
>> from a central location. This central location should be the
>> USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.
>>
>> What?:
>> -----
>>
>> The OTG/dual-role core consists of a set of APIs that allow
>> registration of OTG controller device and OTG capable host and gadget
>> controllers.
>>
>> - The OTG controller driver can provide the OTG capabilities and the
>> Finite State Machine work function via 'struct usb_otg_config'
>> at the time of registration i.e. usb_otg_register();
>>
>> 	struct usb_otg *usb_otg_register(struct device *dev,
>>         	                         struct usb_otg_config *config);
>> 	int usb_otg_unregister(struct device *dev);
>> 	/**
>> 	 * struct usb_otg_config - otg controller configuration
>> 	 * @caps: otg capabilities of the controller
>> 	 * @ops: otg fsm operations
>> 	 * @otg_work: optional custom otg state machine work function
>> 	 */
>> 	struct usb_otg_config {
>> 	        struct usb_otg_caps *otg_caps;
>> 	        struct otg_fsm_ops *fsm_ops;
>> 	        void (*otg_work)(struct work_struct *work);
>> 	};
>>
>> The dual-role state machine is built-into the OTG core so nothing
>> special needs to be provided if only dual-role functionality is desired.
>> The low level OTG controller driver ops are povided via
>> 'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.
>>
>> After registration, the OTG core waits for host, gadget controller
>> and the gadget function driver to be registered. Once all resources are
>> available it instantiates the Finite State Machine (FSM).
>> The host/gadget controllers are started/stopped according to the FSM.
>>
>> - Host and gadget controllers that are a part of OTG/dual-role port must
>> use the OTG core provided APIs to add/remove the host/gadget.
>> i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
>> gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
>> This ensures that the host and gadget controllers are not started till
>> the state machine is ready and the right bus conditions are met.
>> It also allows the host and gadget controllers to provide the OTG
>> controller device to link them together. For Device tree boots
>> the related OTG controller is automatically picked up via the
>> 'otg-controller' property in the Host/Gadget controller nodes.
>>
>> 	int usb_otg_add_hcd(struct usb_hcd *hcd,
>> 			    unsigned int irqnum, unsigned long irqflags,
>> 			    struct device *otg_dev);
>> 	void usb_otg_remove_hcd(struct usb_hcd *hcd);
>>
>> 	int usb_otg_add_gadget_udc(struct device *parent,
>> 				   struct usb_gadget *gadget,
>> 				   struct device *otg_dev);
>> 	usb_del_gadget_udc() must be used for removal.
>>
>>
>> - During the lifetime of the FSM, the OTG controller driver can provide
>> inputs event changes using usb_otg_sync_inputs(). The OTG core will
>> then schedule the FSM work function (or internal dual-role state machine)
>> to update the FSM state. The FSM then calls the OTG controller
>> operations (fsm_ops) as necessary.
>> 	void usb_otg_sync_inputs(struct usb_otg *otg);
>>
>> - The following 2 functions are provided as helpers for use by the
>> OTG controller driver to start/stop the host/gadget controllers.
>> 	int usb_otg_start_host(struct usb_otg *otg, int on);
>> 	int usb_otg_start_gadget(struct usb_otg *otg, int on);
>>
>> - The following function is provided for use by the USB host stack
>> to sync OTG related events to the OTG state machine.
>> e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
>> 	int usb_otg_kick_fsm(struct device *otg_device);
>>
>> - The following function is provided for use by the USB gadget stack
>> to notify OTG/DRD about gadget function driver being ready/not-ready
>> 	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
>>
>> Changelog:
>> ---------
>> v10:
>> - added missing mutex_unlock in failure path in usb_otg_unregister()
>> - removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
>> - comment fixes: urb->URB.
>> - fix commit log: say dev_vdbg() instead of dev_dbg().
>> - Update comments so that HCD means Host Controller Driver.
>> - rebased on Felipe's balbi/usb.git /testing/next
>> - include <linux/usb/of.h> in usb-otg.c
>> - in usb_otg_start_host() check if hcd_ops->add() failed and return
>> error code if it did.
>> - in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
>> error code if it did.
>> - follow kernel-doc style in usb-otg.c
>>
>> v9:
>> - In the DT bindings, clearly indicate which properties are for OTG controller
>> and which ones are for host/device controllers
>> - Removed host/gadget wait list from otg core. Use defer probing if host/gadget
>> registers before dual-role/otg controller.
>> - move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
>> to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
>> an additional mechanism to know when the gadget function driver registers.
>> So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
>> ready/not-ready function driver.
>> - update otg->caps based on capabilities provided by the controller and the
>> device tree overrides.
>> - in usb_drd_work() we must keep calling the drd_statemachine() as long as
>> there is a state change.
>> - updated kconfig so that usbotg can be a module when both host and gadget
>> are modules.
>> - rebased on v4.7-rc1
>>
>> v8:
>> - split out start/stop gadget and connect/disconnect operations.
>> - make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
>> - use create_freezable_workqueue() for OTG work as per Peter's suggestion.
>> - remove usb-otg.h as we're not initializing any OTG timers.
>> - don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)
>>
>> v7:
>> - added dual-role support for host controllers requiring a companion
>> controller. e.g. EHCI + OHCI.
>> - added of_usb_get_otg() to get the OTG controller device
>> from the USB controller's device node.
>> - addressed review comments.
>>
>> v6:
>> - added otg specific APIs for host/gadget registration. behaviour of
>> original host/gadget API remains unchanged. Platform devices can now
>> pass the otg device explicitly while registering host/gadget.
>> - moved hcd specific operations from struct otg_fsm to struct hcd_ops.
>> - made struct usb_otg mandatory for all otg related APIs.
>> - allow otg controller to provide it's own otg_work function so that
>> it can implement it's own state machine.
>> - removed otg fsm and timers from usb-otg.c. Only dual-role state machine
>> is implemented.
>> - vbus is controlled in the dual-role state machine.
>> - PM runtime is used around drd_statemachine().
>> - added otg_dev to xhci platform data to allow platform code to specify
>> the otg controller tied to the xhci host controller.
>>
>> v5: Internal version. Not sent to mailing list
>>
>> 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.
>>
>> --
>> cheers,
>> -roger
>>
>> Roger Quadros (13):
>>   usb: hcd: Initialize hcd->flags to 0
>>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>>   usb: hcd.h: Add OTG to HCD interface
>>   usb: otg-fsm: use usb_otg wherever possible
>>   usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
>>   usb: gadget.h: Add OTG to gadget interface
>>   usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
>>   usb: otg: add OTG/dual-role core
>>   usb: of: add an API to get OTG device from USB controller node
>>   usb: otg: use dev_vdbg() instead of VDBG()
>>   usb: hcd: Adapt to OTG core
>>   usb: gadget: udc: adapt to OTG core
>>   usb: host: xhci-plat: Add otg device to platform data
>>
>> Yoshihiro Shimoda (1):
>>   usb: otg: add hcd companion support
>>
>>  Documentation/devicetree/bindings/usb/generic.txt |   6 +
>>  Documentation/usb/chipidea.txt                    |   2 +-
>>  drivers/usb/Kconfig                               |  18 +
>>  drivers/usb/Makefile                              |   1 +
>>  drivers/usb/chipidea/Makefile                     |   2 +-
>>  drivers/usb/chipidea/ci.h                         |   3 +-
>>  drivers/usb/chipidea/core.c                       |  14 +-
>>  drivers/usb/chipidea/debug.c                      |   2 +-
>>  drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
>>  drivers/usb/chipidea/otg_fsm.h                    |   2 +-
>>  drivers/usb/chipidea/udc.c                        |  17 +-
>>  drivers/usb/common/Makefile                       |   5 +-
>>  drivers/usb/common/common.c                       |  27 +
>>  drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
>>  drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
>>  drivers/usb/core/Kconfig                          |  22 -
>>  drivers/usb/core/hcd.c                            |  56 ++
>>  drivers/usb/gadget/Kconfig                        |   1 +
>>  drivers/usb/gadget/udc/core.c                     | 202 ++++-
>>  drivers/usb/host/xhci-plat.c                      |  35 +-
>>  drivers/usb/phy/Kconfig                           |   2 +-
>>  drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
>>  drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
>>  include/linux/usb/gadget.h                        |  22 +
>>  include/linux/usb/hcd.h                           |  29 +
>>  include/linux/usb/of.h                            |   9 +
>>  include/linux/usb/otg-fsm.h                       | 154 +---
>>  include/linux/usb/otg.h                           | 290 ++++++-
>>  include/linux/usb/xhci_pdriver.h                  |   3 +
>>  29 files changed, 1918 insertions(+), 462 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-14  8:12     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:12 UTC (permalink / raw)
  To: Peter Chen, Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

+Alan. (Sorry Alan, I forgot to add copy you in this series).

Hi,

On 14/06/16 05:17, Peter Chen wrote:
> On Fri, Jun 10, 2016 at 04:07:09PM +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 TI platform related patches will be sent separately.
>>
>> Series is based on v4.7-rc1 + balbi/usb.git testing/next
>> commit 4a2786c10462df650965785462ca82c185164d98.
>>
> 
> Roger, I have acked for all your patches. You can send v11 for all
> patches. When you get Felipe's ack for gadget part, Alan's ack
> for hcd part, and your dwc3 and platform related patches ack,
> you can let Felipe help to queue this patch set since some of
> the code based on his tree. Thank you for your hard work for it.

Thanks Peter,

I'll send v11, with your Acks.

cheers,
-roger

> 
> Peter
> 
>> Why?:
>> ----
>>
>> Currently there is no central location where OTG/dual-role functionality is
>> implemented in the Linux USB stack and every USB controller driver is
>> doing their own thing for OTG/dual-role. We can benefit from code-reuse
>> and simplicity by adding the OTG/dual-role core driver.
>>
>> 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 controllers in dual-role mode. i.e. to stop and start them
>> from a central location. This central location should be the
>> USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.
>>
>> What?:
>> -----
>>
>> The OTG/dual-role core consists of a set of APIs that allow
>> registration of OTG controller device and OTG capable host and gadget
>> controllers.
>>
>> - The OTG controller driver can provide the OTG capabilities and the
>> Finite State Machine work function via 'struct usb_otg_config'
>> at the time of registration i.e. usb_otg_register();
>>
>> 	struct usb_otg *usb_otg_register(struct device *dev,
>>         	                         struct usb_otg_config *config);
>> 	int usb_otg_unregister(struct device *dev);
>> 	/**
>> 	 * struct usb_otg_config - otg controller configuration
>> 	 * @caps: otg capabilities of the controller
>> 	 * @ops: otg fsm operations
>> 	 * @otg_work: optional custom otg state machine work function
>> 	 */
>> 	struct usb_otg_config {
>> 	        struct usb_otg_caps *otg_caps;
>> 	        struct otg_fsm_ops *fsm_ops;
>> 	        void (*otg_work)(struct work_struct *work);
>> 	};
>>
>> The dual-role state machine is built-into the OTG core so nothing
>> special needs to be provided if only dual-role functionality is desired.
>> The low level OTG controller driver ops are povided via
>> 'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.
>>
>> After registration, the OTG core waits for host, gadget controller
>> and the gadget function driver to be registered. Once all resources are
>> available it instantiates the Finite State Machine (FSM).
>> The host/gadget controllers are started/stopped according to the FSM.
>>
>> - Host and gadget controllers that are a part of OTG/dual-role port must
>> use the OTG core provided APIs to add/remove the host/gadget.
>> i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
>> gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
>> This ensures that the host and gadget controllers are not started till
>> the state machine is ready and the right bus conditions are met.
>> It also allows the host and gadget controllers to provide the OTG
>> controller device to link them together. For Device tree boots
>> the related OTG controller is automatically picked up via the
>> 'otg-controller' property in the Host/Gadget controller nodes.
>>
>> 	int usb_otg_add_hcd(struct usb_hcd *hcd,
>> 			    unsigned int irqnum, unsigned long irqflags,
>> 			    struct device *otg_dev);
>> 	void usb_otg_remove_hcd(struct usb_hcd *hcd);
>>
>> 	int usb_otg_add_gadget_udc(struct device *parent,
>> 				   struct usb_gadget *gadget,
>> 				   struct device *otg_dev);
>> 	usb_del_gadget_udc() must be used for removal.
>>
>>
>> - During the lifetime of the FSM, the OTG controller driver can provide
>> inputs event changes using usb_otg_sync_inputs(). The OTG core will
>> then schedule the FSM work function (or internal dual-role state machine)
>> to update the FSM state. The FSM then calls the OTG controller
>> operations (fsm_ops) as necessary.
>> 	void usb_otg_sync_inputs(struct usb_otg *otg);
>>
>> - The following 2 functions are provided as helpers for use by the
>> OTG controller driver to start/stop the host/gadget controllers.
>> 	int usb_otg_start_host(struct usb_otg *otg, int on);
>> 	int usb_otg_start_gadget(struct usb_otg *otg, int on);
>>
>> - The following function is provided for use by the USB host stack
>> to sync OTG related events to the OTG state machine.
>> e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
>> 	int usb_otg_kick_fsm(struct device *otg_device);
>>
>> - The following function is provided for use by the USB gadget stack
>> to notify OTG/DRD about gadget function driver being ready/not-ready
>> 	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
>>
>> Changelog:
>> ---------
>> v10:
>> - added missing mutex_unlock in failure path in usb_otg_unregister()
>> - removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
>> - comment fixes: urb->URB.
>> - fix commit log: say dev_vdbg() instead of dev_dbg().
>> - Update comments so that HCD means Host Controller Driver.
>> - rebased on Felipe's balbi/usb.git /testing/next
>> - include <linux/usb/of.h> in usb-otg.c
>> - in usb_otg_start_host() check if hcd_ops->add() failed and return
>> error code if it did.
>> - in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
>> error code if it did.
>> - follow kernel-doc style in usb-otg.c
>>
>> v9:
>> - In the DT bindings, clearly indicate which properties are for OTG controller
>> and which ones are for host/device controllers
>> - Removed host/gadget wait list from otg core. Use defer probing if host/gadget
>> registers before dual-role/otg controller.
>> - move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
>> to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
>> an additional mechanism to know when the gadget function driver registers.
>> So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
>> ready/not-ready function driver.
>> - update otg->caps based on capabilities provided by the controller and the
>> device tree overrides.
>> - in usb_drd_work() we must keep calling the drd_statemachine() as long as
>> there is a state change.
>> - updated kconfig so that usbotg can be a module when both host and gadget
>> are modules.
>> - rebased on v4.7-rc1
>>
>> v8:
>> - split out start/stop gadget and connect/disconnect operations.
>> - make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
>> - use create_freezable_workqueue() for OTG work as per Peter's suggestion.
>> - remove usb-otg.h as we're not initializing any OTG timers.
>> - don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)
>>
>> v7:
>> - added dual-role support for host controllers requiring a companion
>> controller. e.g. EHCI + OHCI.
>> - added of_usb_get_otg() to get the OTG controller device
>> from the USB controller's device node.
>> - addressed review comments.
>>
>> v6:
>> - added otg specific APIs for host/gadget registration. behaviour of
>> original host/gadget API remains unchanged. Platform devices can now
>> pass the otg device explicitly while registering host/gadget.
>> - moved hcd specific operations from struct otg_fsm to struct hcd_ops.
>> - made struct usb_otg mandatory for all otg related APIs.
>> - allow otg controller to provide it's own otg_work function so that
>> it can implement it's own state machine.
>> - removed otg fsm and timers from usb-otg.c. Only dual-role state machine
>> is implemented.
>> - vbus is controlled in the dual-role state machine.
>> - PM runtime is used around drd_statemachine().
>> - added otg_dev to xhci platform data to allow platform code to specify
>> the otg controller tied to the xhci host controller.
>>
>> v5: Internal version. Not sent to mailing list
>>
>> 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.
>>
>> --
>> cheers,
>> -roger
>>
>> Roger Quadros (13):
>>   usb: hcd: Initialize hcd->flags to 0
>>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>>   usb: hcd.h: Add OTG to HCD interface
>>   usb: otg-fsm: use usb_otg wherever possible
>>   usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
>>   usb: gadget.h: Add OTG to gadget interface
>>   usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
>>   usb: otg: add OTG/dual-role core
>>   usb: of: add an API to get OTG device from USB controller node
>>   usb: otg: use dev_vdbg() instead of VDBG()
>>   usb: hcd: Adapt to OTG core
>>   usb: gadget: udc: adapt to OTG core
>>   usb: host: xhci-plat: Add otg device to platform data
>>
>> Yoshihiro Shimoda (1):
>>   usb: otg: add hcd companion support
>>
>>  Documentation/devicetree/bindings/usb/generic.txt |   6 +
>>  Documentation/usb/chipidea.txt                    |   2 +-
>>  drivers/usb/Kconfig                               |  18 +
>>  drivers/usb/Makefile                              |   1 +
>>  drivers/usb/chipidea/Makefile                     |   2 +-
>>  drivers/usb/chipidea/ci.h                         |   3 +-
>>  drivers/usb/chipidea/core.c                       |  14 +-
>>  drivers/usb/chipidea/debug.c                      |   2 +-
>>  drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
>>  drivers/usb/chipidea/otg_fsm.h                    |   2 +-
>>  drivers/usb/chipidea/udc.c                        |  17 +-
>>  drivers/usb/common/Makefile                       |   5 +-
>>  drivers/usb/common/common.c                       |  27 +
>>  drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
>>  drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
>>  drivers/usb/core/Kconfig                          |  22 -
>>  drivers/usb/core/hcd.c                            |  56 ++
>>  drivers/usb/gadget/Kconfig                        |   1 +
>>  drivers/usb/gadget/udc/core.c                     | 202 ++++-
>>  drivers/usb/host/xhci-plat.c                      |  35 +-
>>  drivers/usb/phy/Kconfig                           |   2 +-
>>  drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
>>  drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
>>  include/linux/usb/gadget.h                        |  22 +
>>  include/linux/usb/hcd.h                           |  29 +
>>  include/linux/usb/of.h                            |   9 +
>>  include/linux/usb/otg-fsm.h                       | 154 +---
>>  include/linux/usb/otg.h                           | 290 ++++++-
>>  include/linux/usb/xhci_pdriver.h                  |   3 +
>>  29 files changed, 1918 insertions(+), 462 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0
@ 2016-06-14  8:16     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:16 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

+Alan,

On 10/06/16 16:07, Roger Quadros wrote:
> When using the OTG/DRD library we can call hcd_add/remove
> consecutively without calling usb_put_hcd/usb_create_hcd in between
> so hcd->flags can be stale.
> 
> If the HC dies due to whatever reason then without this
> patch we get the below error on next hcd_add.
> 
> [   91.494257] xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
> [   91.502068] hub 3-0:1.0: state 0 ports 1 chg 0000 evt 0000
> [   91.510240] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
> [   91.516940] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
> [   91.529745] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
> [   91.540637] usb usb4: New USB device found, idVendor=1d6b, idProduct=0003
> [   91.757865] irq 254: nobody cared (try booting with the "irqpoll" option)
> [   91.757880] CPU: 0 PID: 68 Comm: kworker/u2:2 Not tainted 4.1.4-00828-g1f0ed8c-dirty #44
> [   91.757885] Hardware name: Generic AM43 (Flattened Device Tree)
> [   91.757914] Workqueue: usb_otg usb_otg_work
> [   91.757921] Backtrace:
> [   91.757954] [<c0012af0>] (dump_backtrace) from [<c0012c8c>] (show_stack+0x18/0x1c)
> [   91.757972]  r6:c089d4a4 r5:ffffffff r4:00000000 r3:ee440000
> [   91.757991] [<c0012c74>] (show_stack) from [<c05f7c14>] (dump_stack+0x84/0xd0)
> [   91.758008] [<c05f7b90>] (dump_stack) from [<c0084b30>] (__report_bad_irq+0x28/0xc8)
> [   91.758024]  r7:00000000 r6:000000fe r5:00000000 r4:ee514c40
> [   91.758037] [<c0084b08>] (__report_bad_irq) from [<c00850b0>] (note_interrupt+0x24c/0x2ac)
> [   91.758052]  r6:000000fe r5:00000000 r4:ee514c40 r3:00000000
> [   91.758065] [<c0084e64>] (note_interrupt) from [<c00828fc>] (handle_irq_event_percpu+0xb0/0x158)
> [   91.758085]  r10:ee514c40 r9:c08ce49a r8:000000fe r7:00000000 r6:00000000 r5:00000000
> [   91.758094]  r4:00000000 r3:00000000
> [   91.758105] [<c008284c>] (handle_irq_event_percpu) from [<c00829e8>] (handle_irq_event+0x44/0x64)
> [   91.758126]  r10:00000001 r9:ee441ab0 r8:ee441bb8 r7:c0858b4c r6:ed174280 r5:ee514ca0
> [   91.758132]  r4:ee514c40
> [   91.758144] [<c00829a4>] (handle_irq_event) from [<c0085970>] (handle_fasteoi_irq+0x100/0x1bc)
> [   91.758159]  r6:c085dba0 r5:ee514ca0 r4:ee514c40 r3:00000000
> [   91.758171] [<c0085870>] (handle_fasteoi_irq) from [<c0082058>] (generic_handle_irq+0x28/0x38)
> [   91.758186]  r7:c0853d40 r6:c0858b4c r5:000000fe r4:000000fe
> [   91.758197] [<c0082030>] (generic_handle_irq) from [<c00821c0>] (__handle_domain_irq+0x98/0x12c)
> [   91.758207]  r4:c0853d40 r3:00000100
> [   91.758219] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
> [   91.758239]  r10:00000001 r9:ee441bb8 r8:fa240100 r7:c0858d70 r6:ee441ab0 r5:000000b8
> [   91.758245]  r4:fa24010c
> [   91.758264] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
> [   91.758271] Exception stack(0xee441ab0 to 0xee441af8)
> [   91.758280] 1aa0:                                     00000000 c08d2980 ee441ac0 00000000
> [   91.758292] 1ac0: 00000008 00000089 c0858b4c c0858080 00000000 ee441bb8 00000001 ee441b3c
> [   91.758301] 1ae0: 00000101 ee441af8 c02fc418 c0046a1c 20000113 ffffffff
> [   91.758321]  r8:00000000 r7:ee441ae4 r6:ffffffff r5:20000113 r4:c0046a1c r3:c02fc418
> [   91.758347] [<c00469a0>] (__do_softirq) from [<c0046eac>] (irq_exit+0xb8/0x104)
> [   91.758367]  r10:00000001 r9:ee441bb8 r8:00000000 r7:c0853d40 r6:c0858b4c r5:00000089
> [   91.758373]  r4:00000000
> [   91.758386] [<c0046df4>] (irq_exit) from [<c00821c8>] (__handle_domain_irq+0xa0/0x12c)
> [   91.758395]  r4:00000000 r3:00000100
> [   91.758406] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
> [   91.758426]  r10:c08e3510 r9:20000013 r8:fa240100 r7:c0858d70 r6:ee441bb8 r5:00000039
> [   91.758433]  r4:fa24010c
> [   91.758445] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
> [   91.758450] Exception stack(0xee441bb8 to 0xee441c00)
> [   91.758457] 1ba0:                                                       00000000 00000001
> [   91.758468] 1bc0: 00000000 ee440000 c08e2524 0000004d 00000274 00000000 00000000 20000013
> [   91.758479] 1be0: c08e3510 ee441c4c ee441b60 ee441c00 c03acfec c0080d4c 60000013 ffffffff
> [   91.758499]  r8:00000000 r7:ee441bec r6:ffffffff r5:60000013 r4:c0080d4c r3:c03acfec
> [   91.758524] [<c0080950>] (console_unlock) from [<c0081670>] (vprintk_emit+0x20c/0x500)
> [   91.758544]  r10:ee441cc0 r9:c08d3550 r8:c08e3ea0 r7:00000000 r6:00000001 r5:0000003d
> [   91.758551]  r4:c08d3550
> [   91.758573] [<c0081464>] (vprintk_emit) from [<c03f6f70>] (dev_vprintk_emit+0x104/0x1ac)
> [   91.758593]  r10:ee441d8c r9:0000000e r8:c07951e0 r7:00000006 r6:ee441cc0 r5:0000000d
> [   91.758599]  r4:ee731068
> [   91.758612] [<c03f6e6c>] (dev_vprintk_emit) from [<c03f7040>] (dev_printk_emit+0x28/0x30)
> [   91.758632]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:ed429000 r6:00000006 r5:ee441dc0
> [   91.758638]  r4:ee731068
> [   91.758651] [<c03f701c>] (dev_printk_emit) from [<c03f7098>] (__dev_printk+0x50/0x70)
> [   91.758660]  r3:bf2268cc r2:c07951e0
> [   91.758673] [<c03f7048>] (__dev_printk) from [<c03f70f4>] (_dev_info+0x3c/0x48)
> [   91.758686]  r6:00000000 r5:ee731068 r4:ee731000
> [   91.758790] [<c03f70bc>] (_dev_info) from [<bf20ec3c>] (usb_new_device+0x11c/0x518 [usbcore])
> [   91.758804]  r3:00000003 r2:00001d6b r1:bf225bc4
> [   91.758881] [<bf20eb20>] (usb_new_device [usbcore]) from [<bf213560>] (usb_otg_add_hcd+0x514/0x7f8 [usbcore])
> [   91.758903]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:000000fe r6:ed4290c8 r5:00000000
> [   91.758909]  r4:ed429000
> [   91.758957] [<bf21304c>] (usb_otg_add_hcd [usbcore]) from [<c047a238>] (usb_otg_start_host+0xb8/0xf8)
> [   91.758978]  r10:00000000 r9:00000002 r8:00000000 r7:ee02b000 r6:ee452808 r5:ee452808
> [   91.758985]  r4:ee452808
> [   91.758997] [<c047a180>] (usb_otg_start_host) from [<c047a020>] (drd_set_protocol+0xac/0xd8)
> [   91.759007]  r4:00000001 r3:c047a180
> [   91.759018] [<c0479f74>] (drd_set_protocol) from [<c047a2ec>] (drd_set_state+0x74/0x98)
> [   91.759027]  r5:ee452808 r4:00000009
> [   91.759039] [<c047a278>] (drd_set_state) from [<c047a3dc>] (usb_otg_work+0xcc/0x154)
> [   91.759054]  r6:ee452808 r5:ee4528b8 r4:ee452968 r3:00000000
> [   91.759072] [<c047a310>] (usb_otg_work) from [<c005754c>] (process_one_work+0x128/0x340)
> [   91.759087]  r6:ee02ac00 r5:ee452968 r4:ee42b900 r3:c047a310
> [   91.759100] [<c0057424>] (process_one_work) from [<c00578f8>] (worker_thread+0x158/0x49c)
> [   91.759120]  r10:ee42b900 r9:00000002 r8:ee02ac00 r7:00000088 r6:ee42b918 r5:ee02ac00
> [   91.759127]  r4:ee02ac14
> [   91.759145] [<c00577a0>] (worker_thread) from [<c005cc40>] (kthread+0xdc/0xf8)
> [   91.759165]  r10:00000000 r9:00000000 r8:00000000 r7:c00577a0 r6:ee42b900 r5:ee429940
> [   91.759174]  r4:00000000 r3:00000000
> [   91.759190] [<c005cb64>] (kthread) from [<c000fc08>] (ret_from_fork+0x14/0x2c)
> [   91.759206]  r7:00000000 r6:00000000 r5:c005cb64 r4:ee429940
> [   91.759209] handlers:
> [   91.759255] [<bf211b5c>] usb_hcd_irq [usbcore]
> [   91.759260] Disabling IRQ #254
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Reviewed-by: Peter Chen <peter.chen@nxp.com>
> ---
>  drivers/usb/core/hcd.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index 34b837a..ae6c76d 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -3021,6 +3021,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  	}
>  
>  	usb_put_invalidate_rhdev(hcd);
> +	hcd->flags = 0;
>  }
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
> 

--
cheers,
-roger

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

* Re: [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0
@ 2016-06-14  8:16     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:16 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

+Alan,

On 10/06/16 16:07, Roger Quadros wrote:
> When using the OTG/DRD library we can call hcd_add/remove
> consecutively without calling usb_put_hcd/usb_create_hcd in between
> so hcd->flags can be stale.
> 
> If the HC dies due to whatever reason then without this
> patch we get the below error on next hcd_add.
> 
> [   91.494257] xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
> [   91.502068] hub 3-0:1.0: state 0 ports 1 chg 0000 evt 0000
> [   91.510240] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
> [   91.516940] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
> [   91.529745] usb usb4: We don't know the algorithms for LPM for this host, disabling LPM.
> [   91.540637] usb usb4: New USB device found, idVendor=1d6b, idProduct=0003
> [   91.757865] irq 254: nobody cared (try booting with the "irqpoll" option)
> [   91.757880] CPU: 0 PID: 68 Comm: kworker/u2:2 Not tainted 4.1.4-00828-g1f0ed8c-dirty #44
> [   91.757885] Hardware name: Generic AM43 (Flattened Device Tree)
> [   91.757914] Workqueue: usb_otg usb_otg_work
> [   91.757921] Backtrace:
> [   91.757954] [<c0012af0>] (dump_backtrace) from [<c0012c8c>] (show_stack+0x18/0x1c)
> [   91.757972]  r6:c089d4a4 r5:ffffffff r4:00000000 r3:ee440000
> [   91.757991] [<c0012c74>] (show_stack) from [<c05f7c14>] (dump_stack+0x84/0xd0)
> [   91.758008] [<c05f7b90>] (dump_stack) from [<c0084b30>] (__report_bad_irq+0x28/0xc8)
> [   91.758024]  r7:00000000 r6:000000fe r5:00000000 r4:ee514c40
> [   91.758037] [<c0084b08>] (__report_bad_irq) from [<c00850b0>] (note_interrupt+0x24c/0x2ac)
> [   91.758052]  r6:000000fe r5:00000000 r4:ee514c40 r3:00000000
> [   91.758065] [<c0084e64>] (note_interrupt) from [<c00828fc>] (handle_irq_event_percpu+0xb0/0x158)
> [   91.758085]  r10:ee514c40 r9:c08ce49a r8:000000fe r7:00000000 r6:00000000 r5:00000000
> [   91.758094]  r4:00000000 r3:00000000
> [   91.758105] [<c008284c>] (handle_irq_event_percpu) from [<c00829e8>] (handle_irq_event+0x44/0x64)
> [   91.758126]  r10:00000001 r9:ee441ab0 r8:ee441bb8 r7:c0858b4c r6:ed174280 r5:ee514ca0
> [   91.758132]  r4:ee514c40
> [   91.758144] [<c00829a4>] (handle_irq_event) from [<c0085970>] (handle_fasteoi_irq+0x100/0x1bc)
> [   91.758159]  r6:c085dba0 r5:ee514ca0 r4:ee514c40 r3:00000000
> [   91.758171] [<c0085870>] (handle_fasteoi_irq) from [<c0082058>] (generic_handle_irq+0x28/0x38)
> [   91.758186]  r7:c0853d40 r6:c0858b4c r5:000000fe r4:000000fe
> [   91.758197] [<c0082030>] (generic_handle_irq) from [<c00821c0>] (__handle_domain_irq+0x98/0x12c)
> [   91.758207]  r4:c0853d40 r3:00000100
> [   91.758219] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
> [   91.758239]  r10:00000001 r9:ee441bb8 r8:fa240100 r7:c0858d70 r6:ee441ab0 r5:000000b8
> [   91.758245]  r4:fa24010c
> [   91.758264] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
> [   91.758271] Exception stack(0xee441ab0 to 0xee441af8)
> [   91.758280] 1aa0:                                     00000000 c08d2980 ee441ac0 00000000
> [   91.758292] 1ac0: 00000008 00000089 c0858b4c c0858080 00000000 ee441bb8 00000001 ee441b3c
> [   91.758301] 1ae0: 00000101 ee441af8 c02fc418 c0046a1c 20000113 ffffffff
> [   91.758321]  r8:00000000 r7:ee441ae4 r6:ffffffff r5:20000113 r4:c0046a1c r3:c02fc418
> [   91.758347] [<c00469a0>] (__do_softirq) from [<c0046eac>] (irq_exit+0xb8/0x104)
> [   91.758367]  r10:00000001 r9:ee441bb8 r8:00000000 r7:c0853d40 r6:c0858b4c r5:00000089
> [   91.758373]  r4:00000000
> [   91.758386] [<c0046df4>] (irq_exit) from [<c00821c8>] (__handle_domain_irq+0xa0/0x12c)
> [   91.758395]  r4:00000000 r3:00000100
> [   91.758406] [<c0082128>] (__handle_domain_irq) from [<c00094e0>] (gic_handle_irq+0x28/0x68)
> [   91.758426]  r10:c08e3510 r9:20000013 r8:fa240100 r7:c0858d70 r6:ee441bb8 r5:00000039
> [   91.758433]  r4:fa24010c
> [   91.758445] [<c00094b8>] (gic_handle_irq) from [<c05fd540>] (__irq_svc+0x40/0x74)
> [   91.758450] Exception stack(0xee441bb8 to 0xee441c00)
> [   91.758457] 1ba0:                                                       00000000 00000001
> [   91.758468] 1bc0: 00000000 ee440000 c08e2524 0000004d 00000274 00000000 00000000 20000013
> [   91.758479] 1be0: c08e3510 ee441c4c ee441b60 ee441c00 c03acfec c0080d4c 60000013 ffffffff
> [   91.758499]  r8:00000000 r7:ee441bec r6:ffffffff r5:60000013 r4:c0080d4c r3:c03acfec
> [   91.758524] [<c0080950>] (console_unlock) from [<c0081670>] (vprintk_emit+0x20c/0x500)
> [   91.758544]  r10:ee441cc0 r9:c08d3550 r8:c08e3ea0 r7:00000000 r6:00000001 r5:0000003d
> [   91.758551]  r4:c08d3550
> [   91.758573] [<c0081464>] (vprintk_emit) from [<c03f6f70>] (dev_vprintk_emit+0x104/0x1ac)
> [   91.758593]  r10:ee441d8c r9:0000000e r8:c07951e0 r7:00000006 r6:ee441cc0 r5:0000000d
> [   91.758599]  r4:ee731068
> [   91.758612] [<c03f6e6c>] (dev_vprintk_emit) from [<c03f7040>] (dev_printk_emit+0x28/0x30)
> [   91.758632]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:ed429000 r6:00000006 r5:ee441dc0
> [   91.758638]  r4:ee731068
> [   91.758651] [<c03f701c>] (dev_printk_emit) from [<c03f7098>] (__dev_printk+0x50/0x70)
> [   91.758660]  r3:bf2268cc r2:c07951e0
> [   91.758673] [<c03f7048>] (__dev_printk) from [<c03f70f4>] (_dev_info+0x3c/0x48)
> [   91.758686]  r6:00000000 r5:ee731068 r4:ee731000
> [   91.758790] [<c03f70bc>] (_dev_info) from [<bf20ec3c>] (usb_new_device+0x11c/0x518 [usbcore])
> [   91.758804]  r3:00000003 r2:00001d6b r1:bf225bc4
> [   91.758881] [<bf20eb20>] (usb_new_device [usbcore]) from [<bf213560>] (usb_otg_add_hcd+0x514/0x7f8 [usbcore])
> [   91.758903]  r10:00000001 r9:ee5f8410 r8:ee731000 r7:000000fe r6:ed4290c8 r5:00000000
> [   91.758909]  r4:ed429000
> [   91.758957] [<bf21304c>] (usb_otg_add_hcd [usbcore]) from [<c047a238>] (usb_otg_start_host+0xb8/0xf8)
> [   91.758978]  r10:00000000 r9:00000002 r8:00000000 r7:ee02b000 r6:ee452808 r5:ee452808
> [   91.758985]  r4:ee452808
> [   91.758997] [<c047a180>] (usb_otg_start_host) from [<c047a020>] (drd_set_protocol+0xac/0xd8)
> [   91.759007]  r4:00000001 r3:c047a180
> [   91.759018] [<c0479f74>] (drd_set_protocol) from [<c047a2ec>] (drd_set_state+0x74/0x98)
> [   91.759027]  r5:ee452808 r4:00000009
> [   91.759039] [<c047a278>] (drd_set_state) from [<c047a3dc>] (usb_otg_work+0xcc/0x154)
> [   91.759054]  r6:ee452808 r5:ee4528b8 r4:ee452968 r3:00000000
> [   91.759072] [<c047a310>] (usb_otg_work) from [<c005754c>] (process_one_work+0x128/0x340)
> [   91.759087]  r6:ee02ac00 r5:ee452968 r4:ee42b900 r3:c047a310
> [   91.759100] [<c0057424>] (process_one_work) from [<c00578f8>] (worker_thread+0x158/0x49c)
> [   91.759120]  r10:ee42b900 r9:00000002 r8:ee02ac00 r7:00000088 r6:ee42b918 r5:ee02ac00
> [   91.759127]  r4:ee02ac14
> [   91.759145] [<c00577a0>] (worker_thread) from [<c005cc40>] (kthread+0xdc/0xf8)
> [   91.759165]  r10:00000000 r9:00000000 r8:00000000 r7:c00577a0 r6:ee42b900 r5:ee429940
> [   91.759174]  r4:00000000 r3:00000000
> [   91.759190] [<c005cb64>] (kthread) from [<c000fc08>] (ret_from_fork+0x14/0x2c)
> [   91.759206]  r7:00000000 r6:00000000 r5:c005cb64 r4:ee429940
> [   91.759209] handlers:
> [   91.759255] [<bf211b5c>] usb_hcd_irq [usbcore]
> [   91.759260] Disabling IRQ #254
> 
> Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
> Reviewed-by: Peter Chen <peter.chen-3arQi8VN3Tc@public.gmane.org>
> ---
>  drivers/usb/core/hcd.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index 34b837a..ae6c76d 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -3021,6 +3021,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  	}
>  
>  	usb_put_invalidate_rhdev(hcd);
> +	hcd->flags = 0;
>  }
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
> 

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

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-14  8:17     ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:17 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

+Alan

On 10/06/16 16:07, Roger Quadros wrote:
> The OTG core will use struct otg_hcd_ops to interface
> with the HCD (Host Controller Driver).
> 
> The main purpose of this interface is to avoid directly
> calling HCD APIs 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>
> Acked-by: Peter Chen <peter.chen@nxp.com>
> ---
>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 66fc137..7729c1f 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -400,6 +400,30 @@ struct hc_driver {
>  
>  };
>  
> +/**
> + * struct otg_hcd_ops - Interface between OTG core and HCD
> + *
> + * Provided by the HCD core to allow the OTG core to interface with the HCD
> + *
> + * @add: function to add the HCD
> + * @remove: function to remove the HCD
> + * @usb_bus_start_enum: function to immediately start bus enumeration
> + * @usb_control_msg: function to build and send a control URB
> + * @usb_hub_find_child: function to get pointer to the child device
> + */
> +struct otg_hcd_ops {
> +	int (*add)(struct usb_hcd *hcd,
> +		   unsigned int irqnum, unsigned long irqflags);
> +	void (*remove)(struct usb_hcd *hcd);
> +	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int port_num);
> +	int (*usb_control_msg)(struct usb_device *dev, unsigned int pipe,
> +			       __u8 request, __u8 requesttype, __u16 value,
> +			       __u16 index, void *data, __u16 size,
> +			       int timeout);
> +	struct usb_device * (*usb_hub_find_child)(struct usb_device *hdev,
> +						  int port1);
> +};
> +
>  static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
>  {
>  	return hcd->driver->flags & HCD_BH;
> 

--
cheers,
-roger

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
@ 2016-06-14  8:17     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:17 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

+Alan

On 10/06/16 16:07, Roger Quadros wrote:
> The OTG core will use struct otg_hcd_ops to interface
> with the HCD (Host Controller Driver).
> 
> The main purpose of this interface is to avoid directly
> calling HCD APIs 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>
> Acked-by: Peter Chen <peter.chen@nxp.com>
> ---
>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 66fc137..7729c1f 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -400,6 +400,30 @@ struct hc_driver {
>  
>  };
>  
> +/**
> + * struct otg_hcd_ops - Interface between OTG core and HCD
> + *
> + * Provided by the HCD core to allow the OTG core to interface with the HCD
> + *
> + * @add: function to add the HCD
> + * @remove: function to remove the HCD
> + * @usb_bus_start_enum: function to immediately start bus enumeration
> + * @usb_control_msg: function to build and send a control URB
> + * @usb_hub_find_child: function to get pointer to the child device
> + */
> +struct otg_hcd_ops {
> +	int (*add)(struct usb_hcd *hcd,
> +		   unsigned int irqnum, unsigned long irqflags);
> +	void (*remove)(struct usb_hcd *hcd);
> +	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int port_num);
> +	int (*usb_control_msg)(struct usb_device *dev, unsigned int pipe,
> +			       __u8 request, __u8 requesttype, __u16 value,
> +			       __u16 index, void *data, __u16 size,
> +			       int timeout);
> +	struct usb_device * (*usb_hub_find_child)(struct usb_device *hdev,
> +						  int port1);
> +};
> +
>  static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
>  {
>  	return hcd->driver->flags & HCD_BH;
> 

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

* Re: [PATCH v10 12/14] usb: hcd: Adapt to OTG core
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-14  8:17     ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:17 UTC (permalink / raw)
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree, Alan Stern

+Alan

On 10/06/16 16:07, Roger Quadros wrote:
> Introduce usb_otg_add/remove_hcd() for use by host
> controllers that are part of OTG/dual-role port.
> 
> Non device tree platforms can use the otg_dev argument
> to specify the OTG controller device. If otg_dev is NULL
> then the device tree node's otg-controller property is used to
> get the otg_dev device.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Peter Chen <peter.chen@nxp.com>
> ---
>  drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/hcd.h |  4 ++++
>  2 files changed, 59 insertions(+)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index ae6c76d..c6f4155 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -46,6 +46,11 @@
>  #include <linux/usb.h>
>  #include <linux/usb/hcd.h>
>  #include <linux/usb/phy.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/of.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
>  
>  #include "usb.h"
>  
> @@ -3025,6 +3030,56 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  }
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
> +static struct otg_hcd_ops otg_hcd_intf = {
> +	.add = usb_add_hcd,
> +	.remove = usb_remove_hcd,
> +	.usb_bus_start_enum = usb_bus_start_enum,
> +	.usb_control_msg = usb_control_msg,
> +	.usb_hub_find_child = usb_hub_find_child,
> +};
> +
> +/**
> + * usb_otg_add_hcd - Register the HCD with OTG core.
> + * @hcd: the usb_hcd structure to initialize
> + * @irqnum: Interrupt line to allocate
> + * @irqflags: Interrupt type flags
> + * @otg_dev: OTG controller device managing this HCD
> + *
> + * Registers the HCD with OTG core. OTG core will call usb_add_hcd()
> + * or usb_remove_hcd() as necessary.
> + * If otg_dev is NULL then device tree node is checked for OTG
> + * controller device via the otg-controller property.
> + */
> +int usb_otg_add_hcd(struct usb_hcd *hcd,
> +		    unsigned int irqnum, unsigned long irqflags,
> +		    struct device *otg_dev)
> +{
> +	struct device *dev = hcd->self.controller;
> +
> +	if (!otg_dev) {
> +		hcd->otg_dev = of_usb_get_otg(dev->of_node);
> +		if (!hcd->otg_dev)
> +			return -ENODEV;
> +	} else {
> +		hcd->otg_dev = otg_dev;
> +	}
> +
> +	return usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_add_hcd);
> +
> +/**
> + * usb_otg_remove_hcd - Unregister the HCD with OTG core.
> + * @hcd: the usb_hcd structure to remove
> + *
> + * Unregisters the HCD from the OTG core.
> + */
> +void usb_otg_remove_hcd(struct usb_hcd *hcd)
> +{
> +	usb_otg_unregister_hcd(hcd);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_remove_hcd);
> +
>  void
>  usb_hcd_platform_shutdown(struct platform_device *dev)
>  {
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 36bd54f..0c70282 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -473,6 +473,10 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
>  extern int usb_add_hcd(struct usb_hcd *hcd,
>  		unsigned int irqnum, unsigned long irqflags);
>  extern void usb_remove_hcd(struct usb_hcd *hcd);
> +extern int usb_otg_add_hcd(struct usb_hcd *hcd,
> +			   unsigned int irqnum, unsigned long irqflags,
> +			   struct device *otg_dev);
> +extern void usb_otg_remove_hcd(struct usb_hcd *hcd);
>  extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
>  
>  struct platform_device;
> 

--
cheers,
-roger

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

* Re: [PATCH v10 12/14] usb: hcd: Adapt to OTG core
@ 2016-06-14  8:17     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:17 UTC (permalink / raw)
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree, Alan Stern

+Alan

On 10/06/16 16:07, Roger Quadros wrote:
> Introduce usb_otg_add/remove_hcd() for use by host
> controllers that are part of OTG/dual-role port.
> 
> Non device tree platforms can use the otg_dev argument
> to specify the OTG controller device. If otg_dev is NULL
> then the device tree node's otg-controller property is used to
> get the otg_dev device.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Peter Chen <peter.chen@nxp.com>
> ---
>  drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/hcd.h |  4 ++++
>  2 files changed, 59 insertions(+)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index ae6c76d..c6f4155 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -46,6 +46,11 @@
>  #include <linux/usb.h>
>  #include <linux/usb/hcd.h>
>  #include <linux/usb/phy.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/of.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
>  
>  #include "usb.h"
>  
> @@ -3025,6 +3030,56 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  }
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
> +static struct otg_hcd_ops otg_hcd_intf = {
> +	.add = usb_add_hcd,
> +	.remove = usb_remove_hcd,
> +	.usb_bus_start_enum = usb_bus_start_enum,
> +	.usb_control_msg = usb_control_msg,
> +	.usb_hub_find_child = usb_hub_find_child,
> +};
> +
> +/**
> + * usb_otg_add_hcd - Register the HCD with OTG core.
> + * @hcd: the usb_hcd structure to initialize
> + * @irqnum: Interrupt line to allocate
> + * @irqflags: Interrupt type flags
> + * @otg_dev: OTG controller device managing this HCD
> + *
> + * Registers the HCD with OTG core. OTG core will call usb_add_hcd()
> + * or usb_remove_hcd() as necessary.
> + * If otg_dev is NULL then device tree node is checked for OTG
> + * controller device via the otg-controller property.
> + */
> +int usb_otg_add_hcd(struct usb_hcd *hcd,
> +		    unsigned int irqnum, unsigned long irqflags,
> +		    struct device *otg_dev)
> +{
> +	struct device *dev = hcd->self.controller;
> +
> +	if (!otg_dev) {
> +		hcd->otg_dev = of_usb_get_otg(dev->of_node);
> +		if (!hcd->otg_dev)
> +			return -ENODEV;
> +	} else {
> +		hcd->otg_dev = otg_dev;
> +	}
> +
> +	return usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_add_hcd);
> +
> +/**
> + * usb_otg_remove_hcd - Unregister the HCD with OTG core.
> + * @hcd: the usb_hcd structure to remove
> + *
> + * Unregisters the HCD from the OTG core.
> + */
> +void usb_otg_remove_hcd(struct usb_hcd *hcd)
> +{
> +	usb_otg_unregister_hcd(hcd);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_remove_hcd);
> +
>  void
>  usb_hcd_platform_shutdown(struct platform_device *dev)
>  {
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 36bd54f..0c70282 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -473,6 +473,10 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
>  extern int usb_add_hcd(struct usb_hcd *hcd,
>  		unsigned int irqnum, unsigned long irqflags);
>  extern void usb_remove_hcd(struct usb_hcd *hcd);
> +extern int usb_otg_add_hcd(struct usb_hcd *hcd,
> +			   unsigned int irqnum, unsigned long irqflags,
> +			   struct device *otg_dev);
> +extern void usb_otg_remove_hcd(struct usb_hcd *hcd);
>  extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
>  
>  struct platform_device;
> 

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

* Re: [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-14  8:18     ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:18 UTC (permalink / raw)
  To: mathias.nyman
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

Mathias,

On 10/06/16 16:07, Roger Quadros wrote:
> Host controllers that are part of an OTG/dual-role instance
> need to somehow pass the OTG controller device information
> to the HCD core.
> 
> We use platform data to pass the OTG controller device.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Reviewed-by: Peter Chen <peter.chen@nxp.com>
> ---
>  drivers/usb/host/xhci-plat.c     | 35 ++++++++++++++++++++++++++++-------
>  include/linux/usb/xhci_pdriver.h |  3 +++
>  2 files changed, 31 insertions(+), 7 deletions(-)

Any comments on this one?

> 
> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
> index 676ea45..24d030a 100644
> --- a/drivers/usb/host/xhci-plat.c
> +++ b/drivers/usb/host/xhci-plat.c
> @@ -239,11 +239,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
>  			goto put_usb3_hcd;
>  	}
>  
> -	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> +	if (pdata && pdata->otg_dev)
> +		ret = usb_otg_add_hcd(hcd, irq, IRQF_SHARED, pdata->otg_dev);
> +	else
> +		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> +
>  	if (ret)
>  		goto disable_usb_phy;
>  
> -	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> +	if (pdata && pdata->otg_dev)
> +		ret = usb_otg_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED,
> +				      pdata->otg_dev);
> +	else
> +		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> +
>  	if (ret)
>  		goto dealloc_usb2_hcd;
>  
> @@ -251,7 +260,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
>  
>  
>  dealloc_usb2_hcd:
> -	usb_remove_hcd(hcd);
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(hcd);
> +	else
> +		usb_remove_hcd(hcd);
>  
>  disable_usb_phy:
>  	usb_phy_shutdown(hcd->usb_phy);
> @@ -269,16 +281,25 @@ put_hcd:
>  	return ret;
>  }
>  
> -static int xhci_plat_remove(struct platform_device *dev)
> +static int xhci_plat_remove(struct platform_device *pdev)
>  {
> -	struct usb_hcd	*hcd = platform_get_drvdata(dev);
> +	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
>  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
>  	struct clk *clk = xhci->clk;
> +	struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
> +
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(xhci->shared_hcd);
> +	else
> +		usb_remove_hcd(xhci->shared_hcd);
>  
> -	usb_remove_hcd(xhci->shared_hcd);
>  	usb_phy_shutdown(hcd->usb_phy);
>  
> -	usb_remove_hcd(hcd);
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(hcd);
> +	else
> +		usb_remove_hcd(hcd);
> +
>  	usb_put_hcd(xhci->shared_hcd);
>  
>  	if (!IS_ERR(clk))
> diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
> index 376654b..5c68b83 100644
> --- a/include/linux/usb/xhci_pdriver.h
> +++ b/include/linux/usb/xhci_pdriver.h
> @@ -18,10 +18,13 @@
>   *
>   * @usb3_lpm_capable:	determines if this xhci platform supports USB3
>   *			LPM capability
> + * @otg_dev:		OTG controller device. Only requied if part of
> + *			OTG/dual-role.
>   *
>   */
>  struct usb_xhci_pdata {
>  	unsigned	usb3_lpm_capable:1;
> +	struct device	*otg_dev;
>  };
>  
>  #endif /* __USB_CORE_XHCI_PDRIVER_H */
> 

--
cheers,
-roger

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

* Re: [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data
@ 2016-06-14  8:18     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-14  8:18 UTC (permalink / raw)
  To: mathias.nyman
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

Mathias,

On 10/06/16 16:07, Roger Quadros wrote:
> Host controllers that are part of an OTG/dual-role instance
> need to somehow pass the OTG controller device information
> to the HCD core.
> 
> We use platform data to pass the OTG controller device.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Reviewed-by: Peter Chen <peter.chen@nxp.com>
> ---
>  drivers/usb/host/xhci-plat.c     | 35 ++++++++++++++++++++++++++++-------
>  include/linux/usb/xhci_pdriver.h |  3 +++
>  2 files changed, 31 insertions(+), 7 deletions(-)

Any comments on this one?

> 
> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
> index 676ea45..24d030a 100644
> --- a/drivers/usb/host/xhci-plat.c
> +++ b/drivers/usb/host/xhci-plat.c
> @@ -239,11 +239,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
>  			goto put_usb3_hcd;
>  	}
>  
> -	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> +	if (pdata && pdata->otg_dev)
> +		ret = usb_otg_add_hcd(hcd, irq, IRQF_SHARED, pdata->otg_dev);
> +	else
> +		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> +
>  	if (ret)
>  		goto disable_usb_phy;
>  
> -	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> +	if (pdata && pdata->otg_dev)
> +		ret = usb_otg_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED,
> +				      pdata->otg_dev);
> +	else
> +		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> +
>  	if (ret)
>  		goto dealloc_usb2_hcd;
>  
> @@ -251,7 +260,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
>  
>  
>  dealloc_usb2_hcd:
> -	usb_remove_hcd(hcd);
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(hcd);
> +	else
> +		usb_remove_hcd(hcd);
>  
>  disable_usb_phy:
>  	usb_phy_shutdown(hcd->usb_phy);
> @@ -269,16 +281,25 @@ put_hcd:
>  	return ret;
>  }
>  
> -static int xhci_plat_remove(struct platform_device *dev)
> +static int xhci_plat_remove(struct platform_device *pdev)
>  {
> -	struct usb_hcd	*hcd = platform_get_drvdata(dev);
> +	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
>  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
>  	struct clk *clk = xhci->clk;
> +	struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
> +
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(xhci->shared_hcd);
> +	else
> +		usb_remove_hcd(xhci->shared_hcd);
>  
> -	usb_remove_hcd(xhci->shared_hcd);
>  	usb_phy_shutdown(hcd->usb_phy);
>  
> -	usb_remove_hcd(hcd);
> +	if (pdata && pdata->otg_dev)
> +		usb_otg_remove_hcd(hcd);
> +	else
> +		usb_remove_hcd(hcd);
> +
>  	usb_put_hcd(xhci->shared_hcd);
>  
>  	if (!IS_ERR(clk))
> diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
> index 376654b..5c68b83 100644
> --- a/include/linux/usb/xhci_pdriver.h
> +++ b/include/linux/usb/xhci_pdriver.h
> @@ -18,10 +18,13 @@
>   *
>   * @usb3_lpm_capable:	determines if this xhci platform supports USB3
>   *			LPM capability
> + * @otg_dev:		OTG controller device. Only requied if part of
> + *			OTG/dual-role.
>   *
>   */
>  struct usb_xhci_pdata {
>  	unsigned	usb3_lpm_capable:1;
> +	struct device	*otg_dev;
>  };
>  
>  #endif /* __USB_CORE_XHCI_PDRIVER_H */
> 

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
@ 2016-06-14 14:21       ` Alan Stern
  0 siblings, 0 replies; 172+ messages in thread
From: Alan Stern @ 2016-06-14 14:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Tue, 14 Jun 2016, Roger Quadros wrote:

> +Alan
> 
> On 10/06/16 16:07, Roger Quadros wrote:
> > The OTG core will use struct otg_hcd_ops to interface
> > with the HCD (Host Controller Driver).
> > 
> > The main purpose of this interface is to avoid directly
> > calling HCD APIs 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>
> > Acked-by: Peter Chen <peter.chen@nxp.com>
> > ---
> >  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
> >  1 file changed, 24 insertions(+)
> > 
> > diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> > index 66fc137..7729c1f 100644
> > --- a/include/linux/usb/hcd.h
> > +++ b/include/linux/usb/hcd.h
> > @@ -400,6 +400,30 @@ struct hc_driver {
> >  
> >  };
> >  
> > +/**
> > + * struct otg_hcd_ops - Interface between OTG core and HCD
> > + *
> > + * Provided by the HCD core to allow the OTG core to interface with the HCD

Add:  * in case the OTG core is built-in and the HCD core is built as a module.

Otherwise, for patches 1, 3, and 12:

Acked-by: Alan Stern <stern@rowland.harvard.edu>

Alan Stern

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
@ 2016-06-14 14:21       ` Alan Stern
  0 siblings, 0 replies; 172+ messages in thread
From: Alan Stern @ 2016-06-14 14:21 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, balbi-DgEjT+Ai2ygdnm+yROfE0A,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, 14 Jun 2016, Roger Quadros wrote:

> +Alan
> 
> On 10/06/16 16:07, Roger Quadros wrote:
> > The OTG core will use struct otg_hcd_ops to interface
> > with the HCD (Host Controller Driver).
> > 
> > The main purpose of this interface is to avoid directly
> > calling HCD APIs 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-l0cyMroinI0@public.gmane.org>
> > Acked-by: Peter Chen <peter.chen-3arQi8VN3Tc@public.gmane.org>
> > ---
> >  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
> >  1 file changed, 24 insertions(+)
> > 
> > diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> > index 66fc137..7729c1f 100644
> > --- a/include/linux/usb/hcd.h
> > +++ b/include/linux/usb/hcd.h
> > @@ -400,6 +400,30 @@ struct hc_driver {
> >  
> >  };
> >  
> > +/**
> > + * struct otg_hcd_ops - Interface between OTG core and HCD
> > + *
> > + * Provided by the HCD core to allow the OTG core to interface with the HCD

Add:  * in case the OTG core is built-in and the HCD core is built as a module.

Otherwise, for patches 1, 3, and 12:

Acked-by: Alan Stern <stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org>

Alan Stern

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

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
  2016-06-14 14:21       ` Alan Stern
@ 2016-06-15  7:14         ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-15  7:14 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 14/06/16 17:21, Alan Stern wrote:
> On Tue, 14 Jun 2016, Roger Quadros wrote:
> 
>> +Alan
>>
>> On 10/06/16 16:07, Roger Quadros wrote:
>>> The OTG core will use struct otg_hcd_ops to interface
>>> with the HCD (Host Controller Driver).
>>>
>>> The main purpose of this interface is to avoid directly
>>> calling HCD APIs 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>
>>> Acked-by: Peter Chen <peter.chen@nxp.com>
>>> ---
>>>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
>>>  1 file changed, 24 insertions(+)
>>>
>>> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
>>> index 66fc137..7729c1f 100644
>>> --- a/include/linux/usb/hcd.h
>>> +++ b/include/linux/usb/hcd.h
>>> @@ -400,6 +400,30 @@ struct hc_driver {
>>>  
>>>  };
>>>  
>>> +/**
>>> + * struct otg_hcd_ops - Interface between OTG core and HCD
>>> + *
>>> + * Provided by the HCD core to allow the OTG core to interface with the HCD
> 
> Add:  * in case the OTG core is built-in and the HCD core is built as a module.

OK.

> 
> Otherwise, for patches 1, 3, and 12:
> 
> Acked-by: Alan Stern <stern@rowland.harvard.edu>
> 

Thanks.

cheers,
-roger

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

* Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface
@ 2016-06-15  7:14         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-15  7:14 UTC (permalink / raw)
  To: Alan Stern
  Cc: peter.chen, balbi, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On 14/06/16 17:21, Alan Stern wrote:
> On Tue, 14 Jun 2016, Roger Quadros wrote:
> 
>> +Alan
>>
>> On 10/06/16 16:07, Roger Quadros wrote:
>>> The OTG core will use struct otg_hcd_ops to interface
>>> with the HCD (Host Controller Driver).
>>>
>>> The main purpose of this interface is to avoid directly
>>> calling HCD APIs 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>
>>> Acked-by: Peter Chen <peter.chen@nxp.com>
>>> ---
>>>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
>>>  1 file changed, 24 insertions(+)
>>>
>>> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
>>> index 66fc137..7729c1f 100644
>>> --- a/include/linux/usb/hcd.h
>>> +++ b/include/linux/usb/hcd.h
>>> @@ -400,6 +400,30 @@ struct hc_driver {
>>>  
>>>  };
>>>  
>>> +/**
>>> + * struct otg_hcd_ops - Interface between OTG core and HCD
>>> + *
>>> + * Provided by the HCD core to allow the OTG core to interface with the HCD
> 
> Add:  * in case the OTG core is built-in and the HCD core is built as a module.

OK.

> 
> Otherwise, for patches 1, 3, and 12:
> 
> Acked-by: Alan Stern <stern@rowland.harvard.edu>
> 

Thanks.

cheers,
-roger

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
  2016-06-10 13:07 ` Roger Quadros
@ 2016-06-16 11:07   ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-16 11:07 UTC (permalink / raw)
  To: balbi
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

Hi Felipe,

On 10/06/16 16:07, 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.

Do you have any comments on this series? If yes I can include them
before sending v11 with Acks from Peter and Alan. Thanks.

--
cheers,
-roger

> 
> DWC3 controller and TI platform related patches will be sent separately.
> 
> Series is based on v4.7-rc1 + balbi/usb.git testing/next
> commit 4a2786c10462df650965785462ca82c185164d98.
> 
> Why?:
> ----
> 
> Currently there is no central location where OTG/dual-role functionality is
> implemented in the Linux USB stack and every USB controller driver is
> doing their own thing for OTG/dual-role. We can benefit from code-reuse
> and simplicity by adding the OTG/dual-role core driver.
> 
> 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 controllers in dual-role mode. i.e. to stop and start them
> from a central location. This central location should be the
> USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG/dual-role core consists of a set of APIs that allow
> registration of OTG controller device and OTG capable host and gadget
> controllers.
> 
> - The OTG controller driver can provide the OTG capabilities and the
> Finite State Machine work function via 'struct usb_otg_config'
> at the time of registration i.e. usb_otg_register();
> 
> 	struct usb_otg *usb_otg_register(struct device *dev,
>         	                         struct usb_otg_config *config);
> 	int usb_otg_unregister(struct device *dev);
> 	/**
> 	 * struct usb_otg_config - otg controller configuration
> 	 * @caps: otg capabilities of the controller
> 	 * @ops: otg fsm operations
> 	 * @otg_work: optional custom otg state machine work function
> 	 */
> 	struct usb_otg_config {
> 	        struct usb_otg_caps *otg_caps;
> 	        struct otg_fsm_ops *fsm_ops;
> 	        void (*otg_work)(struct work_struct *work);
> 	};
> 
> The dual-role state machine is built-into the OTG core so nothing
> special needs to be provided if only dual-role functionality is desired.
> The low level OTG controller driver ops are povided via
> 'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.
> 
> After registration, the OTG core waits for host, gadget controller
> and the gadget function driver to be registered. Once all resources are
> available it instantiates the Finite State Machine (FSM).
> The host/gadget controllers are started/stopped according to the FSM.
> 
> - Host and gadget controllers that are a part of OTG/dual-role port must
> use the OTG core provided APIs to add/remove the host/gadget.
> i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
> gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
> This ensures that the host and gadget controllers are not started till
> the state machine is ready and the right bus conditions are met.
> It also allows the host and gadget controllers to provide the OTG
> controller device to link them together. For Device tree boots
> the related OTG controller is automatically picked up via the
> 'otg-controller' property in the Host/Gadget controller nodes.
> 
> 	int usb_otg_add_hcd(struct usb_hcd *hcd,
> 			    unsigned int irqnum, unsigned long irqflags,
> 			    struct device *otg_dev);
> 	void usb_otg_remove_hcd(struct usb_hcd *hcd);
> 
> 	int usb_otg_add_gadget_udc(struct device *parent,
> 				   struct usb_gadget *gadget,
> 				   struct device *otg_dev);
> 	usb_del_gadget_udc() must be used for removal.
> 
> 
> - During the lifetime of the FSM, the OTG controller driver can provide
> inputs event changes using usb_otg_sync_inputs(). The OTG core will
> then schedule the FSM work function (or internal dual-role state machine)
> to update the FSM state. The FSM then calls the OTG controller
> operations (fsm_ops) as necessary.
> 	void usb_otg_sync_inputs(struct usb_otg *otg);
> 
> - The following 2 functions are provided as helpers for use by the
> OTG controller driver to start/stop the host/gadget controllers.
> 	int usb_otg_start_host(struct usb_otg *otg, int on);
> 	int usb_otg_start_gadget(struct usb_otg *otg, int on);
> 
> - The following function is provided for use by the USB host stack
> to sync OTG related events to the OTG state machine.
> e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> 	int usb_otg_kick_fsm(struct device *otg_device);
> 
> - The following function is provided for use by the USB gadget stack
> to notify OTG/DRD about gadget function driver being ready/not-ready
> 	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> 
> Changelog:
> ---------
> v10:
> - added missing mutex_unlock in failure path in usb_otg_unregister()
> - removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
> - comment fixes: urb->URB.
> - fix commit log: say dev_vdbg() instead of dev_dbg().
> - Update comments so that HCD means Host Controller Driver.
> - rebased on Felipe's balbi/usb.git /testing/next
> - include <linux/usb/of.h> in usb-otg.c
> - in usb_otg_start_host() check if hcd_ops->add() failed and return
> error code if it did.
> - in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
> error code if it did.
> - follow kernel-doc style in usb-otg.c
> 
> v9:
> - In the DT bindings, clearly indicate which properties are for OTG controller
> and which ones are for host/device controllers
> - Removed host/gadget wait list from otg core. Use defer probing if host/gadget
> registers before dual-role/otg controller.
> - move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
> to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
> an additional mechanism to know when the gadget function driver registers.
> So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
> ready/not-ready function driver.
> - update otg->caps based on capabilities provided by the controller and the
> device tree overrides.
> - in usb_drd_work() we must keep calling the drd_statemachine() as long as
> there is a state change.
> - updated kconfig so that usbotg can be a module when both host and gadget
> are modules.
> - rebased on v4.7-rc1
> 
> v8:
> - split out start/stop gadget and connect/disconnect operations.
> - make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
> - use create_freezable_workqueue() for OTG work as per Peter's suggestion.
> - remove usb-otg.h as we're not initializing any OTG timers.
> - don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)
> 
> v7:
> - added dual-role support for host controllers requiring a companion
> controller. e.g. EHCI + OHCI.
> - added of_usb_get_otg() to get the OTG controller device
> from the USB controller's device node.
> - addressed review comments.
> 
> v6:
> - added otg specific APIs for host/gadget registration. behaviour of
> original host/gadget API remains unchanged. Platform devices can now
> pass the otg device explicitly while registering host/gadget.
> - moved hcd specific operations from struct otg_fsm to struct hcd_ops.
> - made struct usb_otg mandatory for all otg related APIs.
> - allow otg controller to provide it's own otg_work function so that
> it can implement it's own state machine.
> - removed otg fsm and timers from usb-otg.c. Only dual-role state machine
> is implemented.
> - vbus is controlled in the dual-role state machine.
> - PM runtime is used around drd_statemachine().
> - added otg_dev to xhci platform data to allow platform code to specify
> the otg controller tied to the xhci host controller.
> 
> v5: Internal version. Not sent to mailing list
> 
> 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.
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: hcd: Initialize hcd->flags to 0
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   usb: hcd.h: Add OTG to HCD interface
>   usb: otg-fsm: use usb_otg wherever possible
>   usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
>   usb: otg: add OTG/dual-role core
>   usb: of: add an API to get OTG device from USB controller node
>   usb: otg: use dev_vdbg() instead of VDBG()
>   usb: hcd: Adapt to OTG core
>   usb: gadget: udc: adapt to OTG core
>   usb: host: xhci-plat: Add otg device to platform data
> 
> Yoshihiro Shimoda (1):
>   usb: otg: add hcd companion support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |   6 +
>  Documentation/usb/chipidea.txt                    |   2 +-
>  drivers/usb/Kconfig                               |  18 +
>  drivers/usb/Makefile                              |   1 +
>  drivers/usb/chipidea/Makefile                     |   2 +-
>  drivers/usb/chipidea/ci.h                         |   3 +-
>  drivers/usb/chipidea/core.c                       |  14 +-
>  drivers/usb/chipidea/debug.c                      |   2 +-
>  drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
>  drivers/usb/chipidea/otg_fsm.h                    |   2 +-
>  drivers/usb/chipidea/udc.c                        |  17 +-
>  drivers/usb/common/Makefile                       |   5 +-
>  drivers/usb/common/common.c                       |  27 +
>  drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
>  drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
>  drivers/usb/core/Kconfig                          |  22 -
>  drivers/usb/core/hcd.c                            |  56 ++
>  drivers/usb/gadget/Kconfig                        |   1 +
>  drivers/usb/gadget/udc/core.c                     | 202 ++++-
>  drivers/usb/host/xhci-plat.c                      |  35 +-
>  drivers/usb/phy/Kconfig                           |   2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
>  drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
>  include/linux/usb/gadget.h                        |  22 +
>  include/linux/usb/hcd.h                           |  29 +
>  include/linux/usb/of.h                            |   9 +
>  include/linux/usb/otg-fsm.h                       | 154 +---
>  include/linux/usb/otg.h                           | 290 ++++++-
>  include/linux/usb/xhci_pdriver.h                  |   3 +
>  29 files changed, 1918 insertions(+), 462 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
> 

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-16 11:07   ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-16 11:07 UTC (permalink / raw)
  To: balbi
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

Hi Felipe,

On 10/06/16 16:07, 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.

Do you have any comments on this series? If yes I can include them
before sending v11 with Acks from Peter and Alan. Thanks.

--
cheers,
-roger

> 
> DWC3 controller and TI platform related patches will be sent separately.
> 
> Series is based on v4.7-rc1 + balbi/usb.git testing/next
> commit 4a2786c10462df650965785462ca82c185164d98.
> 
> Why?:
> ----
> 
> Currently there is no central location where OTG/dual-role functionality is
> implemented in the Linux USB stack and every USB controller driver is
> doing their own thing for OTG/dual-role. We can benefit from code-reuse
> and simplicity by adding the OTG/dual-role core driver.
> 
> 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 controllers in dual-role mode. i.e. to stop and start them
> from a central location. This central location should be the
> USB OTG/dual-role 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 couldn't be done till now but can be done from the OTG core.
> 
> What?:
> -----
> 
> The OTG/dual-role core consists of a set of APIs that allow
> registration of OTG controller device and OTG capable host and gadget
> controllers.
> 
> - The OTG controller driver can provide the OTG capabilities and the
> Finite State Machine work function via 'struct usb_otg_config'
> at the time of registration i.e. usb_otg_register();
> 
> 	struct usb_otg *usb_otg_register(struct device *dev,
>         	                         struct usb_otg_config *config);
> 	int usb_otg_unregister(struct device *dev);
> 	/**
> 	 * struct usb_otg_config - otg controller configuration
> 	 * @caps: otg capabilities of the controller
> 	 * @ops: otg fsm operations
> 	 * @otg_work: optional custom otg state machine work function
> 	 */
> 	struct usb_otg_config {
> 	        struct usb_otg_caps *otg_caps;
> 	        struct otg_fsm_ops *fsm_ops;
> 	        void (*otg_work)(struct work_struct *work);
> 	};
> 
> The dual-role state machine is built-into the OTG core so nothing
> special needs to be provided if only dual-role functionality is desired.
> The low level OTG controller driver ops are povided via
> 'struct otg_fsm_ops *fsm_ops' in the 'struct usb_otg_config'.
> 
> After registration, the OTG core waits for host, gadget controller
> and the gadget function driver to be registered. Once all resources are
> available it instantiates the Finite State Machine (FSM).
> The host/gadget controllers are started/stopped according to the FSM.
> 
> - Host and gadget controllers that are a part of OTG/dual-role port must
> use the OTG core provided APIs to add/remove the host/gadget.
> i.e. hosts must use usb_otg_add_hcd() usb_otg_remove_hcd(),,
> gadgets must use usb_otg_add_gadget_udc() usb_del_gadget_udc().
> This ensures that the host and gadget controllers are not started till
> the state machine is ready and the right bus conditions are met.
> It also allows the host and gadget controllers to provide the OTG
> controller device to link them together. For Device tree boots
> the related OTG controller is automatically picked up via the
> 'otg-controller' property in the Host/Gadget controller nodes.
> 
> 	int usb_otg_add_hcd(struct usb_hcd *hcd,
> 			    unsigned int irqnum, unsigned long irqflags,
> 			    struct device *otg_dev);
> 	void usb_otg_remove_hcd(struct usb_hcd *hcd);
> 
> 	int usb_otg_add_gadget_udc(struct device *parent,
> 				   struct usb_gadget *gadget,
> 				   struct device *otg_dev);
> 	usb_del_gadget_udc() must be used for removal.
> 
> 
> - During the lifetime of the FSM, the OTG controller driver can provide
> inputs event changes using usb_otg_sync_inputs(). The OTG core will
> then schedule the FSM work function (or internal dual-role state machine)
> to update the FSM state. The FSM then calls the OTG controller
> operations (fsm_ops) as necessary.
> 	void usb_otg_sync_inputs(struct usb_otg *otg);
> 
> - The following 2 functions are provided as helpers for use by the
> OTG controller driver to start/stop the host/gadget controllers.
> 	int usb_otg_start_host(struct usb_otg *otg, int on);
> 	int usb_otg_start_gadget(struct usb_otg *otg, int on);
> 
> - The following function is provided for use by the USB host stack
> to sync OTG related events to the OTG state machine.
> e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
> 	int usb_otg_kick_fsm(struct device *otg_device);
> 
> - The following function is provided for use by the USB gadget stack
> to notify OTG/DRD about gadget function driver being ready/not-ready
> 	int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> 
> Changelog:
> ---------
> v10:
> - added missing mutex_unlock in failure path in usb_otg_unregister()
> - removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h
> - comment fixes: urb->URB.
> - fix commit log: say dev_vdbg() instead of dev_dbg().
> - Update comments so that HCD means Host Controller Driver.
> - rebased on Felipe's balbi/usb.git /testing/next
> - include <linux/usb/of.h> in usb-otg.c
> - in usb_otg_start_host() check if hcd_ops->add() failed and return
> error code if it did.
> - in usb_otg_start/stop_gadget() check if hcd_ops->add() failed and return
> error code if it did.
> - follow kernel-doc style in usb-otg.c
> 
> v9:
> - In the DT bindings, clearly indicate which properties are for OTG controller
> and which ones are for host/device controllers
> - Removed host/gadget wait list from otg core. Use defer probing if host/gadget
> registers before dual-role/otg controller.
> - move gadget registering to otg core from udc_bind_to_driver()/usb_gadget_remove_driver()
> to usb_add_gadget_udc_release()/usb_del_gadget_udc(). This means that we need
> an additional mechanism to know when the gadget function driver registers.
> So we add usb_otg_gadget_ready() API to allow gadget to notify otg core about
> ready/not-ready function driver.
> - update otg->caps based on capabilities provided by the controller and the
> device tree overrides.
> - in usb_drd_work() we must keep calling the drd_statemachine() as long as
> there is a state change.
> - updated kconfig so that usbotg can be a module when both host and gadget
> are modules.
> - rebased on v4.7-rc1
> 
> v8:
> - split out start/stop gadget and connect/disconnect operations.
> - make CONFIG_OTG dpend on CONFIG_USB_GADGET as well apart from CONFIG_USB
> - use create_freezable_workqueue() for OTG work as per Peter's suggestion.
> - remove usb-otg.h as we're not initializing any OTG timers.
> - don't include unnecessary headers in usb-otg.c (i.e. hrtimer.h & ktime.h)
> 
> v7:
> - added dual-role support for host controllers requiring a companion
> controller. e.g. EHCI + OHCI.
> - added of_usb_get_otg() to get the OTG controller device
> from the USB controller's device node.
> - addressed review comments.
> 
> v6:
> - added otg specific APIs for host/gadget registration. behaviour of
> original host/gadget API remains unchanged. Platform devices can now
> pass the otg device explicitly while registering host/gadget.
> - moved hcd specific operations from struct otg_fsm to struct hcd_ops.
> - made struct usb_otg mandatory for all otg related APIs.
> - allow otg controller to provide it's own otg_work function so that
> it can implement it's own state machine.
> - removed otg fsm and timers from usb-otg.c. Only dual-role state machine
> is implemented.
> - vbus is controlled in the dual-role state machine.
> - PM runtime is used around drd_statemachine().
> - added otg_dev to xhci platform data to allow platform code to specify
> the otg controller tied to the xhci host controller.
> 
> v5: Internal version. Not sent to mailing list
> 
> 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.
> 
> --
> cheers,
> -roger
> 
> Roger Quadros (13):
>   usb: hcd: Initialize hcd->flags to 0
>   usb: otg-fsm: Prevent build warning "VDBG" redefined
>   usb: hcd.h: Add OTG to HCD interface
>   usb: otg-fsm: use usb_otg wherever possible
>   usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
>   usb: gadget.h: Add OTG to gadget interface
>   usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG
>   usb: otg: add OTG/dual-role core
>   usb: of: add an API to get OTG device from USB controller node
>   usb: otg: use dev_vdbg() instead of VDBG()
>   usb: hcd: Adapt to OTG core
>   usb: gadget: udc: adapt to OTG core
>   usb: host: xhci-plat: Add otg device to platform data
> 
> Yoshihiro Shimoda (1):
>   usb: otg: add hcd companion support
> 
>  Documentation/devicetree/bindings/usb/generic.txt |   6 +
>  Documentation/usb/chipidea.txt                    |   2 +-
>  drivers/usb/Kconfig                               |  18 +
>  drivers/usb/Makefile                              |   1 +
>  drivers/usb/chipidea/Makefile                     |   2 +-
>  drivers/usb/chipidea/ci.h                         |   3 +-
>  drivers/usb/chipidea/core.c                       |  14 +-
>  drivers/usb/chipidea/debug.c                      |   2 +-
>  drivers/usb/chipidea/otg_fsm.c                    | 176 +++--
>  drivers/usb/chipidea/otg_fsm.h                    |   2 +-
>  drivers/usb/chipidea/udc.c                        |  17 +-
>  drivers/usb/common/Makefile                       |   5 +-
>  drivers/usb/common/common.c                       |  27 +
>  drivers/usb/common/usb-otg-fsm.c                  | 203 ++---
>  drivers/usb/common/usb-otg.c                      | 919 ++++++++++++++++++++++
>  drivers/usb/core/Kconfig                          |  22 -
>  drivers/usb/core/hcd.c                            |  56 ++
>  drivers/usb/gadget/Kconfig                        |   1 +
>  drivers/usb/gadget/udc/core.c                     | 202 ++++-
>  drivers/usb/host/xhci-plat.c                      |  35 +-
>  drivers/usb/phy/Kconfig                           |   2 +-
>  drivers/usb/phy/phy-fsl-usb.c                     | 155 ++--
>  drivers/usb/phy/phy-fsl-usb.h                     |   3 +-
>  include/linux/usb/gadget.h                        |  22 +
>  include/linux/usb/hcd.h                           |  29 +
>  include/linux/usb/of.h                            |   9 +
>  include/linux/usb/otg-fsm.h                       | 154 +---
>  include/linux/usb/otg.h                           | 290 ++++++-
>  include/linux/usb/xhci_pdriver.h                  |   3 +
>  29 files changed, 1918 insertions(+), 462 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
> 

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-17  7:17     ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-17  7:17 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 794 bytes --]


Hi Roger,

Roger Quadros <rogerq@ti.com> writes:
>> 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.
>
> Do you have any comments on this series? If yes I can include them
> before sending v11 with Acks from Peter and Alan. Thanks.

I'll need some more time to look at this, have been real busy with some
internal tasks. Frankly, though, I still think this is way more complex
than what it needs to be and that's actually quite scary IMO.

I'll try to dedicate some time today to review these patches, hopefully
I'll find a few minutes. I know that I also owe you a look at the IRQ
cleanup for dwc3, I'll see if I can get to that as well.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-17  7:17     ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-17  7:17 UTC (permalink / raw)
  To: Roger Quadros
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 816 bytes --]


Hi Roger,

Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>> 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.
>
> Do you have any comments on this series? If yes I can include them
> before sending v11 with Acks from Peter and Alan. Thanks.

I'll need some more time to look at this, have been real busy with some
internal tasks. Frankly, though, I still think this is way more complex
than what it needs to be and that's actually quite scary IMO.

I'll try to dedicate some time today to review these patches, hopefully
I'll find a few minutes. I know that I also owe you a look at the IRQ
cleanup for dwc3, I'll see if I can get to that as well.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
  2016-06-17  7:17     ` Felipe Balbi
@ 2016-06-17  7:31       ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-17  7:31 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree


[-- Attachment #1.1: Type: text/plain, Size: 1137 bytes --]

On 17/06/16 10:17, Felipe Balbi wrote:
> 
> Hi Roger,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>> 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.
>>
>> Do you have any comments on this series? If yes I can include them
>> before sending v11 with Acks from Peter and Alan. Thanks.
> 
> I'll need some more time to look at this, have been real busy with some
> internal tasks. Frankly, though, I still think this is way more complex
> than what it needs to be and that's actually quite scary IMO.
> 
> I'll try to dedicate some time today to review these patches, hopefully
> I'll find a few minutes. I know that I also owe you a look at the IRQ
> cleanup for dwc3, I'll see if I can get to that as well.
> 

Thanks Felipe. I'm definitely open to improve this in whatever way
we can so that individual controller drivers prefer to use it than
do their own thing. A bit earlier review would have helped to avoid unnecessary
rework but let's do it now than never. :)

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 00/14] USB OTG/dual-role framework
@ 2016-06-17  7:31       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-17  7:31 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko,
	yoshihiro.shimoda.uh, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree


[-- Attachment #1.1: Type: text/plain, Size: 1137 bytes --]

On 17/06/16 10:17, Felipe Balbi wrote:
> 
> Hi Roger,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>> 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.
>>
>> Do you have any comments on this series? If yes I can include them
>> before sending v11 with Acks from Peter and Alan. Thanks.
> 
> I'll need some more time to look at this, have been real busy with some
> internal tasks. Frankly, though, I still think this is way more complex
> than what it needs to be and that's actually quite scary IMO.
> 
> I'll try to dedicate some time today to review these patches, hopefully
> I'll find a few minutes. I know that I also owe you a look at the IRQ
> cleanup for dwc3, I'll see if I can get to that as well.
> 

Thanks Felipe. I'm definitely open to improve this in whatever way
we can so that individual controller drivers prefer to use it than
do their own thing. A bit earlier review would have helped to avoid unnecessary
rework but let's do it now than never. :)

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
  2016-06-10 13:07   ` Roger Quadros
@ 2016-06-20  7:21     ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  7:21 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

[-- Attachment #1: Type: text/plain, Size: 1498 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
> 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>
> ---
>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index 2dd9e6b..f4fc0aa 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -639,6 +639,22 @@ 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
> + * @connect_control: function to connect/disconnect from the bus
> + */
> +struct otg_gadget_ops {
> +	int (*start)(struct usb_gadget *gadget);
> +	int (*stop)(struct usb_gadget *gadget);
> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
> +};

you shouldn't need these at all. They are already part of the gadget
framework as ->udc_start(), ->udc_stop() and ->pullup()

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  7:21     ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  7:21 UTC (permalink / raw)
  To: peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, Roger Quadros

[-- Attachment #1: Type: text/plain, Size: 1498 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
> 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>
> ---
>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index 2dd9e6b..f4fc0aa 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -639,6 +639,22 @@ 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
> + * @connect_control: function to connect/disconnect from the bus
> + */
> +struct otg_gadget_ops {
> +	int (*start)(struct usb_gadget *gadget);
> +	int (*stop)(struct usb_gadget *gadget);
> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
> +};

you shouldn't need these at all. They are already part of the gadget
framework as ->udc_start(), ->udc_stop() and ->pullup()

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
  2016-06-20  7:21     ` Felipe Balbi
@ 2016-06-20  7:28       ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  7:28 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 1748 bytes --]

On 20/06/16 10:21, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>> 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>
>> ---
>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> index 2dd9e6b..f4fc0aa 100644
>> --- a/include/linux/usb/gadget.h
>> +++ b/include/linux/usb/gadget.h
>> @@ -639,6 +639,22 @@ 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
>> + * @connect_control: function to connect/disconnect from the bus
>> + */
>> +struct otg_gadget_ops {
>> +	int (*start)(struct usb_gadget *gadget);
>> +	int (*stop)(struct usb_gadget *gadget);
>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>> +};
> 
> you shouldn't need these at all. They are already part of the gadget
> framework as ->udc_start(), ->udc_stop() and ->pullup()
> 

This is to avoid the undefined symbol errors during build when OTG has is
built-in because USB (host) is built-in but GADGET is still a module.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  7:28       ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  7:28 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 1748 bytes --]

On 20/06/16 10:21, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>> 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>
>> ---
>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> index 2dd9e6b..f4fc0aa 100644
>> --- a/include/linux/usb/gadget.h
>> +++ b/include/linux/usb/gadget.h
>> @@ -639,6 +639,22 @@ 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
>> + * @connect_control: function to connect/disconnect from the bus
>> + */
>> +struct otg_gadget_ops {
>> +	int (*start)(struct usb_gadget *gadget);
>> +	int (*stop)(struct usb_gadget *gadget);
>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>> +};
> 
> you shouldn't need these at all. They are already part of the gadget
> framework as ->udc_start(), ->udc_stop() and ->pullup()
> 

This is to avoid the undefined symbol errors during build when OTG has is
built-in because USB (host) is built-in but GADGET is still a module.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20  7:45       ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  7:45 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

[-- Attachment #1: Type: text/plain, Size: 29561 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
> It provides APIs for the following tasks
>
> - Registering an OTG/dual-role capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine

I think I have already mentioned this, but after over 10 years of OTG,
nobody seems to care about it, why are we still touching at all I don't
know. For common non-OTG role-swapping we really don't need any of this
and, quite frankly, I fail to see enough users for this.

Apparently there's only chipidea which, AFAICT, already had working
dual-role before this OTG State Machine was added to the kernel.

> Provide a dual-role device (DRD) state machine.

there's not such thing as DRD state machine. You don't need to go
through all these states, actually.

> 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>
> ---
> v11:
> - remove usb_otg_kick_fsm().
> - typo fixes: structa/structure, upto/up to.
> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>
>  drivers/usb/Kconfig          |  18 +
>  drivers/usb/common/Makefile  |   6 +-
>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/core/Kconfig     |  14 -
>  drivers/usb/gadget/Kconfig   |   1 +
>  include/linux/usb/gadget.h   |   2 +
>  include/linux/usb/hcd.h      |   1 +
>  include/linux/usb/otg-fsm.h  |   7 +
>  include/linux/usb/otg.h      | 174 ++++++++-
>  9 files changed, 1070 insertions(+), 30 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 8689dcb..ed596ec 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -32,6 +32,23 @@ if USB_SUPPORT
>  config USB_COMMON
>  	tristate
>  
> +config USB_OTG_CORE
> +	tristate

why tristate if you can never set it to 'M'?

> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> new file mode 100644
> index 0000000..a23ab1e
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.c
> @@ -0,0 +1,877 @@
> +/**
> + * drivers/usb/common/usb-otg.c - USB OTG core
> + *
> + * Copyright (C) 2016 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/list.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/usb/of.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/workqueue.h>
> +
> +/* OTG device list */
> +LIST_HEAD(otg_list);

not static? Who needs to touch this private list?

> +static DEFINE_MUTEX(otg_list_mutex);
> +
> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
> +{
> +	if (!hcd->primary_hcd)
> +		return 1;

these seems inverted. If hcd->primary is NULL (meaning, there's no
->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
to explain?

> +	return hcd == hcd->primary_hcd;
> +}
> +
> +/**
> + * usb_otg_get_data() - get usb_otg data structure
> + * @otg_dev:	OTG controller device
> + *
> + * Check if the OTG device is in our OTG list and return
> + * usb_otg data, else NULL.
> + *
> + * otg_list_mutex must be held.
> + *
> + * Return: usb_otg data on success, NULL otherwise.
> + */
> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
> +{
> +	struct usb_otg *otg;
> +
> +	if (!otg_dev)
> +		return NULL;
> +
> +	list_for_each_entry(otg, &otg_list, list) {
> +		if (otg->dev == otg_dev)
> +			return otg;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * usb_otg_start_host() - start/stop the host controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB host controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_host(struct usb_otg *otg, int on)
> +{
> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!otg->host) {
> +		WARN_ONCE(1, "otg: fsm running without host\n");

if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
	return 0;

but, frankly, if you require a 'host' and a 'gadget' don't start this
layer until you have both.

> +		return 0;
> +	}
> +
> +	if (on) {
> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
> +			return 0;
> +
> +		/* start host */
> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> +				   otg->primary_hcd.irqnum,
> +				   otg->primary_hcd.irqflags);

this is usb_add_hcd(), is it not? Why add an indirection?

> +		if (ret) {
> +			dev_err(otg->dev, "otg: host add failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		if (otg->shared_hcd.hcd) {
> +			ret = hcd_ops->add(otg->shared_hcd.hcd,
> +					   otg->shared_hcd.irqnum,
> +					   otg->shared_hcd.irqflags);
> +			if (ret) {
> +				dev_err(otg->dev, "otg: shared host add failed %d\n",
> +					ret);
> +				hcd_ops->remove(otg->primary_hcd.hcd);
> +				return ret;
> +			}
> +		}
> +		otg->flags |= OTG_FLAG_HOST_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
> +			return 0;
> +
> +		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
> +
> +		/* stop host */
> +		if (otg->shared_hcd.hcd)
> +			hcd_ops->remove(otg->shared_hcd.hcd);

usb_del_hcd()?

> +		hcd_ops->remove(otg->primary_hcd.hcd);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
> +
> +/**
> + * usb_otg_start_gadget() - start/stop the gadget controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB gadget controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_gadget(struct usb_otg *otg, int on)
> +{
> +	struct usb_gadget *gadget = otg->gadget;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!gadget) {
> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
> +		return 0;
> +	}

ditto

> +	if (on) {
> +		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
> +			return 0;
> +
> +		ret = otg->gadget_ops->start(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget start failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		otg->flags |= OTG_FLAG_GADGET_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
> +			return 0;
> +
> +		ret = otg->gadget_ops->stop(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
> +
> +/**
> + * drd_set_protocol() -  Set USB protocol if possible
> + * @fsm:	DRD FSM instance
> + * @protocol:	USB protocol to set the state machine to
> + *
> + * Sets the OTG FSM protocol to @protocol if it changed.
> + * fsm->lock must be held.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +	int ret = 0;
> +
> +	if (fsm->protocol != protocol) {
> +		dev_dbg(otg->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(otg, 0);
> +		} else if (fsm->protocol == PROTO_GADGET) {
> +			otg->gadget_ops->connect_control(otg->gadget, false);
> +			ret = otg_start_gadget(otg, 0);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		/* start new protocol */
> +		if (protocol == PROTO_HOST) {
> +			ret = otg_start_host(otg, 1);
> +		} else if (protocol == PROTO_GADGET) {
> +			ret = otg_start_gadget(otg, 1);
> +			otg->gadget_ops->connect_control(otg->gadget, true);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		fsm->protocol = protocol;
> +		return 0;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * drd_set_state() - Set the DRD state machine state.
> + * @fsm:	DRD FSM instance
> + * @new_state:	the new state the DRD FSM must be set to
> + *
> + * Sets the state of the DRD state machine.
> + * fsm->lock must be held.
> + */
> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +
> +	if (otg->state == new_state)
> +		return;
> +
> +	fsm->state_changed = 1;
> +	dev_dbg(otg->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);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_B_PERIPHERAL:
> +		drd_set_protocol(fsm, PROTO_GADGET);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_A_HOST:
> +		drd_set_protocol(fsm, PROTO_HOST);
> +		otg_drv_vbus(otg, 1);
> +		break;
> +	default:
> +		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
> +			 __func__, usb_otg_state_string(new_state));
> +		break;
> +	}
> +
> +	otg->state = new_state;
> +}
> +
> +/**
> + * drd_statemachine() - DRD state change judgement
> + * @otg:	usb_otg instance
> + *
> + * Checks the state machine inputs and state and makes a state change
> + * if required.
> + *
> + * 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
> + *
> + * Return: 0 if state wasn't changed, 1 if state changed.
> + */
> +int drd_statemachine(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +	enum usb_otg_state state;
> +	int ret;
> +
> +	mutex_lock(&fsm->lock);
> +
> +	fsm->state_changed = 0;
> +	state = 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;
> +
> +	default:
> +		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
> +			__func__, usb_otg_state_string(state));
> +		break;
> +	}
> +
> +	ret = fsm->state_changed;
> +	mutex_unlock(&fsm->lock);
> +	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
> +		fsm->state_changed);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(drd_statemachine);

why is this exported at all? It only runs from the work_struct
below. BTW, that work_struct looks unnecessary.

> +
> +/**
> + * usb_drd_work() - Dual-role state machine work function
> + * @work: work_struct context
> + *
> + * Runs the DRD state machine. Scheduled whenever there is a change
> + * in FSM inputs.
> + */
> +static void usb_drd_work(struct work_struct *work)
> +{
> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
> +
> +	pm_runtime_get_sync(otg->dev);
> +	while (drd_statemachine(otg))
> +		;
> +	pm_runtime_put_sync(otg->dev);

so, once this gets kicked it'll keep on running until a state doesn't
change.

> +}
> +
> +/**
> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
> + * @dev: OTG/dual-role controller device.
> + * @config: OTG configuration.
> + *
> + * Registers the OTG/dual-role controller device with the USB OTG core.
> + *
> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
> + */
> +struct usb_otg *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config)
> +{
> +	struct usb_otg *otg;
> +	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 */
> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
> +	if (!otg) {
> +		ret = -ENOMEM;
> +		goto unlock;
> +	}
> +
> +	otg->dev = dev;
> +	/* otg->caps is controller caps + DT overrides */
> +	otg->caps = *config->otg_caps;
> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
> +	if (ret)
> +		goto err_wq;
> +
> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
> +	     otg->caps.adp_support) && !config->otg_work) {
> +		dev_err(dev,
> +			"otg: otg_work must be provided for OTG support\n");
> +		ret = -EINVAL;
> +		goto err_wq;
> +	}
> +
> +	if (config->otg_work)	/* custom otg_work ? */
> +		INIT_WORK(&otg->work, config->otg_work);
> +	else
> +		INIT_WORK(&otg->work, usb_drd_work);

why do you need to cope with custom work handlers?

> +	otg->wq = create_freezable_workqueue("usb_otg");
> +	if (!otg->wq) {
> +		dev_err(dev, "otg: %s: can't create workqueue\n",
> +			__func__);
> +		ret = -ENOMEM;
> +		goto err_wq;
> +	}
> +
> +	/* set otg ops */
> +	otg->fsm.ops = config->fsm_ops;
> +
> +	mutex_init(&otg->fsm.lock);
> +
> +	list_add_tail(&otg->list, &otg_list);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return otg;
> +
> +err_wq:
> +	kfree(otg);
> +unlock:
> +	mutex_unlock(&otg_list_mutex);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register);
> +
> +/**
> + * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
> + * @dev: OTG controller device.
> + *
> + * Unregisters the OTG/dual-role 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 *otg;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(dev);
> +	if (!otg) {
> +		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 (otg->host || otg->gadget) {
> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
> +			__func__);
> +		mutex_unlock(&otg_list_mutex);
> +		return -EBUSY;
> +	}

I think a better choice would've been to unregister host and gadget in
case they haven't been unregistered yet. That's a common
expectation. Specially since driver core does the same thing when you
unregister a parent device.

> +	/* OTG FSM is halted when host/gadget unregistered */
> +	destroy_workqueue(otg->wq);
> +
> +	/* remove from otg list */
> +	list_del(&otg->list);
> +	kfree(otg);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
> +
> +/**
> + * usb_otg_start_fsm() - Start the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
> + * must be ready for the OTG FSM to start.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_start_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (fsm->running)
> +		goto kick_fsm;
> +
> +	if (!otg->host) {
> +		dev_info(otg->dev, "otg: can't start till host registers\n");
> +		return;
> +	}
> +
> +	if (!otg->gadget) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget UDC registers\n");
> +		return;
> +	}

okay, so you never kick the FSM until host and gadget are
registered. Why do you need to test for the case where the FSM is
running without host/gadget?

You seem to guarantee that will never be the case.

> +	if (!otg->gadget_ready) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget function registers\n");
> +		return;
> +	}
> +
> +	fsm->running = true;
> +kick_fsm:
> +	queue_work(otg->wq, &otg->work);
> +}
> +
> +/**
> + * usb_otg_stop_fsm() - Stop the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Stops the HCD, UDC and the OTG FSM.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_stop_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (!fsm->running)
> +		return;
> +
> +	/* no more new events queued */
> +	fsm->running = false;
> +
> +	flush_workqueue(otg->wq);
> +	otg->state = OTG_STATE_UNDEFINED;
> +
> +	/* stop host/gadget immediately */
> +	if (fsm->protocol == PROTO_HOST) {
> +		otg_start_host(otg, 0);
> +	} else if (fsm->protocol == PROTO_GADGET) {
> +		otg->gadget_ops->connect_control(otg->gadget, false);
> +		otg_start_gadget(otg, 0);
> +	}
> +	fsm->protocol = PROTO_UNDEF;
> +}
> +
> +/**
> + * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
> + * @otg:	usb_otg 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 usb_otg *otg)
> +{
> +	/* Don't kick FSM till it has started */
> +	if (!otg->fsm.running)
> +		return;
> +
> +	/* Kick FSM */
> +	queue_work(otg->wq, &otg->work);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
> +
> +/**
> + * usb_otg_register_hcd() - Register the host controller to OTG core
> + * @hcd:	host controller
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
> + * hcd->otg_dev must contain the related otg controller device.
> + *
> + * Return: 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 *otg;
> +	struct device *hcd_dev = hcd->self.controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(hcd_dev,
> +			"otg: controller not yet registered. deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	/* HCD will be started by OTG fsm when needed */
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->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 == otg->primary_hcd.hcd) {
> +			if (otg->shared_hcd.hcd) {
> +				dev_err(otg_dev, "otg: shared host already registered\n");
> +				goto err;
> +			}
> +
> +			otg->shared_hcd.hcd = hcd;
> +			otg->shared_hcd.irqnum = irqnum;
> +			otg->shared_hcd.irqflags = irqflags;
> +			otg->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;
> +		}
> +
> +		otg->primary_hcd.hcd = hcd;
> +		otg->primary_hcd.irqnum = irqnum;
> +		otg->primary_hcd.irqflags = irqflags;
> +		otg->primary_hcd.ops = ops;
> +		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
> +		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(otg);
> +	} else {
> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> +	}
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +
> +err:
> +	mutex_unlock(&otg->fsm.lock);
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> +
> +/**
> + * usb_otg_unregister_hcd() - Unregister the 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 *otg;
> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (hcd == otg->primary_hcd.hcd) {
> +		otg->primary_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else if (hcd == otg->shared_hcd.hcd) {
> +		otg->shared_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	/* stop FSM & Host */
> +	usb_otg_stop_fsm(otg);
> +	otg->host = NULL;
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> +
> +/**
> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
> + * @gadget:	gadget controller instance
> + * @ops:	gadget interface ops
> + *
> + * 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 up to the OTG state machine to do so.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_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);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(gadget_dev,
> +			"otg: controller not yet registered, deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget) {
> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> +		mutex_unlock(&otg->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	otg->gadget = gadget;
> +	otg->gadget_ops = ops;
> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> +		 dev_name(&gadget->dev));
> +
> +	/* FSM will be started in usb_otg_gadget_ready() */
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> +
> +/**
> + * usb_otg_unregister_gadget() - Unregister the 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 *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* FSM must be stopped in usb_otg_gadget_ready() */
> +	if (otg->gadget_ready) {
> +		dev_err(otg_dev,
> +			"otg: gadget %s unregistered before being unready, forcing stop\n",
> +			dev_name(&gadget->dev));
> +		usb_otg_stop_fsm(otg);
> +	}
> +
> +	otg->gadget = NULL;
> +	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
> + * @gadget:	gadget controller
> + * @ready:	0: function driver ready, 1: function driver not ready
> + *
> + * Notify the OTG core about status of the gadget function driver.
> + * As OTG core is responsible to start/stop the gadget controller, it
> + * must be aware when the gadget function driver is available or not.
> + * This function is used by the Gadget core to inform the OTG core
> + * about the gadget function driver readyness.
> + *
> + * Return: 0 on sucess, error value otherwise.
> + */
> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* Start/stop FSM & gadget */
> +	otg->gadget_ready = ready;
> +	if (ready)
> +		usb_otg_start_fsm(otg);
> +	else
> +		usb_otg_stop_fsm(otg);
> +
> +	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
> +		ready ? "" : "not ");
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
> +
> +MODULE_LICENSE("GPL");

GPL or GPL 2-only?

> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index f4fc0aa..1d74fb8 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>   * @in_epnum: last used in ep number
>   * @mA: last set mA value
>   * @otg_caps: OTG capabilities of this gadget.
> + * @otg_dev: OTG controller device, if needs to be used with OTG core.

do you really know of any platform which has a separate OTG controller?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20  7:45       ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  7:45 UTC (permalink / raw)
  To: peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, rogerq-l0cyMroinI0

[-- Attachment #1: Type: text/plain, Size: 29627 bytes --]


Hi,

Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
> It provides APIs for the following tasks
>
> - Registering an OTG/dual-role capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine

I think I have already mentioned this, but after over 10 years of OTG,
nobody seems to care about it, why are we still touching at all I don't
know. For common non-OTG role-swapping we really don't need any of this
and, quite frankly, I fail to see enough users for this.

Apparently there's only chipidea which, AFAICT, already had working
dual-role before this OTG State Machine was added to the kernel.

> Provide a dual-role device (DRD) state machine.

there's not such thing as DRD state machine. You don't need to go
through all these states, actually.

> 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-l0cyMroinI0@public.gmane.org>
> ---
> v11:
> - remove usb_otg_kick_fsm().
> - typo fixes: structa/structure, upto/up to.
> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>
>  drivers/usb/Kconfig          |  18 +
>  drivers/usb/common/Makefile  |   6 +-
>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/core/Kconfig     |  14 -
>  drivers/usb/gadget/Kconfig   |   1 +
>  include/linux/usb/gadget.h   |   2 +
>  include/linux/usb/hcd.h      |   1 +
>  include/linux/usb/otg-fsm.h  |   7 +
>  include/linux/usb/otg.h      | 174 ++++++++-
>  9 files changed, 1070 insertions(+), 30 deletions(-)
>  create mode 100644 drivers/usb/common/usb-otg.c
>
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 8689dcb..ed596ec 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -32,6 +32,23 @@ if USB_SUPPORT
>  config USB_COMMON
>  	tristate
>  
> +config USB_OTG_CORE
> +	tristate

why tristate if you can never set it to 'M'?

> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> new file mode 100644
> index 0000000..a23ab1e
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.c
> @@ -0,0 +1,877 @@
> +/**
> + * drivers/usb/common/usb-otg.c - USB OTG core
> + *
> + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
> + * Author: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
> + *
> + * 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/list.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/usb/of.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/workqueue.h>
> +
> +/* OTG device list */
> +LIST_HEAD(otg_list);

not static? Who needs to touch this private list?

> +static DEFINE_MUTEX(otg_list_mutex);
> +
> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
> +{
> +	if (!hcd->primary_hcd)
> +		return 1;

these seems inverted. If hcd->primary is NULL (meaning, there's no
->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
to explain?

> +	return hcd == hcd->primary_hcd;
> +}
> +
> +/**
> + * usb_otg_get_data() - get usb_otg data structure
> + * @otg_dev:	OTG controller device
> + *
> + * Check if the OTG device is in our OTG list and return
> + * usb_otg data, else NULL.
> + *
> + * otg_list_mutex must be held.
> + *
> + * Return: usb_otg data on success, NULL otherwise.
> + */
> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
> +{
> +	struct usb_otg *otg;
> +
> +	if (!otg_dev)
> +		return NULL;
> +
> +	list_for_each_entry(otg, &otg_list, list) {
> +		if (otg->dev == otg_dev)
> +			return otg;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * usb_otg_start_host() - start/stop the host controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB host controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_host(struct usb_otg *otg, int on)
> +{
> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!otg->host) {
> +		WARN_ONCE(1, "otg: fsm running without host\n");

if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
	return 0;

but, frankly, if you require a 'host' and a 'gadget' don't start this
layer until you have both.

> +		return 0;
> +	}
> +
> +	if (on) {
> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
> +			return 0;
> +
> +		/* start host */
> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> +				   otg->primary_hcd.irqnum,
> +				   otg->primary_hcd.irqflags);

this is usb_add_hcd(), is it not? Why add an indirection?

> +		if (ret) {
> +			dev_err(otg->dev, "otg: host add failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		if (otg->shared_hcd.hcd) {
> +			ret = hcd_ops->add(otg->shared_hcd.hcd,
> +					   otg->shared_hcd.irqnum,
> +					   otg->shared_hcd.irqflags);
> +			if (ret) {
> +				dev_err(otg->dev, "otg: shared host add failed %d\n",
> +					ret);
> +				hcd_ops->remove(otg->primary_hcd.hcd);
> +				return ret;
> +			}
> +		}
> +		otg->flags |= OTG_FLAG_HOST_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
> +			return 0;
> +
> +		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
> +
> +		/* stop host */
> +		if (otg->shared_hcd.hcd)
> +			hcd_ops->remove(otg->shared_hcd.hcd);

usb_del_hcd()?

> +		hcd_ops->remove(otg->primary_hcd.hcd);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
> +
> +/**
> + * usb_otg_start_gadget() - start/stop the gadget controller
> + * @otg:	usb_otg instance
> + * @on:		true to start, false to stop
> + *
> + * Start/stop the USB gadget controller. This function is meant
> + * for use by the OTG controller driver.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +int usb_otg_start_gadget(struct usb_otg *otg, int on)
> +{
> +	struct usb_gadget *gadget = otg->gadget;
> +	int ret;
> +
> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
> +	if (!gadget) {
> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
> +		return 0;
> +	}

ditto

> +	if (on) {
> +		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
> +			return 0;
> +
> +		ret = otg->gadget_ops->start(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget start failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		otg->flags |= OTG_FLAG_GADGET_RUNNING;
> +	} else {
> +		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
> +			return 0;
> +
> +		ret = otg->gadget_ops->stop(otg->gadget);
> +		if (ret) {
> +			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
> +				ret);
> +			return ret;
> +		}
> +		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
> +
> +/**
> + * drd_set_protocol() -  Set USB protocol if possible
> + * @fsm:	DRD FSM instance
> + * @protocol:	USB protocol to set the state machine to
> + *
> + * Sets the OTG FSM protocol to @protocol if it changed.
> + * fsm->lock must be held.
> + *
> + * Return: 0 on success, error value otherwise.
> + */
> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +	int ret = 0;
> +
> +	if (fsm->protocol != protocol) {
> +		dev_dbg(otg->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(otg, 0);
> +		} else if (fsm->protocol == PROTO_GADGET) {
> +			otg->gadget_ops->connect_control(otg->gadget, false);
> +			ret = otg_start_gadget(otg, 0);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		/* start new protocol */
> +		if (protocol == PROTO_HOST) {
> +			ret = otg_start_host(otg, 1);
> +		} else if (protocol == PROTO_GADGET) {
> +			ret = otg_start_gadget(otg, 1);
> +			otg->gadget_ops->connect_control(otg->gadget, true);
> +		}
> +
> +		if (ret)
> +			return ret;
> +
> +		fsm->protocol = protocol;
> +		return 0;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * drd_set_state() - Set the DRD state machine state.
> + * @fsm:	DRD FSM instance
> + * @new_state:	the new state the DRD FSM must be set to
> + *
> + * Sets the state of the DRD state machine.
> + * fsm->lock must be held.
> + */
> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> +{
> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
> +
> +	if (otg->state == new_state)
> +		return;
> +
> +	fsm->state_changed = 1;
> +	dev_dbg(otg->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);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_B_PERIPHERAL:
> +		drd_set_protocol(fsm, PROTO_GADGET);
> +		otg_drv_vbus(otg, 0);
> +		break;
> +	case OTG_STATE_A_HOST:
> +		drd_set_protocol(fsm, PROTO_HOST);
> +		otg_drv_vbus(otg, 1);
> +		break;
> +	default:
> +		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
> +			 __func__, usb_otg_state_string(new_state));
> +		break;
> +	}
> +
> +	otg->state = new_state;
> +}
> +
> +/**
> + * drd_statemachine() - DRD state change judgement
> + * @otg:	usb_otg instance
> + *
> + * Checks the state machine inputs and state and makes a state change
> + * if required.
> + *
> + * 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
> + *
> + * Return: 0 if state wasn't changed, 1 if state changed.
> + */
> +int drd_statemachine(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +	enum usb_otg_state state;
> +	int ret;
> +
> +	mutex_lock(&fsm->lock);
> +
> +	fsm->state_changed = 0;
> +	state = 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;
> +
> +	default:
> +		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
> +			__func__, usb_otg_state_string(state));
> +		break;
> +	}
> +
> +	ret = fsm->state_changed;
> +	mutex_unlock(&fsm->lock);
> +	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
> +		fsm->state_changed);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(drd_statemachine);

why is this exported at all? It only runs from the work_struct
below. BTW, that work_struct looks unnecessary.

> +
> +/**
> + * usb_drd_work() - Dual-role state machine work function
> + * @work: work_struct context
> + *
> + * Runs the DRD state machine. Scheduled whenever there is a change
> + * in FSM inputs.
> + */
> +static void usb_drd_work(struct work_struct *work)
> +{
> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
> +
> +	pm_runtime_get_sync(otg->dev);
> +	while (drd_statemachine(otg))
> +		;
> +	pm_runtime_put_sync(otg->dev);

so, once this gets kicked it'll keep on running until a state doesn't
change.

> +}
> +
> +/**
> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
> + * @dev: OTG/dual-role controller device.
> + * @config: OTG configuration.
> + *
> + * Registers the OTG/dual-role controller device with the USB OTG core.
> + *
> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
> + */
> +struct usb_otg *usb_otg_register(struct device *dev,
> +				 struct usb_otg_config *config)
> +{
> +	struct usb_otg *otg;
> +	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 */
> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
> +	if (!otg) {
> +		ret = -ENOMEM;
> +		goto unlock;
> +	}
> +
> +	otg->dev = dev;
> +	/* otg->caps is controller caps + DT overrides */
> +	otg->caps = *config->otg_caps;
> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
> +	if (ret)
> +		goto err_wq;
> +
> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
> +	     otg->caps.adp_support) && !config->otg_work) {
> +		dev_err(dev,
> +			"otg: otg_work must be provided for OTG support\n");
> +		ret = -EINVAL;
> +		goto err_wq;
> +	}
> +
> +	if (config->otg_work)	/* custom otg_work ? */
> +		INIT_WORK(&otg->work, config->otg_work);
> +	else
> +		INIT_WORK(&otg->work, usb_drd_work);

why do you need to cope with custom work handlers?

> +	otg->wq = create_freezable_workqueue("usb_otg");
> +	if (!otg->wq) {
> +		dev_err(dev, "otg: %s: can't create workqueue\n",
> +			__func__);
> +		ret = -ENOMEM;
> +		goto err_wq;
> +	}
> +
> +	/* set otg ops */
> +	otg->fsm.ops = config->fsm_ops;
> +
> +	mutex_init(&otg->fsm.lock);
> +
> +	list_add_tail(&otg->list, &otg_list);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return otg;
> +
> +err_wq:
> +	kfree(otg);
> +unlock:
> +	mutex_unlock(&otg_list_mutex);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register);
> +
> +/**
> + * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
> + * @dev: OTG controller device.
> + *
> + * Unregisters the OTG/dual-role 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 *otg;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(dev);
> +	if (!otg) {
> +		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 (otg->host || otg->gadget) {
> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
> +			__func__);
> +		mutex_unlock(&otg_list_mutex);
> +		return -EBUSY;
> +	}

I think a better choice would've been to unregister host and gadget in
case they haven't been unregistered yet. That's a common
expectation. Specially since driver core does the same thing when you
unregister a parent device.

> +	/* OTG FSM is halted when host/gadget unregistered */
> +	destroy_workqueue(otg->wq);
> +
> +	/* remove from otg list */
> +	list_del(&otg->list);
> +	kfree(otg);
> +	mutex_unlock(&otg_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
> +
> +/**
> + * usb_otg_start_fsm() - Start the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
> + * must be ready for the OTG FSM to start.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_start_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (fsm->running)
> +		goto kick_fsm;
> +
> +	if (!otg->host) {
> +		dev_info(otg->dev, "otg: can't start till host registers\n");
> +		return;
> +	}
> +
> +	if (!otg->gadget) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget UDC registers\n");
> +		return;
> +	}

okay, so you never kick the FSM until host and gadget are
registered. Why do you need to test for the case where the FSM is
running without host/gadget?

You seem to guarantee that will never be the case.

> +	if (!otg->gadget_ready) {
> +		dev_info(otg->dev,
> +			 "otg: can't start till gadget function registers\n");
> +		return;
> +	}
> +
> +	fsm->running = true;
> +kick_fsm:
> +	queue_work(otg->wq, &otg->work);
> +}
> +
> +/**
> + * usb_otg_stop_fsm() - Stop the OTG FSM
> + * @otg:	usb_otg instance
> + *
> + * Stops the HCD, UDC and the OTG FSM.
> + *
> + * fsm->lock must be held.
> + */
> +static void usb_otg_stop_fsm(struct usb_otg *otg)
> +{
> +	struct otg_fsm *fsm = &otg->fsm;
> +
> +	if (!fsm->running)
> +		return;
> +
> +	/* no more new events queued */
> +	fsm->running = false;
> +
> +	flush_workqueue(otg->wq);
> +	otg->state = OTG_STATE_UNDEFINED;
> +
> +	/* stop host/gadget immediately */
> +	if (fsm->protocol == PROTO_HOST) {
> +		otg_start_host(otg, 0);
> +	} else if (fsm->protocol == PROTO_GADGET) {
> +		otg->gadget_ops->connect_control(otg->gadget, false);
> +		otg_start_gadget(otg, 0);
> +	}
> +	fsm->protocol = PROTO_UNDEF;
> +}
> +
> +/**
> + * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
> + * @otg:	usb_otg 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 usb_otg *otg)
> +{
> +	/* Don't kick FSM till it has started */
> +	if (!otg->fsm.running)
> +		return;
> +
> +	/* Kick FSM */
> +	queue_work(otg->wq, &otg->work);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
> +
> +/**
> + * usb_otg_register_hcd() - Register the host controller to OTG core
> + * @hcd:	host controller
> + * @irqnum:	interrupt number
> + * @irqflags:	interrupt flags
> + * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
> + * hcd->otg_dev must contain the related otg controller device.
> + *
> + * Return: 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 *otg;
> +	struct device *hcd_dev = hcd->self.controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	/* we're otg but otg controller might not yet be registered */
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(hcd_dev,
> +			"otg: controller not yet registered. deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	/* HCD will be started by OTG fsm when needed */
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->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 == otg->primary_hcd.hcd) {
> +			if (otg->shared_hcd.hcd) {
> +				dev_err(otg_dev, "otg: shared host already registered\n");
> +				goto err;
> +			}
> +
> +			otg->shared_hcd.hcd = hcd;
> +			otg->shared_hcd.irqnum = irqnum;
> +			otg->shared_hcd.irqflags = irqflags;
> +			otg->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;
> +		}
> +
> +		otg->primary_hcd.hcd = hcd;
> +		otg->primary_hcd.irqnum = irqnum;
> +		otg->primary_hcd.irqflags = irqflags;
> +		otg->primary_hcd.ops = ops;
> +		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
> +		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(otg);
> +	} else {
> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
> +	}
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +
> +err:
> +	mutex_unlock(&otg->fsm.lock);
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
> +
> +/**
> + * usb_otg_unregister_hcd() - Unregister the 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 *otg;
> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
> +	struct device *otg_dev = hcd->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;	/* we're definitely not OTG */
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (hcd == otg->primary_hcd.hcd) {
> +		otg->primary_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else if (hcd == otg->shared_hcd.hcd) {
> +		otg->shared_hcd.hcd = NULL;
> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
> +			 dev_name(hcd_dev));
> +	} else {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
> +			dev_name(hcd_dev));
> +		return -EINVAL;
> +	}
> +
> +	/* stop FSM & Host */
> +	usb_otg_stop_fsm(otg);
> +	otg->host = NULL;
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
> +
> +/**
> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
> + * @gadget:	gadget controller instance
> + * @ops:	gadget interface ops
> + *
> + * 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 up to the OTG state machine to do so.
> + *
> + * Returns: 0 on success, error value otherwise.
> + */
> +int usb_otg_register_gadget(struct usb_gadget *gadget,
> +			    struct otg_gadget_ops *ops)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_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);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_dbg(gadget_dev,
> +			"otg: controller not yet registered, deferring.\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget) {
> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
> +		mutex_unlock(&otg->fsm.lock);
> +		return -EINVAL;
> +	}
> +
> +	otg->gadget = gadget;
> +	otg->gadget_ops = ops;
> +	dev_info(otg_dev, "otg: gadget %s registered\n",
> +		 dev_name(&gadget->dev));
> +
> +	/* FSM will be started in usb_otg_gadget_ready() */
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
> +
> +/**
> + * usb_otg_unregister_gadget() - Unregister the 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 *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* FSM must be stopped in usb_otg_gadget_ready() */
> +	if (otg->gadget_ready) {
> +		dev_err(otg_dev,
> +			"otg: gadget %s unregistered before being unready, forcing stop\n",
> +			dev_name(&gadget->dev));
> +		usb_otg_stop_fsm(otg);
> +	}
> +
> +	otg->gadget = NULL;
> +	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
> + * @gadget:	gadget controller
> + * @ready:	0: function driver ready, 1: function driver not ready
> + *
> + * Notify the OTG core about status of the gadget function driver.
> + * As OTG core is responsible to start/stop the gadget controller, it
> + * must be aware when the gadget function driver is available or not.
> + * This function is used by the Gadget core to inform the OTG core
> + * about the gadget function driver readyness.
> + *
> + * Return: 0 on sucess, error value otherwise.
> + */
> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
> +{
> +	struct usb_otg *otg;
> +	struct device *gadget_dev = &gadget->dev;
> +	struct device *otg_dev = gadget->otg_dev;
> +
> +	if (!otg_dev)
> +		return -EINVAL;
> +
> +	mutex_lock(&otg_list_mutex);
> +	otg = usb_otg_get_data(otg_dev);
> +	mutex_unlock(&otg_list_mutex);
> +	if (!otg) {
> +		dev_err(gadget_dev,
> +			"otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&otg->fsm.lock);
> +	if (otg->gadget != gadget) {
> +		mutex_unlock(&otg->fsm.lock);
> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
> +			dev_name(&gadget->dev));
> +		return -EINVAL;
> +	}
> +
> +	/* Start/stop FSM & gadget */
> +	otg->gadget_ready = ready;
> +	if (ready)
> +		usb_otg_start_fsm(otg);
> +	else
> +		usb_otg_stop_fsm(otg);
> +
> +	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
> +		ready ? "" : "not ");
> +
> +	mutex_unlock(&otg->fsm.lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
> +
> +MODULE_LICENSE("GPL");

GPL or GPL 2-only?

> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> index f4fc0aa..1d74fb8 100644
> --- a/include/linux/usb/gadget.h
> +++ b/include/linux/usb/gadget.h
> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>   * @in_epnum: last used in ep number
>   * @mA: last set mA value
>   * @otg_caps: OTG capabilities of this gadget.
> + * @otg_dev: OTG controller device, if needs to be used with OTG core.

do you really know of any platform which has a separate OTG controller?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  8:13         ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  8:13 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 1985 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
> [ Unknown signature status ]
> On 20/06/16 10:21, Felipe Balbi wrote:
>> 
>> Hi,
>> 
>> Roger Quadros <rogerq@ti.com> writes:
>>> 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>
>>> ---
>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>  1 file changed, 16 insertions(+)
>>>
>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>> index 2dd9e6b..f4fc0aa 100644
>>> --- a/include/linux/usb/gadget.h
>>> +++ b/include/linux/usb/gadget.h
>>> @@ -639,6 +639,22 @@ 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
>>> + * @connect_control: function to connect/disconnect from the bus
>>> + */
>>> +struct otg_gadget_ops {
>>> +	int (*start)(struct usb_gadget *gadget);
>>> +	int (*stop)(struct usb_gadget *gadget);
>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>> +};
>> 
>> you shouldn't need these at all. They are already part of the gadget
>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>> 
>
> This is to avoid the undefined symbol errors during build when OTG has is
> built-in because USB (host) is built-in but GADGET is still a module.

change your Kconfig dependencies. OTG layer shouldn't be built-in unless
both Gadget and Host are built-in.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  8:13         ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  8:13 UTC (permalink / raw)
  To: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2051 bytes --]


Hi,

Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
> [ Unknown signature status ]
> On 20/06/16 10:21, Felipe Balbi wrote:
>> 
>> Hi,
>> 
>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>> 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-l0cyMroinI0@public.gmane.org>
>>> ---
>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>  1 file changed, 16 insertions(+)
>>>
>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>> index 2dd9e6b..f4fc0aa 100644
>>> --- a/include/linux/usb/gadget.h
>>> +++ b/include/linux/usb/gadget.h
>>> @@ -639,6 +639,22 @@ 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
>>> + * @connect_control: function to connect/disconnect from the bus
>>> + */
>>> +struct otg_gadget_ops {
>>> +	int (*start)(struct usb_gadget *gadget);
>>> +	int (*stop)(struct usb_gadget *gadget);
>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>> +};
>> 
>> you shouldn't need these at all. They are already part of the gadget
>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>> 
>
> This is to avoid the undefined symbol errors during build when OTG has is
> built-in because USB (host) is built-in but GADGET is still a module.

change your Kconfig dependencies. OTG layer shouldn't be built-in unless
both Gadget and Host are built-in.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  8:25           ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  8:25 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 2289 bytes --]

On 20/06/16 11:13, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>> [ Unknown signature status ]
>> On 20/06/16 10:21, Felipe Balbi wrote:
>>>
>>> Hi,
>>>
>>> Roger Quadros <rogerq@ti.com> writes:
>>>> 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>
>>>> ---
>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>  1 file changed, 16 insertions(+)
>>>>
>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>> index 2dd9e6b..f4fc0aa 100644
>>>> --- a/include/linux/usb/gadget.h
>>>> +++ b/include/linux/usb/gadget.h
>>>> @@ -639,6 +639,22 @@ 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
>>>> + * @connect_control: function to connect/disconnect from the bus
>>>> + */
>>>> +struct otg_gadget_ops {
>>>> +	int (*start)(struct usb_gadget *gadget);
>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>> +};
>>>
>>> you shouldn't need these at all. They are already part of the gadget
>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>
>>
>> This is to avoid the undefined symbol errors during build when OTG has is
>> built-in because USB (host) is built-in but GADGET is still a module.
> 
> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
> both Gadget and Host are built-in.
> 

That is only one side of the story.
What happens if OTG is (m), Host is (m) but Gadget is (built in).

Gadget build will fail because of undefined symbol errors for all of the
OTG APIs.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  8:25           ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  8:25 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA


[-- Attachment #1.1: Type: text/plain, Size: 2355 bytes --]

On 20/06/16 11:13, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>> [ Unknown signature status ]
>> On 20/06/16 10:21, Felipe Balbi wrote:
>>>
>>> Hi,
>>>
>>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>> 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-l0cyMroinI0@public.gmane.org>
>>>> ---
>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>  1 file changed, 16 insertions(+)
>>>>
>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>> index 2dd9e6b..f4fc0aa 100644
>>>> --- a/include/linux/usb/gadget.h
>>>> +++ b/include/linux/usb/gadget.h
>>>> @@ -639,6 +639,22 @@ 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
>>>> + * @connect_control: function to connect/disconnect from the bus
>>>> + */
>>>> +struct otg_gadget_ops {
>>>> +	int (*start)(struct usb_gadget *gadget);
>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>> +};
>>>
>>> you shouldn't need these at all. They are already part of the gadget
>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>
>>
>> This is to avoid the undefined symbol errors during build when OTG has is
>> built-in because USB (host) is built-in but GADGET is still a module.
> 
> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
> both Gadget and Host are built-in.
> 

That is only one side of the story.
What happens if OTG is (m), Host is (m) but Gadget is (built in).

Gadget build will fail because of undefined symbol errors for all of the
OTG APIs.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  9:24             ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  9:24 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 2375 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
>>>> Roger Quadros <rogerq@ti.com> writes:
>>>>> 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>
>>>>> ---
>>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>>  1 file changed, 16 insertions(+)
>>>>>
>>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>>> index 2dd9e6b..f4fc0aa 100644
>>>>> --- a/include/linux/usb/gadget.h
>>>>> +++ b/include/linux/usb/gadget.h
>>>>> @@ -639,6 +639,22 @@ 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
>>>>> + * @connect_control: function to connect/disconnect from the bus
>>>>> + */
>>>>> +struct otg_gadget_ops {
>>>>> +	int (*start)(struct usb_gadget *gadget);
>>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>>> +};
>>>>
>>>> you shouldn't need these at all. They are already part of the gadget
>>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>>
>>>
>>> This is to avoid the undefined symbol errors during build when OTG has is
>>> built-in because USB (host) is built-in but GADGET is still a module.
>> 
>> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
>> both Gadget and Host are built-in.
>> 
>
> That is only one side of the story.
> What happens if OTG is (m), Host is (m) but Gadget is (built in).
>
> Gadget build will fail because of undefined symbol errors for all of
> the OTG APIs.

So you created a circular dependency, right? That's not good either. I
suggest you clean that up because this is bound to create randconfig
build problems in the long run.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  9:24             ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20  9:24 UTC (permalink / raw)
  To: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2441 bytes --]


Hi,

Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>>> 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-l0cyMroinI0@public.gmane.org>
>>>>> ---
>>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>>  1 file changed, 16 insertions(+)
>>>>>
>>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>>> index 2dd9e6b..f4fc0aa 100644
>>>>> --- a/include/linux/usb/gadget.h
>>>>> +++ b/include/linux/usb/gadget.h
>>>>> @@ -639,6 +639,22 @@ 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
>>>>> + * @connect_control: function to connect/disconnect from the bus
>>>>> + */
>>>>> +struct otg_gadget_ops {
>>>>> +	int (*start)(struct usb_gadget *gadget);
>>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>>> +};
>>>>
>>>> you shouldn't need these at all. They are already part of the gadget
>>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>>
>>>
>>> This is to avoid the undefined symbol errors during build when OTG has is
>>> built-in because USB (host) is built-in but GADGET is still a module.
>> 
>> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
>> both Gadget and Host are built-in.
>> 
>
> That is only one side of the story.
> What happens if OTG is (m), Host is (m) but Gadget is (built in).
>
> Gadget build will fail because of undefined symbol errors for all of
> the OTG APIs.

So you created a circular dependency, right? That's not good either. I
suggest you clean that up because this is bound to create randconfig
build problems in the long run.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  9:43               ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  9:43 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 2666 bytes --]

On 20/06/16 12:24, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>> 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>
>>>>>> ---
>>>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>>>  1 file changed, 16 insertions(+)
>>>>>>
>>>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>>>> index 2dd9e6b..f4fc0aa 100644
>>>>>> --- a/include/linux/usb/gadget.h
>>>>>> +++ b/include/linux/usb/gadget.h
>>>>>> @@ -639,6 +639,22 @@ 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
>>>>>> + * @connect_control: function to connect/disconnect from the bus
>>>>>> + */
>>>>>> +struct otg_gadget_ops {
>>>>>> +	int (*start)(struct usb_gadget *gadget);
>>>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>>>> +};
>>>>>
>>>>> you shouldn't need these at all. They are already part of the gadget
>>>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>>>
>>>>
>>>> This is to avoid the undefined symbol errors during build when OTG has is
>>>> built-in because USB (host) is built-in but GADGET is still a module.
>>>
>>> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
>>> both Gadget and Host are built-in.
>>>
>>
>> That is only one side of the story.
>> What happens if OTG is (m), Host is (m) but Gadget is (built in).
>>
>> Gadget build will fail because of undefined symbol errors for all of
>> the OTG APIs.
> 
> So you created a circular dependency, right? That's not good either. I
> suggest you clean that up because this is bound to create randconfig
> build problems in the long run.
> 

We can't avoid the circular dependency.
Gadget/Host has to register with otg. otg has to use gadget & host functions.

If you have better ideas, please let us know.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface
@ 2016-06-20  9:43               ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20  9:43 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA


[-- Attachment #1.1: Type: text/plain, Size: 2732 bytes --]

On 20/06/16 12:24, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>>>> 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-l0cyMroinI0@public.gmane.org>
>>>>>> ---
>>>>>>  include/linux/usb/gadget.h | 16 ++++++++++++++++
>>>>>>  1 file changed, 16 insertions(+)
>>>>>>
>>>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>>>> index 2dd9e6b..f4fc0aa 100644
>>>>>> --- a/include/linux/usb/gadget.h
>>>>>> +++ b/include/linux/usb/gadget.h
>>>>>> @@ -639,6 +639,22 @@ 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
>>>>>> + * @connect_control: function to connect/disconnect from the bus
>>>>>> + */
>>>>>> +struct otg_gadget_ops {
>>>>>> +	int (*start)(struct usb_gadget *gadget);
>>>>>> +	int (*stop)(struct usb_gadget *gadget);
>>>>>> +	int (*connect_control)(struct usb_gadget *gadget, bool connect);
>>>>>> +};
>>>>>
>>>>> you shouldn't need these at all. They are already part of the gadget
>>>>> framework as ->udc_start(), ->udc_stop() and ->pullup()
>>>>>
>>>>
>>>> This is to avoid the undefined symbol errors during build when OTG has is
>>>> built-in because USB (host) is built-in but GADGET is still a module.
>>>
>>> change your Kconfig dependencies. OTG layer shouldn't be built-in unless
>>> both Gadget and Host are built-in.
>>>
>>
>> That is only one side of the story.
>> What happens if OTG is (m), Host is (m) but Gadget is (built in).
>>
>> Gadget build will fail because of undefined symbol errors for all of
>> the OTG APIs.
> 
> So you created a circular dependency, right? That's not good either. I
> suggest you clean that up because this is bound to create randconfig
> build problems in the long run.
> 

We can't avoid the circular dependency.
Gadget/Host has to register with otg. otg has to use gadget & host functions.

If you have better ideas, please let us know.

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 10:13         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20 10:13 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen, yoshihiro.shimoda.uh
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree


[-- Attachment #1.1: Type: text/plain, Size: 32422 bytes --]

Hi,

On 20/06/16 10:45, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
> 
> I think I have already mentioned this, but after over 10 years of OTG,
> nobody seems to care about it, why are we still touching at all I don't
> know. For common non-OTG role-swapping we really don't need any of this
> and, quite frankly, I fail to see enough users for this.
> 
> Apparently there's only chipidea which, AFAICT, already had working
> dual-role before this OTG State Machine was added to the kernel.
> 
>> Provide a dual-role device (DRD) state machine.
> 
> there's not such thing as DRD state machine. You don't need to go
> through all these states, actually.

There are 3 states though.
HOST (id = 0)
PERIPHERAL (id = 1, vbus = 1)
IDLE (id = 1, vbus = 0).

> 
>> 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>
>> ---
>> v11:
>> - remove usb_otg_kick_fsm().
>> - typo fixes: structa/structure, upto/up to.
>> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>>
>>  drivers/usb/Kconfig          |  18 +
>>  drivers/usb/common/Makefile  |   6 +-
>>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>>  drivers/usb/core/Kconfig     |  14 -
>>  drivers/usb/gadget/Kconfig   |   1 +
>>  include/linux/usb/gadget.h   |   2 +
>>  include/linux/usb/hcd.h      |   1 +
>>  include/linux/usb/otg-fsm.h  |   7 +
>>  include/linux/usb/otg.h      | 174 ++++++++-
>>  9 files changed, 1070 insertions(+), 30 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>
>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>> index 8689dcb..ed596ec 100644
>> --- a/drivers/usb/Kconfig
>> +++ b/drivers/usb/Kconfig
>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>  config USB_COMMON
>>  	tristate
>>  
>> +config USB_OTG_CORE
>> +	tristate
> 
> why tristate if you can never set it to 'M'?

This gets internally set to M if either USB or GADGET is M.
We select it in USB and GADGET.
This was the only way I could get usb-otg.c to build as

m if USB OR GADGET is m
built-in if USB and GADGET are built in.

> 
>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>> new file mode 100644
>> index 0000000..a23ab1e
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.c
>> @@ -0,0 +1,877 @@
>> +/**
>> + * drivers/usb/common/usb-otg.c - USB OTG core
>> + *
>> + * Copyright (C) 2016 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/list.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/usb/of.h>
>> +#include <linux/usb/otg.h>
>> +#include <linux/usb/gadget.h>
>> +#include <linux/workqueue.h>
>> +
>> +/* OTG device list */
>> +LIST_HEAD(otg_list);
> 
> not static? Who needs to touch this private list?

right, it should be static.

> 
>> +static DEFINE_MUTEX(otg_list_mutex);
>> +
>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>> +{
>> +	if (!hcd->primary_hcd)
>> +		return 1;
> 
> these seems inverted. If hcd->primary is NULL (meaning, there's no
> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
> to explain?

hcd->primary_hcd is a link used by the shared hcd to point to the primary_hcd.
primary_hcd's have this link as NULL.

> 
>> +	return hcd == hcd->primary_hcd;
>> +}
>> +
>> +/**
>> + * usb_otg_get_data() - get usb_otg data structure
>> + * @otg_dev:	OTG controller device
>> + *
>> + * Check if the OTG device is in our OTG list and return
>> + * usb_otg data, else NULL.
>> + *
>> + * otg_list_mutex must be held.
>> + *
>> + * Return: usb_otg data on success, NULL otherwise.
>> + */
>> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
>> +{
>> +	struct usb_otg *otg;
>> +
>> +	if (!otg_dev)
>> +		return NULL;
>> +
>> +	list_for_each_entry(otg, &otg_list, list) {
>> +		if (otg->dev == otg_dev)
>> +			return otg;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +/**
>> + * usb_otg_start_host() - start/stop the host controller
>> + * @otg:	usb_otg instance
>> + * @on:		true to start, false to stop
>> + *
>> + * Start/stop the USB host controller. This function is meant
>> + * for use by the OTG controller driver.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>> +{
>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>> +	int ret;
>> +
>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>> +	if (!otg->host) {
>> +		WARN_ONCE(1, "otg: fsm running without host\n");
> 
> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
> 	return 0;
> 
> but, frankly, if you require a 'host' and a 'gadget' don't start this
> layer until you have both.

We don't start the layer till we have both host and gadget. But
this API is for external use and might be called at any time.

I could change the warning message to
 
if (WARN_ONCE(!otg->host, "otg: %s called in invalid context\n", __func__))
	return 0;

> 
>> +		return 0;
>> +	}
>> +
>> +	if (on) {
>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>> +			return 0;
>> +
>> +		/* start host */
>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> +				   otg->primary_hcd.irqnum,
>> +				   otg->primary_hcd.irqflags);
> 
> this is usb_add_hcd(), is it not? Why add an indirection?

I've introduced the host and gadget ops interface to get around the
circular dependency issue we can't avoid.
otg needs to call host/gadget functions and host/gadget also needs to
call otg functions.

> 
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: host add failed %d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		if (otg->shared_hcd.hcd) {
>> +			ret = hcd_ops->add(otg->shared_hcd.hcd,
>> +					   otg->shared_hcd.irqnum,
>> +					   otg->shared_hcd.irqflags);
>> +			if (ret) {
>> +				dev_err(otg->dev, "otg: shared host add failed %d\n",
>> +					ret);
>> +				hcd_ops->remove(otg->primary_hcd.hcd);
>> +				return ret;
>> +			}
>> +		}
>> +		otg->flags |= OTG_FLAG_HOST_RUNNING;
>> +	} else {
>> +		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
>> +			return 0;
>> +
>> +		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
>> +
>> +		/* stop host */
>> +		if (otg->shared_hcd.hcd)
>> +			hcd_ops->remove(otg->shared_hcd.hcd);
> 
> usb_del_hcd()?
> 
>> +		hcd_ops->remove(otg->primary_hcd.hcd);
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
>> +
>> +/**
>> + * usb_otg_start_gadget() - start/stop the gadget controller
>> + * @otg:	usb_otg instance
>> + * @on:		true to start, false to stop
>> + *
>> + * Start/stop the USB gadget controller. This function is meant
>> + * for use by the OTG controller driver.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_start_gadget(struct usb_otg *otg, int on)
>> +{
>> +	struct usb_gadget *gadget = otg->gadget;
>> +	int ret;
>> +
>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>> +	if (!gadget) {
>> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
>> +		return 0;
>> +	}
> 
> ditto

I'll fix up the message to

("otg: %s called in invalid context\n", __func__)

> 
>> +	if (on) {
>> +		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
>> +			return 0;
>> +
>> +		ret = otg->gadget_ops->start(otg->gadget);
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: gadget start failed: %d\n",
>> +				ret);
>> +			return ret;
>> +		}
>> +
>> +		otg->flags |= OTG_FLAG_GADGET_RUNNING;
>> +	} else {
>> +		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
>> +			return 0;
>> +
>> +		ret = otg->gadget_ops->stop(otg->gadget);
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
>> +				ret);
>> +			return ret;
>> +		}
>> +		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
>> +
>> +/**
>> + * drd_set_protocol() -  Set USB protocol if possible
>> + * @fsm:	DRD FSM instance
>> + * @protocol:	USB protocol to set the state machine to
>> + *
>> + * Sets the OTG FSM protocol to @protocol if it changed.
>> + * fsm->lock must be held.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
>> +{
>> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
>> +	int ret = 0;
>> +
>> +	if (fsm->protocol != protocol) {
>> +		dev_dbg(otg->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(otg, 0);
>> +		} else if (fsm->protocol == PROTO_GADGET) {
>> +			otg->gadget_ops->connect_control(otg->gadget, false);
>> +			ret = otg_start_gadget(otg, 0);
>> +		}
>> +
>> +		if (ret)
>> +			return ret;
>> +
>> +		/* start new protocol */
>> +		if (protocol == PROTO_HOST) {
>> +			ret = otg_start_host(otg, 1);
>> +		} else if (protocol == PROTO_GADGET) {
>> +			ret = otg_start_gadget(otg, 1);
>> +			otg->gadget_ops->connect_control(otg->gadget, true);
>> +		}
>> +
>> +		if (ret)
>> +			return ret;
>> +
>> +		fsm->protocol = protocol;
>> +		return 0;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * drd_set_state() - Set the DRD state machine state.
>> + * @fsm:	DRD FSM instance
>> + * @new_state:	the new state the DRD FSM must be set to
>> + *
>> + * Sets the state of the DRD state machine.
>> + * fsm->lock must be held.
>> + */
>> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>> +{
>> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	if (otg->state == new_state)
>> +		return;
>> +
>> +	fsm->state_changed = 1;
>> +	dev_dbg(otg->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);
>> +		otg_drv_vbus(otg, 0);
>> +		break;
>> +	case OTG_STATE_B_PERIPHERAL:
>> +		drd_set_protocol(fsm, PROTO_GADGET);
>> +		otg_drv_vbus(otg, 0);
>> +		break;
>> +	case OTG_STATE_A_HOST:
>> +		drd_set_protocol(fsm, PROTO_HOST);
>> +		otg_drv_vbus(otg, 1);
>> +		break;
>> +	default:
>> +		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
>> +			 __func__, usb_otg_state_string(new_state));
>> +		break;
>> +	}
>> +
>> +	otg->state = new_state;
>> +}
>> +
>> +/**
>> + * drd_statemachine() - DRD state change judgement
>> + * @otg:	usb_otg instance
>> + *
>> + * Checks the state machine inputs and state and makes a state change
>> + * if required.
>> + *
>> + * 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
>> + *
>> + * Return: 0 if state wasn't changed, 1 if state changed.
>> + */
>> +int drd_statemachine(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +	enum usb_otg_state state;
>> +	int ret;
>> +
>> +	mutex_lock(&fsm->lock);
>> +
>> +	fsm->state_changed = 0;
>> +	state = 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;
>> +
>> +	default:
>> +		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
>> +			__func__, usb_otg_state_string(state));
>> +		break;
>> +	}
>> +
>> +	ret = fsm->state_changed;
>> +	mutex_unlock(&fsm->lock);
>> +	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
>> +		fsm->state_changed);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(drd_statemachine);
> 
> why is this exported at all? It only runs from the work_struct

You're right. It shouldn't be exported.

> below. BTW, that work_struct looks unnecessary.

why? The kick could be triggered from an interrupt context. e.g. otg_irq.

> 
>> +
>> +/**
>> + * usb_drd_work() - Dual-role state machine work function
>> + * @work: work_struct context
>> + *
>> + * Runs the DRD state machine. Scheduled whenever there is a change
>> + * in FSM inputs.
>> + */
>> +static void usb_drd_work(struct work_struct *work)
>> +{
>> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
>> +
>> +	pm_runtime_get_sync(otg->dev);
>> +	while (drd_statemachine(otg))
>> +		;
>> +	pm_runtime_put_sync(otg->dev);
> 
> so, once this gets kicked it'll keep on running until a state doesn't
> change.

yes.
> 
>> +}
>> +
>> +/**
>> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
>> + * @dev: OTG/dual-role controller device.
>> + * @config: OTG configuration.
>> + *
>> + * Registers the OTG/dual-role controller device with the USB OTG core.
>> + *
>> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
>> + */
>> +struct usb_otg *usb_otg_register(struct device *dev,
>> +				 struct usb_otg_config *config)
>> +{
>> +	struct usb_otg *otg;
>> +	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 */
>> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
>> +	if (!otg) {
>> +		ret = -ENOMEM;
>> +		goto unlock;
>> +	}
>> +
>> +	otg->dev = dev;
>> +	/* otg->caps is controller caps + DT overrides */
>> +	otg->caps = *config->otg_caps;
>> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
>> +	if (ret)
>> +		goto err_wq;
>> +
>> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
>> +	     otg->caps.adp_support) && !config->otg_work) {
>> +		dev_err(dev,
>> +			"otg: otg_work must be provided for OTG support\n");
>> +		ret = -EINVAL;
>> +		goto err_wq;
>> +	}
>> +
>> +	if (config->otg_work)	/* custom otg_work ? */
>> +		INIT_WORK(&otg->work, config->otg_work);
>> +	else
>> +		INIT_WORK(&otg->work, usb_drd_work);
> 
> why do you need to cope with custom work handlers?

It was just a provision to provide your own state machine if the generic
one does not meet your needs. But i'm OK to get rid of it as well.

Maybe Peter can chime in.

> 
>> +	otg->wq = create_freezable_workqueue("usb_otg");
>> +	if (!otg->wq) {
>> +		dev_err(dev, "otg: %s: can't create workqueue\n",
>> +			__func__);
>> +		ret = -ENOMEM;
>> +		goto err_wq;
>> +	}
>> +
>> +	/* set otg ops */
>> +	otg->fsm.ops = config->fsm_ops;
>> +
>> +	mutex_init(&otg->fsm.lock);
>> +
>> +	list_add_tail(&otg->list, &otg_list);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	return otg;
>> +
>> +err_wq:
>> +	kfree(otg);
>> +unlock:
>> +	mutex_unlock(&otg_list_mutex);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register);
>> +
>> +/**
>> + * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
>> + * @dev: OTG controller device.
>> + *
>> + * Unregisters the OTG/dual-role 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 *otg;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(dev);
>> +	if (!otg) {
>> +		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 (otg->host || otg->gadget) {
>> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
>> +			__func__);
>> +		mutex_unlock(&otg_list_mutex);
>> +		return -EBUSY;
>> +	}
> 
> I think a better choice would've been to unregister host and gadget in
> case they haven't been unregistered yet. That's a common
> expectation. Specially since driver core does the same thing when you
> unregister a parent device.

I agree.

> 
>> +	/* OTG FSM is halted when host/gadget unregistered */
>> +	destroy_workqueue(otg->wq);
>> +
>> +	/* remove from otg list */
>> +	list_del(&otg->list);
>> +	kfree(otg);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
>> +
>> +/**
>> + * usb_otg_start_fsm() - Start the OTG FSM
>> + * @otg:	usb_otg instance
>> + *
>> + * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
>> + * must be ready for the OTG FSM to start.
>> + *
>> + * fsm->lock must be held.
>> + */
>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +
>> +	if (fsm->running)
>> +		goto kick_fsm;
>> +
>> +	if (!otg->host) {
>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>> +		return;
>> +	}
>> +
>> +	if (!otg->gadget) {
>> +		dev_info(otg->dev,
>> +			 "otg: can't start till gadget UDC registers\n");
>> +		return;
>> +	}
> 
> okay, so you never kick the FSM until host and gadget are
> registered. Why do you need to test for the case where the FSM is
> running without host/gadget?

That message in the test was misleading. It could also be a
used as a warning if users did something wrong.
> 
> You seem to guarantee that will never be the case.
> 
>> +	if (!otg->gadget_ready) {
>> +		dev_info(otg->dev,
>> +			 "otg: can't start till gadget function registers\n");
>> +		return;
>> +	}
>> +
>> +	fsm->running = true;
>> +kick_fsm:
>> +	queue_work(otg->wq, &otg->work);
>> +}
>> +
>> +/**
>> + * usb_otg_stop_fsm() - Stop the OTG FSM
>> + * @otg:	usb_otg instance
>> + *
>> + * Stops the HCD, UDC and the OTG FSM.
>> + *
>> + * fsm->lock must be held.
>> + */
>> +static void usb_otg_stop_fsm(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +
>> +	if (!fsm->running)
>> +		return;
>> +
>> +	/* no more new events queued */
>> +	fsm->running = false;
>> +
>> +	flush_workqueue(otg->wq);
>> +	otg->state = OTG_STATE_UNDEFINED;
>> +
>> +	/* stop host/gadget immediately */
>> +	if (fsm->protocol == PROTO_HOST) {
>> +		otg_start_host(otg, 0);
>> +	} else if (fsm->protocol == PROTO_GADGET) {
>> +		otg->gadget_ops->connect_control(otg->gadget, false);
>> +		otg_start_gadget(otg, 0);
>> +	}
>> +	fsm->protocol = PROTO_UNDEF;
>> +}
>> +
>> +/**
>> + * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
>> + * @otg:	usb_otg 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 usb_otg *otg)
>> +{
>> +	/* Don't kick FSM till it has started */
>> +	if (!otg->fsm.running)
>> +		return;
>> +
>> +	/* Kick FSM */
>> +	queue_work(otg->wq, &otg->work);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
>> +
>> +/**
>> + * usb_otg_register_hcd() - Register the host controller to OTG core
>> + * @hcd:	host controller
>> + * @irqnum:	interrupt number
>> + * @irqflags:	interrupt flags
>> + * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
>> + * hcd->otg_dev must contain the related otg controller device.
>> + *
>> + * Return: 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 *otg;
>> +	struct device *hcd_dev = hcd->self.controller;
>> +	struct device *otg_dev = hcd->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(hcd_dev,
>> +			"otg: controller not yet registered. deferring.\n");
>> +		return -EPROBE_DEFER;
>> +	}
>> +
>> +	/* HCD will be started by OTG fsm when needed */
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->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 == otg->primary_hcd.hcd) {
>> +			if (otg->shared_hcd.hcd) {
>> +				dev_err(otg_dev, "otg: shared host already registered\n");
>> +				goto err;
>> +			}
>> +
>> +			otg->shared_hcd.hcd = hcd;
>> +			otg->shared_hcd.irqnum = irqnum;
>> +			otg->shared_hcd.irqflags = irqflags;
>> +			otg->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;
>> +		}
>> +
>> +		otg->primary_hcd.hcd = hcd;
>> +		otg->primary_hcd.irqnum = irqnum;
>> +		otg->primary_hcd.irqflags = irqflags;
>> +		otg->primary_hcd.ops = ops;
>> +		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
>> +		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(otg);
>> +	} else {
>> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
>> +	}
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +
>> +err:
>> +	mutex_unlock(&otg->fsm.lock);
>> +	return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
>> +
>> +/**
>> + * usb_otg_unregister_hcd() - Unregister the 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 *otg;
>> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
>> +	struct device *otg_dev = hcd->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (hcd == otg->primary_hcd.hcd) {
>> +		otg->primary_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else if (hcd == otg->shared_hcd.hcd) {
>> +		otg->shared_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* stop FSM & Host */
>> +	usb_otg_stop_fsm(otg);
>> +	otg->host = NULL;
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
>> +
>> +/**
>> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
>> + * @gadget:	gadget controller instance
>> + * @ops:	gadget interface ops
>> + *
>> + * 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 up to the OTG state machine to do so.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops)
>> +{
>> +	struct usb_otg *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_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);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(gadget_dev,
>> +			"otg: controller not yet registered, deferring.\n");
>> +		return -EPROBE_DEFER;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget) {
>> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
>> +		mutex_unlock(&otg->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	otg->gadget = gadget;
>> +	otg->gadget_ops = ops;
>> +	dev_info(otg_dev, "otg: gadget %s registered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	/* FSM will be started in usb_otg_gadget_ready() */
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
>> +
>> +/**
>> + * usb_otg_unregister_gadget() - Unregister the 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 *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(gadget_dev,
>> +			"otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget != gadget) {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* FSM must be stopped in usb_otg_gadget_ready() */
>> +	if (otg->gadget_ready) {
>> +		dev_err(otg_dev,
>> +			"otg: gadget %s unregistered before being unready, forcing stop\n",
>> +			dev_name(&gadget->dev));
>> +		usb_otg_stop_fsm(otg);
>> +	}
>> +
>> +	otg->gadget = NULL;
>> +	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
>> + * @gadget:	gadget controller
>> + * @ready:	0: function driver ready, 1: function driver not ready
>> + *
>> + * Notify the OTG core about status of the gadget function driver.
>> + * As OTG core is responsible to start/stop the gadget controller, it
>> + * must be aware when the gadget function driver is available or not.
>> + * This function is used by the Gadget core to inform the OTG core
>> + * about the gadget function driver readyness.
>> + *
>> + * Return: 0 on sucess, error value otherwise.
>> + */
>> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
>> +{
>> +	struct usb_otg *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(gadget_dev,
>> +			"otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget != gadget) {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Start/stop FSM & gadget */
>> +	otg->gadget_ready = ready;
>> +	if (ready)
>> +		usb_otg_start_fsm(otg);
>> +	else
>> +		usb_otg_stop_fsm(otg);
>> +
>> +	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
>> +		ready ? "" : "not ");
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
>> +
>> +MODULE_LICENSE("GPL");
> 
> GPL or GPL 2-only?

GPL v2.

> 
>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> index f4fc0aa..1d74fb8 100644
>> --- a/include/linux/usb/gadget.h
>> +++ b/include/linux/usb/gadget.h
>> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>>   * @in_epnum: last used in ep number
>>   * @mA: last set mA value
>>   * @otg_caps: OTG capabilities of this gadget.
>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> 
> do you really know of any platform which has a separate OTG controller?
> 

Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
and gadget.

[1] http://article.gmane.org/gmane.linux.ports.tegra/22969

Yoshihiro,

How is the dual-role architecture on your Renesas platform?

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 10:13         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20 10:13 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA


[-- Attachment #1.1: Type: text/plain, Size: 32488 bytes --]

Hi,

On 20/06/16 10:45, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
> 
> I think I have already mentioned this, but after over 10 years of OTG,
> nobody seems to care about it, why are we still touching at all I don't
> know. For common non-OTG role-swapping we really don't need any of this
> and, quite frankly, I fail to see enough users for this.
> 
> Apparently there's only chipidea which, AFAICT, already had working
> dual-role before this OTG State Machine was added to the kernel.
> 
>> Provide a dual-role device (DRD) state machine.
> 
> there's not such thing as DRD state machine. You don't need to go
> through all these states, actually.

There are 3 states though.
HOST (id = 0)
PERIPHERAL (id = 1, vbus = 1)
IDLE (id = 1, vbus = 0).

> 
>> 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-l0cyMroinI0@public.gmane.org>
>> ---
>> v11:
>> - remove usb_otg_kick_fsm().
>> - typo fixes: structa/structure, upto/up to.
>> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>>
>>  drivers/usb/Kconfig          |  18 +
>>  drivers/usb/common/Makefile  |   6 +-
>>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>>  drivers/usb/core/Kconfig     |  14 -
>>  drivers/usb/gadget/Kconfig   |   1 +
>>  include/linux/usb/gadget.h   |   2 +
>>  include/linux/usb/hcd.h      |   1 +
>>  include/linux/usb/otg-fsm.h  |   7 +
>>  include/linux/usb/otg.h      | 174 ++++++++-
>>  9 files changed, 1070 insertions(+), 30 deletions(-)
>>  create mode 100644 drivers/usb/common/usb-otg.c
>>
>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>> index 8689dcb..ed596ec 100644
>> --- a/drivers/usb/Kconfig
>> +++ b/drivers/usb/Kconfig
>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>  config USB_COMMON
>>  	tristate
>>  
>> +config USB_OTG_CORE
>> +	tristate
> 
> why tristate if you can never set it to 'M'?

This gets internally set to M if either USB or GADGET is M.
We select it in USB and GADGET.
This was the only way I could get usb-otg.c to build as

m if USB OR GADGET is m
built-in if USB and GADGET are built in.

> 
>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>> new file mode 100644
>> index 0000000..a23ab1e
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.c
>> @@ -0,0 +1,877 @@
>> +/**
>> + * drivers/usb/common/usb-otg.c - USB OTG core
>> + *
>> + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
>> + * Author: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
>> + *
>> + * 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/list.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/usb/of.h>
>> +#include <linux/usb/otg.h>
>> +#include <linux/usb/gadget.h>
>> +#include <linux/workqueue.h>
>> +
>> +/* OTG device list */
>> +LIST_HEAD(otg_list);
> 
> not static? Who needs to touch this private list?

right, it should be static.

> 
>> +static DEFINE_MUTEX(otg_list_mutex);
>> +
>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>> +{
>> +	if (!hcd->primary_hcd)
>> +		return 1;
> 
> these seems inverted. If hcd->primary is NULL (meaning, there's no
> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
> to explain?

hcd->primary_hcd is a link used by the shared hcd to point to the primary_hcd.
primary_hcd's have this link as NULL.

> 
>> +	return hcd == hcd->primary_hcd;
>> +}
>> +
>> +/**
>> + * usb_otg_get_data() - get usb_otg data structure
>> + * @otg_dev:	OTG controller device
>> + *
>> + * Check if the OTG device is in our OTG list and return
>> + * usb_otg data, else NULL.
>> + *
>> + * otg_list_mutex must be held.
>> + *
>> + * Return: usb_otg data on success, NULL otherwise.
>> + */
>> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
>> +{
>> +	struct usb_otg *otg;
>> +
>> +	if (!otg_dev)
>> +		return NULL;
>> +
>> +	list_for_each_entry(otg, &otg_list, list) {
>> +		if (otg->dev == otg_dev)
>> +			return otg;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +/**
>> + * usb_otg_start_host() - start/stop the host controller
>> + * @otg:	usb_otg instance
>> + * @on:		true to start, false to stop
>> + *
>> + * Start/stop the USB host controller. This function is meant
>> + * for use by the OTG controller driver.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>> +{
>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>> +	int ret;
>> +
>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>> +	if (!otg->host) {
>> +		WARN_ONCE(1, "otg: fsm running without host\n");
> 
> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
> 	return 0;
> 
> but, frankly, if you require a 'host' and a 'gadget' don't start this
> layer until you have both.

We don't start the layer till we have both host and gadget. But
this API is for external use and might be called at any time.

I could change the warning message to
 
if (WARN_ONCE(!otg->host, "otg: %s called in invalid context\n", __func__))
	return 0;

> 
>> +		return 0;
>> +	}
>> +
>> +	if (on) {
>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>> +			return 0;
>> +
>> +		/* start host */
>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> +				   otg->primary_hcd.irqnum,
>> +				   otg->primary_hcd.irqflags);
> 
> this is usb_add_hcd(), is it not? Why add an indirection?

I've introduced the host and gadget ops interface to get around the
circular dependency issue we can't avoid.
otg needs to call host/gadget functions and host/gadget also needs to
call otg functions.

> 
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: host add failed %d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		if (otg->shared_hcd.hcd) {
>> +			ret = hcd_ops->add(otg->shared_hcd.hcd,
>> +					   otg->shared_hcd.irqnum,
>> +					   otg->shared_hcd.irqflags);
>> +			if (ret) {
>> +				dev_err(otg->dev, "otg: shared host add failed %d\n",
>> +					ret);
>> +				hcd_ops->remove(otg->primary_hcd.hcd);
>> +				return ret;
>> +			}
>> +		}
>> +		otg->flags |= OTG_FLAG_HOST_RUNNING;
>> +	} else {
>> +		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
>> +			return 0;
>> +
>> +		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
>> +
>> +		/* stop host */
>> +		if (otg->shared_hcd.hcd)
>> +			hcd_ops->remove(otg->shared_hcd.hcd);
> 
> usb_del_hcd()?
> 
>> +		hcd_ops->remove(otg->primary_hcd.hcd);
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_host);
>> +
>> +/**
>> + * usb_otg_start_gadget() - start/stop the gadget controller
>> + * @otg:	usb_otg instance
>> + * @on:		true to start, false to stop
>> + *
>> + * Start/stop the USB gadget controller. This function is meant
>> + * for use by the OTG controller driver.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_start_gadget(struct usb_otg *otg, int on)
>> +{
>> +	struct usb_gadget *gadget = otg->gadget;
>> +	int ret;
>> +
>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>> +	if (!gadget) {
>> +		WARN_ONCE(1, "otg: fsm running without gadget\n");
>> +		return 0;
>> +	}
> 
> ditto

I'll fix up the message to

("otg: %s called in invalid context\n", __func__)

> 
>> +	if (on) {
>> +		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
>> +			return 0;
>> +
>> +		ret = otg->gadget_ops->start(otg->gadget);
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: gadget start failed: %d\n",
>> +				ret);
>> +			return ret;
>> +		}
>> +
>> +		otg->flags |= OTG_FLAG_GADGET_RUNNING;
>> +	} else {
>> +		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
>> +			return 0;
>> +
>> +		ret = otg->gadget_ops->stop(otg->gadget);
>> +		if (ret) {
>> +			dev_err(otg->dev, "otg: gadget stop failed: %d\n",
>> +				ret);
>> +			return ret;
>> +		}
>> +		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
>> +
>> +/**
>> + * drd_set_protocol() -  Set USB protocol if possible
>> + * @fsm:	DRD FSM instance
>> + * @protocol:	USB protocol to set the state machine to
>> + *
>> + * Sets the OTG FSM protocol to @protocol if it changed.
>> + * fsm->lock must be held.
>> + *
>> + * Return: 0 on success, error value otherwise.
>> + */
>> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
>> +{
>> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
>> +	int ret = 0;
>> +
>> +	if (fsm->protocol != protocol) {
>> +		dev_dbg(otg->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(otg, 0);
>> +		} else if (fsm->protocol == PROTO_GADGET) {
>> +			otg->gadget_ops->connect_control(otg->gadget, false);
>> +			ret = otg_start_gadget(otg, 0);
>> +		}
>> +
>> +		if (ret)
>> +			return ret;
>> +
>> +		/* start new protocol */
>> +		if (protocol == PROTO_HOST) {
>> +			ret = otg_start_host(otg, 1);
>> +		} else if (protocol == PROTO_GADGET) {
>> +			ret = otg_start_gadget(otg, 1);
>> +			otg->gadget_ops->connect_control(otg->gadget, true);
>> +		}
>> +
>> +		if (ret)
>> +			return ret;
>> +
>> +		fsm->protocol = protocol;
>> +		return 0;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * drd_set_state() - Set the DRD state machine state.
>> + * @fsm:	DRD FSM instance
>> + * @new_state:	the new state the DRD FSM must be set to
>> + *
>> + * Sets the state of the DRD state machine.
>> + * fsm->lock must be held.
>> + */
>> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>> +{
>> +	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
>> +
>> +	if (otg->state == new_state)
>> +		return;
>> +
>> +	fsm->state_changed = 1;
>> +	dev_dbg(otg->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);
>> +		otg_drv_vbus(otg, 0);
>> +		break;
>> +	case OTG_STATE_B_PERIPHERAL:
>> +		drd_set_protocol(fsm, PROTO_GADGET);
>> +		otg_drv_vbus(otg, 0);
>> +		break;
>> +	case OTG_STATE_A_HOST:
>> +		drd_set_protocol(fsm, PROTO_HOST);
>> +		otg_drv_vbus(otg, 1);
>> +		break;
>> +	default:
>> +		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
>> +			 __func__, usb_otg_state_string(new_state));
>> +		break;
>> +	}
>> +
>> +	otg->state = new_state;
>> +}
>> +
>> +/**
>> + * drd_statemachine() - DRD state change judgement
>> + * @otg:	usb_otg instance
>> + *
>> + * Checks the state machine inputs and state and makes a state change
>> + * if required.
>> + *
>> + * 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
>> + *
>> + * Return: 0 if state wasn't changed, 1 if state changed.
>> + */
>> +int drd_statemachine(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +	enum usb_otg_state state;
>> +	int ret;
>> +
>> +	mutex_lock(&fsm->lock);
>> +
>> +	fsm->state_changed = 0;
>> +	state = 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;
>> +
>> +	default:
>> +		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
>> +			__func__, usb_otg_state_string(state));
>> +		break;
>> +	}
>> +
>> +	ret = fsm->state_changed;
>> +	mutex_unlock(&fsm->lock);
>> +	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
>> +		fsm->state_changed);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(drd_statemachine);
> 
> why is this exported at all? It only runs from the work_struct

You're right. It shouldn't be exported.

> below. BTW, that work_struct looks unnecessary.

why? The kick could be triggered from an interrupt context. e.g. otg_irq.

> 
>> +
>> +/**
>> + * usb_drd_work() - Dual-role state machine work function
>> + * @work: work_struct context
>> + *
>> + * Runs the DRD state machine. Scheduled whenever there is a change
>> + * in FSM inputs.
>> + */
>> +static void usb_drd_work(struct work_struct *work)
>> +{
>> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
>> +
>> +	pm_runtime_get_sync(otg->dev);
>> +	while (drd_statemachine(otg))
>> +		;
>> +	pm_runtime_put_sync(otg->dev);
> 
> so, once this gets kicked it'll keep on running until a state doesn't
> change.

yes.
> 
>> +}
>> +
>> +/**
>> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
>> + * @dev: OTG/dual-role controller device.
>> + * @config: OTG configuration.
>> + *
>> + * Registers the OTG/dual-role controller device with the USB OTG core.
>> + *
>> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
>> + */
>> +struct usb_otg *usb_otg_register(struct device *dev,
>> +				 struct usb_otg_config *config)
>> +{
>> +	struct usb_otg *otg;
>> +	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 */
>> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
>> +	if (!otg) {
>> +		ret = -ENOMEM;
>> +		goto unlock;
>> +	}
>> +
>> +	otg->dev = dev;
>> +	/* otg->caps is controller caps + DT overrides */
>> +	otg->caps = *config->otg_caps;
>> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
>> +	if (ret)
>> +		goto err_wq;
>> +
>> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
>> +	     otg->caps.adp_support) && !config->otg_work) {
>> +		dev_err(dev,
>> +			"otg: otg_work must be provided for OTG support\n");
>> +		ret = -EINVAL;
>> +		goto err_wq;
>> +	}
>> +
>> +	if (config->otg_work)	/* custom otg_work ? */
>> +		INIT_WORK(&otg->work, config->otg_work);
>> +	else
>> +		INIT_WORK(&otg->work, usb_drd_work);
> 
> why do you need to cope with custom work handlers?

It was just a provision to provide your own state machine if the generic
one does not meet your needs. But i'm OK to get rid of it as well.

Maybe Peter can chime in.

> 
>> +	otg->wq = create_freezable_workqueue("usb_otg");
>> +	if (!otg->wq) {
>> +		dev_err(dev, "otg: %s: can't create workqueue\n",
>> +			__func__);
>> +		ret = -ENOMEM;
>> +		goto err_wq;
>> +	}
>> +
>> +	/* set otg ops */
>> +	otg->fsm.ops = config->fsm_ops;
>> +
>> +	mutex_init(&otg->fsm.lock);
>> +
>> +	list_add_tail(&otg->list, &otg_list);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	return otg;
>> +
>> +err_wq:
>> +	kfree(otg);
>> +unlock:
>> +	mutex_unlock(&otg_list_mutex);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register);
>> +
>> +/**
>> + * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
>> + * @dev: OTG controller device.
>> + *
>> + * Unregisters the OTG/dual-role 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 *otg;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(dev);
>> +	if (!otg) {
>> +		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 (otg->host || otg->gadget) {
>> +		dev_err(dev, "otg: %s: host/gadget still registered\n",
>> +			__func__);
>> +		mutex_unlock(&otg_list_mutex);
>> +		return -EBUSY;
>> +	}
> 
> I think a better choice would've been to unregister host and gadget in
> case they haven't been unregistered yet. That's a common
> expectation. Specially since driver core does the same thing when you
> unregister a parent device.

I agree.

> 
>> +	/* OTG FSM is halted when host/gadget unregistered */
>> +	destroy_workqueue(otg->wq);
>> +
>> +	/* remove from otg list */
>> +	list_del(&otg->list);
>> +	kfree(otg);
>> +	mutex_unlock(&otg_list_mutex);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister);
>> +
>> +/**
>> + * usb_otg_start_fsm() - Start the OTG FSM
>> + * @otg:	usb_otg instance
>> + *
>> + * Start the OTG FSM if we can. The HCD, UDC and gadget function driver
>> + * must be ready for the OTG FSM to start.
>> + *
>> + * fsm->lock must be held.
>> + */
>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +
>> +	if (fsm->running)
>> +		goto kick_fsm;
>> +
>> +	if (!otg->host) {
>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>> +		return;
>> +	}
>> +
>> +	if (!otg->gadget) {
>> +		dev_info(otg->dev,
>> +			 "otg: can't start till gadget UDC registers\n");
>> +		return;
>> +	}
> 
> okay, so you never kick the FSM until host and gadget are
> registered. Why do you need to test for the case where the FSM is
> running without host/gadget?

That message in the test was misleading. It could also be a
used as a warning if users did something wrong.
> 
> You seem to guarantee that will never be the case.
> 
>> +	if (!otg->gadget_ready) {
>> +		dev_info(otg->dev,
>> +			 "otg: can't start till gadget function registers\n");
>> +		return;
>> +	}
>> +
>> +	fsm->running = true;
>> +kick_fsm:
>> +	queue_work(otg->wq, &otg->work);
>> +}
>> +
>> +/**
>> + * usb_otg_stop_fsm() - Stop the OTG FSM
>> + * @otg:	usb_otg instance
>> + *
>> + * Stops the HCD, UDC and the OTG FSM.
>> + *
>> + * fsm->lock must be held.
>> + */
>> +static void usb_otg_stop_fsm(struct usb_otg *otg)
>> +{
>> +	struct otg_fsm *fsm = &otg->fsm;
>> +
>> +	if (!fsm->running)
>> +		return;
>> +
>> +	/* no more new events queued */
>> +	fsm->running = false;
>> +
>> +	flush_workqueue(otg->wq);
>> +	otg->state = OTG_STATE_UNDEFINED;
>> +
>> +	/* stop host/gadget immediately */
>> +	if (fsm->protocol == PROTO_HOST) {
>> +		otg_start_host(otg, 0);
>> +	} else if (fsm->protocol == PROTO_GADGET) {
>> +		otg->gadget_ops->connect_control(otg->gadget, false);
>> +		otg_start_gadget(otg, 0);
>> +	}
>> +	fsm->protocol = PROTO_UNDEF;
>> +}
>> +
>> +/**
>> + * usb_otg_sync_inputs() - Sync OTG inputs with the OTG state machine
>> + * @otg:	usb_otg 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 usb_otg *otg)
>> +{
>> +	/* Don't kick FSM till it has started */
>> +	if (!otg->fsm.running)
>> +		return;
>> +
>> +	/* Kick FSM */
>> +	queue_work(otg->wq, &otg->work);
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
>> +
>> +/**
>> + * usb_otg_register_hcd() - Register the host controller to OTG core
>> + * @hcd:	host controller
>> + * @irqnum:	interrupt number
>> + * @irqflags:	interrupt flags
>> + * @ops:	HCD ops to interface with 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 up to the OTG state machine to do so.
>> + * hcd->otg_dev must contain the related otg controller device.
>> + *
>> + * Return: 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 *otg;
>> +	struct device *hcd_dev = hcd->self.controller;
>> +	struct device *otg_dev = hcd->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	/* we're otg but otg controller might not yet be registered */
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(hcd_dev,
>> +			"otg: controller not yet registered. deferring.\n");
>> +		return -EPROBE_DEFER;
>> +	}
>> +
>> +	/* HCD will be started by OTG fsm when needed */
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->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 == otg->primary_hcd.hcd) {
>> +			if (otg->shared_hcd.hcd) {
>> +				dev_err(otg_dev, "otg: shared host already registered\n");
>> +				goto err;
>> +			}
>> +
>> +			otg->shared_hcd.hcd = hcd;
>> +			otg->shared_hcd.irqnum = irqnum;
>> +			otg->shared_hcd.irqflags = irqflags;
>> +			otg->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;
>> +		}
>> +
>> +		otg->primary_hcd.hcd = hcd;
>> +		otg->primary_hcd.irqnum = irqnum;
>> +		otg->primary_hcd.irqflags = irqflags;
>> +		otg->primary_hcd.ops = ops;
>> +		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
>> +		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(otg);
>> +	} else {
>> +		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
>> +	}
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +
>> +err:
>> +	mutex_unlock(&otg->fsm.lock);
>> +	return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
>> +
>> +/**
>> + * usb_otg_unregister_hcd() - Unregister the 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 *otg;
>> +	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
>> +	struct device *otg_dev = hcd->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;	/* we're definitely not OTG */
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (hcd == otg->primary_hcd.hcd) {
>> +		otg->primary_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: primary host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else if (hcd == otg->shared_hcd.hcd) {
>> +		otg->shared_hcd.hcd = NULL;
>> +		dev_info(otg_dev, "otg: shared host %s unregistered\n",
>> +			 dev_name(hcd_dev));
>> +	} else {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
>> +			dev_name(hcd_dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* stop FSM & Host */
>> +	usb_otg_stop_fsm(otg);
>> +	otg->host = NULL;
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
>> +
>> +/**
>> + * usb_otg_register_gadget() - Register the gadget controller to OTG core
>> + * @gadget:	gadget controller instance
>> + * @ops:	gadget interface ops
>> + *
>> + * 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 up to the OTG state machine to do so.
>> + *
>> + * Returns: 0 on success, error value otherwise.
>> + */
>> +int usb_otg_register_gadget(struct usb_gadget *gadget,
>> +			    struct otg_gadget_ops *ops)
>> +{
>> +	struct usb_otg *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_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);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_dbg(gadget_dev,
>> +			"otg: controller not yet registered, deferring.\n");
>> +		return -EPROBE_DEFER;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget) {
>> +		dev_err(otg_dev, "otg: gadget already registered with otg\n");
>> +		mutex_unlock(&otg->fsm.lock);
>> +		return -EINVAL;
>> +	}
>> +
>> +	otg->gadget = gadget;
>> +	otg->gadget_ops = ops;
>> +	dev_info(otg_dev, "otg: gadget %s registered\n",
>> +		 dev_name(&gadget->dev));
>> +
>> +	/* FSM will be started in usb_otg_gadget_ready() */
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
>> +
>> +/**
>> + * usb_otg_unregister_gadget() - Unregister the 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 *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(gadget_dev,
>> +			"otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget != gadget) {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* FSM must be stopped in usb_otg_gadget_ready() */
>> +	if (otg->gadget_ready) {
>> +		dev_err(otg_dev,
>> +			"otg: gadget %s unregistered before being unready, forcing stop\n",
>> +			dev_name(&gadget->dev));
>> +		usb_otg_stop_fsm(otg);
>> +	}
>> +
>> +	otg->gadget = NULL;
>> +	mutex_unlock(&otg->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_gadget_ready() - Notify gadget function driver ready status
>> + * @gadget:	gadget controller
>> + * @ready:	0: function driver ready, 1: function driver not ready
>> + *
>> + * Notify the OTG core about status of the gadget function driver.
>> + * As OTG core is responsible to start/stop the gadget controller, it
>> + * must be aware when the gadget function driver is available or not.
>> + * This function is used by the Gadget core to inform the OTG core
>> + * about the gadget function driver readyness.
>> + *
>> + * Return: 0 on sucess, error value otherwise.
>> + */
>> +int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
>> +{
>> +	struct usb_otg *otg;
>> +	struct device *gadget_dev = &gadget->dev;
>> +	struct device *otg_dev = gadget->otg_dev;
>> +
>> +	if (!otg_dev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&otg_list_mutex);
>> +	otg = usb_otg_get_data(otg_dev);
>> +	mutex_unlock(&otg_list_mutex);
>> +	if (!otg) {
>> +		dev_err(gadget_dev,
>> +			"otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	mutex_lock(&otg->fsm.lock);
>> +	if (otg->gadget != gadget) {
>> +		mutex_unlock(&otg->fsm.lock);
>> +		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
>> +			dev_name(&gadget->dev));
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Start/stop FSM & gadget */
>> +	otg->gadget_ready = ready;
>> +	if (ready)
>> +		usb_otg_start_fsm(otg);
>> +	else
>> +		usb_otg_stop_fsm(otg);
>> +
>> +	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
>> +		ready ? "" : "not ");
>> +
>> +	mutex_unlock(&otg->fsm.lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
>> +
>> +MODULE_LICENSE("GPL");
> 
> GPL or GPL 2-only?

GPL v2.

> 
>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> index f4fc0aa..1d74fb8 100644
>> --- a/include/linux/usb/gadget.h
>> +++ b/include/linux/usb/gadget.h
>> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>>   * @in_epnum: last used in ep number
>>   * @mA: last set mA value
>>   * @otg_caps: OTG capabilities of this gadget.
>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> 
> do you really know of any platform which has a separate OTG controller?
> 

Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
and gadget.

[1] http://article.gmane.org/gmane.linux.ports.tegra/22969

Yoshihiro,

How is the dual-role architecture on your Renesas platform?

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 11:49         ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-20 11:49 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

On Mon, Jun 20, 2016 at 10:45:31AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
> > It provides APIs for the following tasks
> >
> > - Registering an OTG/dual-role capable controller
> > - Registering Host and Gadget controllers to OTG core
> > - Providing inputs to and kicking the OTG state machine
> 
> I think I have already mentioned this, but after over 10 years of OTG,
> nobody seems to care about it, why are we still touching at all I don't
> know. For common non-OTG role-swapping we really don't need any of this
> and, quite frankly, I fail to see enough users for this.
> 
> Apparently there's only chipidea which, AFAICT, already had working
> dual-role before this OTG State Machine was added to the kernel.

Some users would like to know if vendor's platform is OTG compliance,
so we add it to pass usb.org USB OTG certification test.

For the real use case, some Carplay platforms need it.

> 
> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> > index f4fc0aa..1d74fb8 100644
> > --- a/include/linux/usb/gadget.h
> > +++ b/include/linux/usb/gadget.h
> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >   * @in_epnum: last used in ep number
> >   * @mA: last set mA value
> >   * @otg_caps: OTG capabilities of this gadget.
> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> 
> do you really know of any platform which has a separate OTG controller?
> 

It may not be a real separate OTG controller. It can be a hardware part
(external connector, external IC, SoC OTG register area, etc) to handle vbus
,id and other signals which are used for role swap.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 11:49         ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-20 11:49 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Mon, Jun 20, 2016 at 10:45:31AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
> > It provides APIs for the following tasks
> >
> > - Registering an OTG/dual-role capable controller
> > - Registering Host and Gadget controllers to OTG core
> > - Providing inputs to and kicking the OTG state machine
> 
> I think I have already mentioned this, but after over 10 years of OTG,
> nobody seems to care about it, why are we still touching at all I don't
> know. For common non-OTG role-swapping we really don't need any of this
> and, quite frankly, I fail to see enough users for this.
> 
> Apparently there's only chipidea which, AFAICT, already had working
> dual-role before this OTG State Machine was added to the kernel.

Some users would like to know if vendor's platform is OTG compliance,
so we add it to pass usb.org USB OTG certification test.

For the real use case, some Carplay platforms need it.

> 
> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> > index f4fc0aa..1d74fb8 100644
> > --- a/include/linux/usb/gadget.h
> > +++ b/include/linux/usb/gadget.h
> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >   * @in_epnum: last used in ep number
> >   * @mA: last set mA value
> >   * @otg_caps: OTG capabilities of this gadget.
> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> 
> do you really know of any platform which has a separate OTG controller?
> 

It may not be a real separate OTG controller. It can be a hardware part
(external connector, external IC, SoC OTG register area, etc) to handle vbus
,id and other signals which are used for role swap.

-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-20 10:13         ` Roger Quadros
  (?)
@ 2016-06-20 12:03         ` Felipe Balbi
  2016-06-20 12:26             ` Roger Quadros
  2016-06-21  6:39           ` Peter Chen
  -1 siblings, 2 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20 12:03 UTC (permalink / raw)
  To: Roger Quadros, peter.chen, yoshihiro.shimoda.uh
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 13540 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
>> Roger Quadros <rogerq@ti.com> writes:
>>> It provides APIs for the following tasks
>>>
>>> - Registering an OTG/dual-role capable controller
>>> - Registering Host and Gadget controllers to OTG core
>>> - Providing inputs to and kicking the OTG state machine
>> 
>> I think I have already mentioned this, but after over 10 years of OTG,
>> nobody seems to care about it, why are we still touching at all I don't
>> know. For common non-OTG role-swapping we really don't need any of this
>> and, quite frankly, I fail to see enough users for this.
>> 
>> Apparently there's only chipidea which, AFAICT, already had working
>> dual-role before this OTG State Machine was added to the kernel.
>> 
>>> Provide a dual-role device (DRD) state machine.
>> 
>> there's not such thing as DRD state machine. You don't need to go
>> through all these states, actually.
>
> There are 3 states though.
> HOST (id = 0)
> PERIPHERAL (id = 1, vbus = 1)
> IDLE (id = 1, vbus = 0).

IDLE is pretty much given, though ;-)

>>> 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>
>>> ---
>>> v11:
>>> - remove usb_otg_kick_fsm().
>>> - typo fixes: structa/structure, upto/up to.
>>> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>>>
>>>  drivers/usb/Kconfig          |  18 +
>>>  drivers/usb/common/Makefile  |   6 +-
>>>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>>>  drivers/usb/core/Kconfig     |  14 -
>>>  drivers/usb/gadget/Kconfig   |   1 +
>>>  include/linux/usb/gadget.h   |   2 +
>>>  include/linux/usb/hcd.h      |   1 +
>>>  include/linux/usb/otg-fsm.h  |   7 +
>>>  include/linux/usb/otg.h      | 174 ++++++++-
>>>  9 files changed, 1070 insertions(+), 30 deletions(-)
>>>  create mode 100644 drivers/usb/common/usb-otg.c
>>>
>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>>> index 8689dcb..ed596ec 100644
>>> --- a/drivers/usb/Kconfig
>>> +++ b/drivers/usb/Kconfig
>>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>>  config USB_COMMON
>>>  	tristate
>>>  
>>> +config USB_OTG_CORE
>>> +	tristate
>> 
>> why tristate if you can never set it to 'M'?
>
> This gets internally set to M if either USB or GADGET is M.
> We select it in USB and GADGET.
> This was the only way I could get usb-otg.c to build as
>
> m if USB OR GADGET is m
> built-in if USB and GADGET are built in.

I could only see a "select USB_OTG_CORE", select will always set it 'y'
and disregard dependencies. Maybe I missed something else.

>>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>>> new file mode 100644
>>> index 0000000..a23ab1e
>>> --- /dev/null
>>> +++ b/drivers/usb/common/usb-otg.c
>>> @@ -0,0 +1,877 @@
>>> +/**
>>> + * drivers/usb/common/usb-otg.c - USB OTG core
>>> + *
>>> + * Copyright (C) 2016 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/list.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/usb/of.h>
>>> +#include <linux/usb/otg.h>
>>> +#include <linux/usb/gadget.h>
>>> +#include <linux/workqueue.h>
>>> +
>>> +/* OTG device list */
>>> +LIST_HEAD(otg_list);
>> 
>> not static? Who needs to touch this private list?
>
> right, it should be static.
>
>> 
>>> +static DEFINE_MUTEX(otg_list_mutex);
>>> +
>>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>>> +{
>>> +	if (!hcd->primary_hcd)
>>> +		return 1;
>> 
>> these seems inverted. If hcd->primary is NULL (meaning, there's no
>> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
>> to explain?
>
> hcd->primary_hcd is a link used by the shared hcd to point to the
> primary_hcd.  primary_hcd's have this link as NULL.

So the following check is unnecessary and should always evaluate to
false, right ?

>>> +	return hcd == hcd->primary_hcd;
>>> +}
>>> +
>>> +/**
>>> + * usb_otg_get_data() - get usb_otg data structure
>>> + * @otg_dev:	OTG controller device
>>> + *
>>> + * Check if the OTG device is in our OTG list and return
>>> + * usb_otg data, else NULL.
>>> + *
>>> + * otg_list_mutex must be held.
>>> + *
>>> + * Return: usb_otg data on success, NULL otherwise.
>>> + */
>>> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
>>> +{
>>> +	struct usb_otg *otg;
>>> +
>>> +	if (!otg_dev)
>>> +		return NULL;
>>> +
>>> +	list_for_each_entry(otg, &otg_list, list) {
>>> +		if (otg->dev == otg_dev)
>>> +			return otg;
>>> +	}
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +/**
>>> + * usb_otg_start_host() - start/stop the host controller
>>> + * @otg:	usb_otg instance
>>> + * @on:		true to start, false to stop
>>> + *
>>> + * Start/stop the USB host controller. This function is meant
>>> + * for use by the OTG controller driver.
>>> + *
>>> + * Return: 0 on success, error value otherwise.
>>> + */
>>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>>> +{
>>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>>> +	int ret;
>>> +
>>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>>> +	if (!otg->host) {
>>> +		WARN_ONCE(1, "otg: fsm running without host\n");
>> 
>> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
>> 	return 0;
>> 
>> but, frankly, if you require a 'host' and a 'gadget' don't start this
>> layer until you have both.
>
> We don't start the layer till we have both host and gadget. But
> this API is for external use and might be called at any time.

well, if callers call this at the wrong time, it's callers' fault. Let
them oops so we catch the error.

> I could change the warning message to
>  
> if (WARN_ONCE(!otg->host, "otg: %s called in invalid context\n", __func__))
> 	return 0;

you don't neet that.

>>> +		return 0;
>>> +	}
>>> +
>>> +	if (on) {
>>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>>> +			return 0;
>>> +
>>> +		/* start host */
>>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>>> +				   otg->primary_hcd.irqnum,
>>> +				   otg->primary_hcd.irqflags);
>> 
>> this is usb_add_hcd(), is it not? Why add an indirection?
>
> I've introduced the host and gadget ops interface to get around the
> circular dependency issue we can't avoid.
> otg needs to call host/gadget functions and host/gadget also needs to
> call otg functions.

IMO, this shows a fragility of your design. You're, now, lying to
usb_hcd and usb_udc and making them register into a virtual layer that
doesn't exist. And that layer will end up calling the real registration
function when some magic event happens.

This is only really needed for quirky devices like dwc3 (but see more on
dwc3 below) where host and peripheral registers shadow each
other. Otherwise we would be able to always keep hcd and udc always
registered. They would get different interrupt statuses anyway and
nothing would ever break.

However, when it comes to dwc3, we already have all the code necessary
to workaround this issue by destroying the XHCI pdev when OTG interrupt
says we should be peripheral (and vice-versa). DWC3 also keeps track of
the OTG states for those folks who really care about OTG (Hint: nobody
has cared for the past 10 years, why would they do so now?) and we don't
need a SW state machine when the HW handles that for us, right?

As for chipidea, IIRC, that doesn't need a SW state machine either, but
I know very little about that IP and don't even have documentation on
it. My understanding, however, is that chipidea behaves kinda like MUSB,
which changes roles automatically in HW based on ID pin state.

>>> +EXPORT_SYMBOL_GPL(drd_statemachine);
>> 
>> why is this exported at all? It only runs from the work_struct
>
> You're right. It shouldn't be exported.
>
>> below. BTW, that work_struct looks unnecessary.
>
> why? The kick could be triggered from an interrupt
> context. e.g. otg_irq.

We have threaded IRQ handlers in the kernel, right? Make use of that
and, with a little smart locking and IRQ masking, you can run the OTG
IRQ thread almost completely lockless ;-)

>>> +/**
>>> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
>>> + * @dev: OTG/dual-role controller device.
>>> + * @config: OTG configuration.
>>> + *
>>> + * Registers the OTG/dual-role controller device with the USB OTG core.
>>> + *
>>> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
>>> + */
>>> +struct usb_otg *usb_otg_register(struct device *dev,
>>> +				 struct usb_otg_config *config)
>>> +{
>>> +	struct usb_otg *otg;
>>> +	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 */
>>> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
>>> +	if (!otg) {
>>> +		ret = -ENOMEM;
>>> +		goto unlock;
>>> +	}
>>> +
>>> +	otg->dev = dev;
>>> +	/* otg->caps is controller caps + DT overrides */
>>> +	otg->caps = *config->otg_caps;
>>> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
>>> +	if (ret)
>>> +		goto err_wq;
>>> +
>>> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
>>> +	     otg->caps.adp_support) && !config->otg_work) {
>>> +		dev_err(dev,
>>> +			"otg: otg_work must be provided for OTG support\n");
>>> +		ret = -EINVAL;
>>> +		goto err_wq;
>>> +	}
>>> +
>>> +	if (config->otg_work)	/* custom otg_work ? */
>>> +		INIT_WORK(&otg->work, config->otg_work);
>>> +	else
>>> +		INIT_WORK(&otg->work, usb_drd_work);
>> 
>> why do you need to cope with custom work handlers?
>
> It was just a provision to provide your own state machine if the generic
> one does not meet your needs. But i'm OK to get rid of it as well.

If you allow for this, every time there is a limitation, people will
just provide a copy of the state machine with a small change here and
there instead of fixing the real issue.

>>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>>> +{
>>> +	struct otg_fsm *fsm = &otg->fsm;
>>> +
>>> +	if (fsm->running)
>>> +		goto kick_fsm;
>>> +
>>> +	if (!otg->host) {
>>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>>> +		return;
>>> +	}
>>> +
>>> +	if (!otg->gadget) {
>>> +		dev_info(otg->dev,
>>> +			 "otg: can't start till gadget UDC registers\n");
>>> +		return;
>>> +	}
>> 
>> okay, so you never kick the FSM until host and gadget are
>> registered. Why do you need to test for the case where the FSM is
>> running without host/gadget?
>
> That message in the test was misleading. It could also be a
> used as a warning if users did something wrong.

this usb_otg_start_fsm() establishes a contract. That contract says that
the USB OTG FSM won't start until host and gadget are running and
registered, yada yada yada. Drivers trying to kicking the FSM without
calling usb_otg_start_fsm() first deserve to oops.

>>> +MODULE_LICENSE("GPL");
>> 
>> GPL or GPL 2-only?
>
> GPL v2.
>
>> 
>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>> index f4fc0aa..1d74fb8 100644
>>> --- a/include/linux/usb/gadget.h
>>> +++ b/include/linux/usb/gadget.h
>>> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>>>   * @in_epnum: last used in ep number
>>>   * @mA: last set mA value
>>>   * @otg_caps: OTG capabilities of this gadget.
>>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> 
>> do you really know of any platform which has a separate OTG controller?
>> 
>
> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> and gadget.
>
> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969

that's not an OTG controller, it's just a mux. No different than Intel's
mux for swapping between XHCI and peripheral-only DWC3.

frankly, I would NEVER talk about OTG when type-C comes into play. They
are two competing standards and, apparently, type-C is winning when it
comes to role-swapping.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-20 11:49         ` Peter Chen
@ 2016-06-20 12:08           ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20 12:08 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 2488 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> Roger Quadros <rogerq@ti.com> writes:
>> > It provides APIs for the following tasks
>> >
>> > - Registering an OTG/dual-role capable controller
>> > - Registering Host and Gadget controllers to OTG core
>> > - Providing inputs to and kicking the OTG state machine
>> 
>> I think I have already mentioned this, but after over 10 years of OTG,
>> nobody seems to care about it, why are we still touching at all I don't
>> know. For common non-OTG role-swapping we really don't need any of this
>> and, quite frankly, I fail to see enough users for this.
>> 
>> Apparently there's only chipidea which, AFAICT, already had working
>> dual-role before this OTG State Machine was added to the kernel.
>
> Some users would like to know if vendor's platform is OTG compliance,
> so we add it to pass usb.org USB OTG certification test.

I strongly doubt that's really what they mean. IMHO, users want to know
if they can swap roles. Ask them if they are really going for OTG
certification. Ask them if they have an OPT tester. Ask them if they
really want all those timers. If they want HNP polling, etc etc etc.

So far, I haven't seen anybody talking about real USB OTG (the spec)
when they say OTG. Usually they just mean "a method for swapping between
host and peripheral roles, but we really don't want all the extra cost
of the OTG specification".

> For the real use case, some Carplay platforms need it.

Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
specification which is not OTG-compliant.

>> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> > index f4fc0aa..1d74fb8 100644
>> > --- a/include/linux/usb/gadget.h
>> > +++ b/include/linux/usb/gadget.h
>> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >   * @in_epnum: last used in ep number
>> >   * @mA: last set mA value
>> >   * @otg_caps: OTG capabilities of this gadget.
>> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> 
>> do you really know of any platform which has a separate OTG controller?
>> 
>
> It may not be a real separate OTG controller. It can be a hardware part
> (external connector, external IC, SoC OTG register area, etc) to handle vbus
> ,id and other signals which are used for role swap.

That's already solved. EXTCON solved that years back and OMAP has been
using EXTCON to program its UTMI mailbox.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 12:08           ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20 12:08 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2540 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>> > It provides APIs for the following tasks
>> >
>> > - Registering an OTG/dual-role capable controller
>> > - Registering Host and Gadget controllers to OTG core
>> > - Providing inputs to and kicking the OTG state machine
>> 
>> I think I have already mentioned this, but after over 10 years of OTG,
>> nobody seems to care about it, why are we still touching at all I don't
>> know. For common non-OTG role-swapping we really don't need any of this
>> and, quite frankly, I fail to see enough users for this.
>> 
>> Apparently there's only chipidea which, AFAICT, already had working
>> dual-role before this OTG State Machine was added to the kernel.
>
> Some users would like to know if vendor's platform is OTG compliance,
> so we add it to pass usb.org USB OTG certification test.

I strongly doubt that's really what they mean. IMHO, users want to know
if they can swap roles. Ask them if they are really going for OTG
certification. Ask them if they have an OPT tester. Ask them if they
really want all those timers. If they want HNP polling, etc etc etc.

So far, I haven't seen anybody talking about real USB OTG (the spec)
when they say OTG. Usually they just mean "a method for swapping between
host and peripheral roles, but we really don't want all the extra cost
of the OTG specification".

> For the real use case, some Carplay platforms need it.

Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
specification which is not OTG-compliant.

>> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> > index f4fc0aa..1d74fb8 100644
>> > --- a/include/linux/usb/gadget.h
>> > +++ b/include/linux/usb/gadget.h
>> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >   * @in_epnum: last used in ep number
>> >   * @mA: last set mA value
>> >   * @otg_caps: OTG capabilities of this gadget.
>> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> 
>> do you really know of any platform which has a separate OTG controller?
>> 
>
> It may not be a real separate OTG controller. It can be a hardware part
> (external connector, external IC, SoC OTG register area, etc) to handle vbus
> ,id and other signals which are used for role swap.

That's already solved. EXTCON solved that years back and OMAP has been
using EXTCON to program its UTMI mailbox.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 12:26             ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20 12:26 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen, yoshihiro.shimoda.uh
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree


[-- Attachment #1.1: Type: text/plain, Size: 15211 bytes --]

On 20/06/16 15:03, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>> Roger Quadros <rogerq@ti.com> writes:
>>>> It provides APIs for the following tasks
>>>>
>>>> - Registering an OTG/dual-role capable controller
>>>> - Registering Host and Gadget controllers to OTG core
>>>> - Providing inputs to and kicking the OTG state machine
>>>
>>> I think I have already mentioned this, but after over 10 years of OTG,
>>> nobody seems to care about it, why are we still touching at all I don't
>>> know. For common non-OTG role-swapping we really don't need any of this
>>> and, quite frankly, I fail to see enough users for this.
>>>
>>> Apparently there's only chipidea which, AFAICT, already had working
>>> dual-role before this OTG State Machine was added to the kernel.
>>>
>>>> Provide a dual-role device (DRD) state machine.
>>>
>>> there's not such thing as DRD state machine. You don't need to go
>>> through all these states, actually.
>>
>> There are 3 states though.
>> HOST (id = 0)
>> PERIPHERAL (id = 1, vbus = 1)
>> IDLE (id = 1, vbus = 0).
> 
> IDLE is pretty much given, though ;-)
> 
>>>> 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>
>>>> ---
>>>> v11:
>>>> - remove usb_otg_kick_fsm().
>>>> - typo fixes: structa/structure, upto/up to.
>>>> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>>>>
>>>>  drivers/usb/Kconfig          |  18 +
>>>>  drivers/usb/common/Makefile  |   6 +-
>>>>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/usb/core/Kconfig     |  14 -
>>>>  drivers/usb/gadget/Kconfig   |   1 +
>>>>  include/linux/usb/gadget.h   |   2 +
>>>>  include/linux/usb/hcd.h      |   1 +
>>>>  include/linux/usb/otg-fsm.h  |   7 +
>>>>  include/linux/usb/otg.h      | 174 ++++++++-
>>>>  9 files changed, 1070 insertions(+), 30 deletions(-)
>>>>  create mode 100644 drivers/usb/common/usb-otg.c
>>>>
>>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>>>> index 8689dcb..ed596ec 100644
>>>> --- a/drivers/usb/Kconfig
>>>> +++ b/drivers/usb/Kconfig
>>>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>>>  config USB_COMMON
>>>>  	tristate
>>>>  
>>>> +config USB_OTG_CORE
>>>> +	tristate
>>>
>>> why tristate if you can never set it to 'M'?
>>
>> This gets internally set to M if either USB or GADGET is M.
>> We select it in USB and GADGET.
>> This was the only way I could get usb-otg.c to build as
>>
>> m if USB OR GADGET is m
>> built-in if USB and GADGET are built in.
> 
> I could only see a "select USB_OTG_CORE", select will always set it 'y'
> and disregard dependencies. Maybe I missed something else.

Not always. See how USB_COMMON works.
> 
>>>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>>>> new file mode 100644
>>>> index 0000000..a23ab1e
>>>> --- /dev/null
>>>> +++ b/drivers/usb/common/usb-otg.c
>>>> @@ -0,0 +1,877 @@
>>>> +/**
>>>> + * drivers/usb/common/usb-otg.c - USB OTG core
>>>> + *
>>>> + * Copyright (C) 2016 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/list.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_platform.h>
>>>> +#include <linux/usb/of.h>
>>>> +#include <linux/usb/otg.h>
>>>> +#include <linux/usb/gadget.h>
>>>> +#include <linux/workqueue.h>
>>>> +
>>>> +/* OTG device list */
>>>> +LIST_HEAD(otg_list);
>>>
>>> not static? Who needs to touch this private list?
>>
>> right, it should be static.
>>
>>>
>>>> +static DEFINE_MUTEX(otg_list_mutex);
>>>> +
>>>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>>>> +{
>>>> +	if (!hcd->primary_hcd)
>>>> +		return 1;
>>>
>>> these seems inverted. If hcd->primary is NULL (meaning, there's no
>>> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
>>> to explain?
>>
>> hcd->primary_hcd is a link used by the shared hcd to point to the
>> primary_hcd.  primary_hcd's have this link as NULL.
> 
> So the following check is unnecessary and should always evaluate to
> false, right ?

Actually primary_hcd's not having a shared HCD have hcd->primary_hcd as NULL
and those having a shared HCD do have it pointing to the primary hcd.

> 
>>>> +	return hcd == hcd->primary_hcd;
>>>> +}
>>>> +
>>>> +/**
>>>> + * usb_otg_get_data() - get usb_otg data structure
>>>> + * @otg_dev:	OTG controller device
>>>> + *
>>>> + * Check if the OTG device is in our OTG list and return
>>>> + * usb_otg data, else NULL.
>>>> + *
>>>> + * otg_list_mutex must be held.
>>>> + *
>>>> + * Return: usb_otg data on success, NULL otherwise.
>>>> + */
>>>> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
>>>> +{
>>>> +	struct usb_otg *otg;
>>>> +
>>>> +	if (!otg_dev)
>>>> +		return NULL;
>>>> +
>>>> +	list_for_each_entry(otg, &otg_list, list) {
>>>> +		if (otg->dev == otg_dev)
>>>> +			return otg;
>>>> +	}
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/**
>>>> + * usb_otg_start_host() - start/stop the host controller
>>>> + * @otg:	usb_otg instance
>>>> + * @on:		true to start, false to stop
>>>> + *
>>>> + * Start/stop the USB host controller. This function is meant
>>>> + * for use by the OTG controller driver.
>>>> + *
>>>> + * Return: 0 on success, error value otherwise.
>>>> + */
>>>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>>>> +{
>>>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>>>> +	int ret;
>>>> +
>>>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>>>> +	if (!otg->host) {
>>>> +		WARN_ONCE(1, "otg: fsm running without host\n");
>>>
>>> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
>>> 	return 0;
>>>
>>> but, frankly, if you require a 'host' and a 'gadget' don't start this
>>> layer until you have both.
>>
>> We don't start the layer till we have both host and gadget. But
>> this API is for external use and might be called at any time.
> 
> well, if callers call this at the wrong time, it's callers' fault. Let
> them oops so we catch the error.

So you suggest we allow a NULL pointer dereference here?

> 
>> I could change the warning message to
>>  
>> if (WARN_ONCE(!otg->host, "otg: %s called in invalid context\n", __func__))
>> 	return 0;
> 
> you don't neet that.
> 
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	if (on) {
>>>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>>>> +			return 0;
>>>> +
>>>> +		/* start host */
>>>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>>>> +				   otg->primary_hcd.irqnum,
>>>> +				   otg->primary_hcd.irqflags);
>>>
>>> this is usb_add_hcd(), is it not? Why add an indirection?
>>
>> I've introduced the host and gadget ops interface to get around the
>> circular dependency issue we can't avoid.
>> otg needs to call host/gadget functions and host/gadget also needs to
>> call otg functions.
> 
> IMO, this shows a fragility of your design. You're, now, lying to
> usb_hcd and usb_udc and making them register into a virtual layer that
> doesn't exist. And that layer will end up calling the real registration
> function when some magic event happens.
> 
> This is only really needed for quirky devices like dwc3 (but see more on
> dwc3 below) where host and peripheral registers shadow each
> other. Otherwise we would be able to always keep hcd and udc always
> registered. They would get different interrupt statuses anyway and
> nothing would ever break.

Well I only had the opportunity to work with dwc3 so I had to ensure
the design worked with it.

> 
> However, when it comes to dwc3, we already have all the code necessary
> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> the OTG states for those folks who really care about OTG (Hint: nobody
> has cared for the past 10 years, why would they do so now?) and we don't
> need a SW state machine when the HW handles that for us, right?

Where is the code? I'd like to test dual-role on TI platforms.

> 
> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> I know very little about that IP and don't even have documentation on
> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> which changes roles automatically in HW based on ID pin state.
> 
>>>> +EXPORT_SYMBOL_GPL(drd_statemachine);
>>>
>>> why is this exported at all? It only runs from the work_struct
>>
>> You're right. It shouldn't be exported.
>>
>>> below. BTW, that work_struct looks unnecessary.
>>
>> why? The kick could be triggered from an interrupt
>> context. e.g. otg_irq.
> 
> We have threaded IRQ handlers in the kernel, right? Make use of that
> and, with a little smart locking and IRQ masking, you can run the OTG
> IRQ thread almost completely lockless ;-)

Not a problem if we have the constraint that usb_otg_sync_inputs()
needs to be called in thread context only.

> 
>>>> +/**
>>>> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
>>>> + * @dev: OTG/dual-role controller device.
>>>> + * @config: OTG configuration.
>>>> + *
>>>> + * Registers the OTG/dual-role controller device with the USB OTG core.
>>>> + *
>>>> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
>>>> + */
>>>> +struct usb_otg *usb_otg_register(struct device *dev,
>>>> +				 struct usb_otg_config *config)
>>>> +{
>>>> +	struct usb_otg *otg;
>>>> +	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 */
>>>> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
>>>> +	if (!otg) {
>>>> +		ret = -ENOMEM;
>>>> +		goto unlock;
>>>> +	}
>>>> +
>>>> +	otg->dev = dev;
>>>> +	/* otg->caps is controller caps + DT overrides */
>>>> +	otg->caps = *config->otg_caps;
>>>> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
>>>> +	if (ret)
>>>> +		goto err_wq;
>>>> +
>>>> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
>>>> +	     otg->caps.adp_support) && !config->otg_work) {
>>>> +		dev_err(dev,
>>>> +			"otg: otg_work must be provided for OTG support\n");
>>>> +		ret = -EINVAL;
>>>> +		goto err_wq;
>>>> +	}
>>>> +
>>>> +	if (config->otg_work)	/* custom otg_work ? */
>>>> +		INIT_WORK(&otg->work, config->otg_work);
>>>> +	else
>>>> +		INIT_WORK(&otg->work, usb_drd_work);
>>>
>>> why do you need to cope with custom work handlers?
>>
>> It was just a provision to provide your own state machine if the generic
>> one does not meet your needs. But i'm OK to get rid of it as well.
> 
> If you allow for this, every time there is a limitation, people will
> just provide a copy of the state machine with a small change here and
> there instead of fixing the real issue.

I agree with you here. I'll get rid of the custom_otg_work.

> 
>>>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>>>> +{
>>>> +	struct otg_fsm *fsm = &otg->fsm;
>>>> +
>>>> +	if (fsm->running)
>>>> +		goto kick_fsm;
>>>> +
>>>> +	if (!otg->host) {
>>>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	if (!otg->gadget) {
>>>> +		dev_info(otg->dev,
>>>> +			 "otg: can't start till gadget UDC registers\n");
>>>> +		return;
>>>> +	}
>>>
>>> okay, so you never kick the FSM until host and gadget are
>>> registered. Why do you need to test for the case where the FSM is
>>> running without host/gadget?
>>
>> That message in the test was misleading. It could also be a
>> used as a warning if users did something wrong.
> 
> this usb_otg_start_fsm() establishes a contract. That contract says that
> the USB OTG FSM won't start until host and gadget are running and
> registered, yada yada yada. Drivers trying to kicking the FSM without
> calling usb_otg_start_fsm() first deserve to oops.

I'm considering the worst case where OTG controller, host controller and gadget controller
are 3 independent entities which can get probed in any order.

OTG controller driver doesn't really know when host and gadget register.
All it cares about is getting the hardware events and kicking the OTG machine.

(NOTE: when I say OTG controller it might as well be just the dual-role bits
that handle the ID and VBUS interrupts).

usb_otg_start_fsm() is not public.
usb_otg_sync_inputs() is the public function that the OTG driver will use.

> 
>>>> +MODULE_LICENSE("GPL");
>>>
>>> GPL or GPL 2-only?
>>
>> GPL v2.
>>
>>>
>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>> index f4fc0aa..1d74fb8 100644
>>>> --- a/include/linux/usb/gadget.h
>>>> +++ b/include/linux/usb/gadget.h
>>>> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>>>>   * @in_epnum: last used in ep number
>>>>   * @mA: last set mA value
>>>>   * @otg_caps: OTG capabilities of this gadget.
>>>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>>>
>>> do you really know of any platform which has a separate OTG controller?
>>>
>>
>> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> and gadget.
>>
>> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> 
> that's not an OTG controller, it's just a mux. No different than Intel's
> mux for swapping between XHCI and peripheral-only DWC3.
> 
> frankly, I would NEVER talk about OTG when type-C comes into play. They
> are two competing standards and, apparently, type-C is winning when it
> comes to role-swapping.
> 

Good to know.

cheers,
-roger



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-20 12:26             ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-20 12:26 UTC (permalink / raw)
  To: Felipe Balbi, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA


[-- Attachment #1.1: Type: text/plain, Size: 15299 bytes --]

On 20/06/16 15:03, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>> It provides APIs for the following tasks
>>>>
>>>> - Registering an OTG/dual-role capable controller
>>>> - Registering Host and Gadget controllers to OTG core
>>>> - Providing inputs to and kicking the OTG state machine
>>>
>>> I think I have already mentioned this, but after over 10 years of OTG,
>>> nobody seems to care about it, why are we still touching at all I don't
>>> know. For common non-OTG role-swapping we really don't need any of this
>>> and, quite frankly, I fail to see enough users for this.
>>>
>>> Apparently there's only chipidea which, AFAICT, already had working
>>> dual-role before this OTG State Machine was added to the kernel.
>>>
>>>> Provide a dual-role device (DRD) state machine.
>>>
>>> there's not such thing as DRD state machine. You don't need to go
>>> through all these states, actually.
>>
>> There are 3 states though.
>> HOST (id = 0)
>> PERIPHERAL (id = 1, vbus = 1)
>> IDLE (id = 1, vbus = 0).
> 
> IDLE is pretty much given, though ;-)
> 
>>>> 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-l0cyMroinI0@public.gmane.org>
>>>> ---
>>>> v11:
>>>> - remove usb_otg_kick_fsm().
>>>> - typo fixes: structa/structure, upto/up to.
>>>> - remove "obj-$(CONFIG_USB_OTG_CORE)     += common/" from Makefile.
>>>>
>>>>  drivers/usb/Kconfig          |  18 +
>>>>  drivers/usb/common/Makefile  |   6 +-
>>>>  drivers/usb/common/usb-otg.c | 877 +++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/usb/core/Kconfig     |  14 -
>>>>  drivers/usb/gadget/Kconfig   |   1 +
>>>>  include/linux/usb/gadget.h   |   2 +
>>>>  include/linux/usb/hcd.h      |   1 +
>>>>  include/linux/usb/otg-fsm.h  |   7 +
>>>>  include/linux/usb/otg.h      | 174 ++++++++-
>>>>  9 files changed, 1070 insertions(+), 30 deletions(-)
>>>>  create mode 100644 drivers/usb/common/usb-otg.c
>>>>
>>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>>>> index 8689dcb..ed596ec 100644
>>>> --- a/drivers/usb/Kconfig
>>>> +++ b/drivers/usb/Kconfig
>>>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>>>  config USB_COMMON
>>>>  	tristate
>>>>  
>>>> +config USB_OTG_CORE
>>>> +	tristate
>>>
>>> why tristate if you can never set it to 'M'?
>>
>> This gets internally set to M if either USB or GADGET is M.
>> We select it in USB and GADGET.
>> This was the only way I could get usb-otg.c to build as
>>
>> m if USB OR GADGET is m
>> built-in if USB and GADGET are built in.
> 
> I could only see a "select USB_OTG_CORE", select will always set it 'y'
> and disregard dependencies. Maybe I missed something else.

Not always. See how USB_COMMON works.
> 
>>>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>>>> new file mode 100644
>>>> index 0000000..a23ab1e
>>>> --- /dev/null
>>>> +++ b/drivers/usb/common/usb-otg.c
>>>> @@ -0,0 +1,877 @@
>>>> +/**
>>>> + * drivers/usb/common/usb-otg.c - USB OTG core
>>>> + *
>>>> + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
>>>> + * Author: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
>>>> + *
>>>> + * 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/list.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_platform.h>
>>>> +#include <linux/usb/of.h>
>>>> +#include <linux/usb/otg.h>
>>>> +#include <linux/usb/gadget.h>
>>>> +#include <linux/workqueue.h>
>>>> +
>>>> +/* OTG device list */
>>>> +LIST_HEAD(otg_list);
>>>
>>> not static? Who needs to touch this private list?
>>
>> right, it should be static.
>>
>>>
>>>> +static DEFINE_MUTEX(otg_list_mutex);
>>>> +
>>>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>>>> +{
>>>> +	if (!hcd->primary_hcd)
>>>> +		return 1;
>>>
>>> these seems inverted. If hcd->primary is NULL (meaning, there's no
>>> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
>>> to explain?
>>
>> hcd->primary_hcd is a link used by the shared hcd to point to the
>> primary_hcd.  primary_hcd's have this link as NULL.
> 
> So the following check is unnecessary and should always evaluate to
> false, right ?

Actually primary_hcd's not having a shared HCD have hcd->primary_hcd as NULL
and those having a shared HCD do have it pointing to the primary hcd.

> 
>>>> +	return hcd == hcd->primary_hcd;
>>>> +}
>>>> +
>>>> +/**
>>>> + * usb_otg_get_data() - get usb_otg data structure
>>>> + * @otg_dev:	OTG controller device
>>>> + *
>>>> + * Check if the OTG device is in our OTG list and return
>>>> + * usb_otg data, else NULL.
>>>> + *
>>>> + * otg_list_mutex must be held.
>>>> + *
>>>> + * Return: usb_otg data on success, NULL otherwise.
>>>> + */
>>>> +static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
>>>> +{
>>>> +	struct usb_otg *otg;
>>>> +
>>>> +	if (!otg_dev)
>>>> +		return NULL;
>>>> +
>>>> +	list_for_each_entry(otg, &otg_list, list) {
>>>> +		if (otg->dev == otg_dev)
>>>> +			return otg;
>>>> +	}
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/**
>>>> + * usb_otg_start_host() - start/stop the host controller
>>>> + * @otg:	usb_otg instance
>>>> + * @on:		true to start, false to stop
>>>> + *
>>>> + * Start/stop the USB host controller. This function is meant
>>>> + * for use by the OTG controller driver.
>>>> + *
>>>> + * Return: 0 on success, error value otherwise.
>>>> + */
>>>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>>>> +{
>>>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>>>> +	int ret;
>>>> +
>>>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>>>> +	if (!otg->host) {
>>>> +		WARN_ONCE(1, "otg: fsm running without host\n");
>>>
>>> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
>>> 	return 0;
>>>
>>> but, frankly, if you require a 'host' and a 'gadget' don't start this
>>> layer until you have both.
>>
>> We don't start the layer till we have both host and gadget. But
>> this API is for external use and might be called at any time.
> 
> well, if callers call this at the wrong time, it's callers' fault. Let
> them oops so we catch the error.

So you suggest we allow a NULL pointer dereference here?

> 
>> I could change the warning message to
>>  
>> if (WARN_ONCE(!otg->host, "otg: %s called in invalid context\n", __func__))
>> 	return 0;
> 
> you don't neet that.
> 
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	if (on) {
>>>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>>>> +			return 0;
>>>> +
>>>> +		/* start host */
>>>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>>>> +				   otg->primary_hcd.irqnum,
>>>> +				   otg->primary_hcd.irqflags);
>>>
>>> this is usb_add_hcd(), is it not? Why add an indirection?
>>
>> I've introduced the host and gadget ops interface to get around the
>> circular dependency issue we can't avoid.
>> otg needs to call host/gadget functions and host/gadget also needs to
>> call otg functions.
> 
> IMO, this shows a fragility of your design. You're, now, lying to
> usb_hcd and usb_udc and making them register into a virtual layer that
> doesn't exist. And that layer will end up calling the real registration
> function when some magic event happens.
> 
> This is only really needed for quirky devices like dwc3 (but see more on
> dwc3 below) where host and peripheral registers shadow each
> other. Otherwise we would be able to always keep hcd and udc always
> registered. They would get different interrupt statuses anyway and
> nothing would ever break.

Well I only had the opportunity to work with dwc3 so I had to ensure
the design worked with it.

> 
> However, when it comes to dwc3, we already have all the code necessary
> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> the OTG states for those folks who really care about OTG (Hint: nobody
> has cared for the past 10 years, why would they do so now?) and we don't
> need a SW state machine when the HW handles that for us, right?

Where is the code? I'd like to test dual-role on TI platforms.

> 
> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> I know very little about that IP and don't even have documentation on
> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> which changes roles automatically in HW based on ID pin state.
> 
>>>> +EXPORT_SYMBOL_GPL(drd_statemachine);
>>>
>>> why is this exported at all? It only runs from the work_struct
>>
>> You're right. It shouldn't be exported.
>>
>>> below. BTW, that work_struct looks unnecessary.
>>
>> why? The kick could be triggered from an interrupt
>> context. e.g. otg_irq.
> 
> We have threaded IRQ handlers in the kernel, right? Make use of that
> and, with a little smart locking and IRQ masking, you can run the OTG
> IRQ thread almost completely lockless ;-)

Not a problem if we have the constraint that usb_otg_sync_inputs()
needs to be called in thread context only.

> 
>>>> +/**
>>>> + * usb_otg_register() - Register the OTG/dual-role device to OTG core
>>>> + * @dev: OTG/dual-role controller device.
>>>> + * @config: OTG configuration.
>>>> + *
>>>> + * Registers the OTG/dual-role controller device with the USB OTG core.
>>>> + *
>>>> + * Return: struct usb_otg * if success, ERR_PTR() otherwise.
>>>> + */
>>>> +struct usb_otg *usb_otg_register(struct device *dev,
>>>> +				 struct usb_otg_config *config)
>>>> +{
>>>> +	struct usb_otg *otg;
>>>> +	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 */
>>>> +	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
>>>> +	if (!otg) {
>>>> +		ret = -ENOMEM;
>>>> +		goto unlock;
>>>> +	}
>>>> +
>>>> +	otg->dev = dev;
>>>> +	/* otg->caps is controller caps + DT overrides */
>>>> +	otg->caps = *config->otg_caps;
>>>> +	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
>>>> +	if (ret)
>>>> +		goto err_wq;
>>>> +
>>>> +	if ((otg->caps.hnp_support || otg->caps.srp_support ||
>>>> +	     otg->caps.adp_support) && !config->otg_work) {
>>>> +		dev_err(dev,
>>>> +			"otg: otg_work must be provided for OTG support\n");
>>>> +		ret = -EINVAL;
>>>> +		goto err_wq;
>>>> +	}
>>>> +
>>>> +	if (config->otg_work)	/* custom otg_work ? */
>>>> +		INIT_WORK(&otg->work, config->otg_work);
>>>> +	else
>>>> +		INIT_WORK(&otg->work, usb_drd_work);
>>>
>>> why do you need to cope with custom work handlers?
>>
>> It was just a provision to provide your own state machine if the generic
>> one does not meet your needs. But i'm OK to get rid of it as well.
> 
> If you allow for this, every time there is a limitation, people will
> just provide a copy of the state machine with a small change here and
> there instead of fixing the real issue.

I agree with you here. I'll get rid of the custom_otg_work.

> 
>>>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>>>> +{
>>>> +	struct otg_fsm *fsm = &otg->fsm;
>>>> +
>>>> +	if (fsm->running)
>>>> +		goto kick_fsm;
>>>> +
>>>> +	if (!otg->host) {
>>>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	if (!otg->gadget) {
>>>> +		dev_info(otg->dev,
>>>> +			 "otg: can't start till gadget UDC registers\n");
>>>> +		return;
>>>> +	}
>>>
>>> okay, so you never kick the FSM until host and gadget are
>>> registered. Why do you need to test for the case where the FSM is
>>> running without host/gadget?
>>
>> That message in the test was misleading. It could also be a
>> used as a warning if users did something wrong.
> 
> this usb_otg_start_fsm() establishes a contract. That contract says that
> the USB OTG FSM won't start until host and gadget are running and
> registered, yada yada yada. Drivers trying to kicking the FSM without
> calling usb_otg_start_fsm() first deserve to oops.

I'm considering the worst case where OTG controller, host controller and gadget controller
are 3 independent entities which can get probed in any order.

OTG controller driver doesn't really know when host and gadget register.
All it cares about is getting the hardware events and kicking the OTG machine.

(NOTE: when I say OTG controller it might as well be just the dual-role bits
that handle the ID and VBUS interrupts).

usb_otg_start_fsm() is not public.
usb_otg_sync_inputs() is the public function that the OTG driver will use.

> 
>>>> +MODULE_LICENSE("GPL");
>>>
>>> GPL or GPL 2-only?
>>
>> GPL v2.
>>
>>>
>>>> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>>>> index f4fc0aa..1d74fb8 100644
>>>> --- a/include/linux/usb/gadget.h
>>>> +++ b/include/linux/usb/gadget.h
>>>> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>>>>   * @in_epnum: last used in ep number
>>>>   * @mA: last set mA value
>>>>   * @otg_caps: OTG capabilities of this gadget.
>>>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>>>
>>> do you really know of any platform which has a separate OTG controller?
>>>
>>
>> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> and gadget.
>>
>> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> 
> that's not an OTG controller, it's just a mux. No different than Intel's
> mux for swapping between XHCI and peripheral-only DWC3.
> 
> frankly, I would NEVER talk about OTG when type-C comes into play. They
> are two competing standards and, apparently, type-C is winning when it
> comes to role-swapping.
> 

Good to know.

cheers,
-roger



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-20 12:26             ` Roger Quadros
  (?)
@ 2016-06-20 12:46             ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-20 12:46 UTC (permalink / raw)
  To: Roger Quadros, peter.chen, yoshihiro.shimoda.uh
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 8602 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
>>>>> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
>>>>> index 8689dcb..ed596ec 100644
>>>>> --- a/drivers/usb/Kconfig
>>>>> +++ b/drivers/usb/Kconfig
>>>>> @@ -32,6 +32,23 @@ if USB_SUPPORT
>>>>>  config USB_COMMON
>>>>>  	tristate
>>>>>  
>>>>> +config USB_OTG_CORE
>>>>> +	tristate
>>>>
>>>> why tristate if you can never set it to 'M'?
>>>
>>> This gets internally set to M if either USB or GADGET is M.
>>> We select it in USB and GADGET.
>>> This was the only way I could get usb-otg.c to build as
>>>
>>> m if USB OR GADGET is m
>>> built-in if USB and GADGET are built in.
>> 
>> I could only see a "select USB_OTG_CORE", select will always set it 'y'
>> and disregard dependencies. Maybe I missed something else.
>
> Not always. See how USB_COMMON works.

USB_COMMON is always 'y'. That could be changes a bool as well.

Do you have any defconfig where USB_COMMON or USB_OTG_CORE gets set to
'm'?

>>>>> +static DEFINE_MUTEX(otg_list_mutex);
>>>>> +
>>>>> +static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>>>>> +{
>>>>> +	if (!hcd->primary_hcd)
>>>>> +		return 1;
>>>>
>>>> these seems inverted. If hcd->primary is NULL (meaning, there's no
>>>> ->primary_hcd), then we tell caller that this _is_ a primary hcd? Care
>>>> to explain?
>>>
>>> hcd->primary_hcd is a link used by the shared hcd to point to the
>>> primary_hcd.  primary_hcd's have this link as NULL.
>> 
>> So the following check is unnecessary and should always evaluate to
>> false, right ?
>
> Actually primary_hcd's not having a shared HCD have hcd->primary_hcd as NULL
> and those having a shared HCD do have it pointing to the primary hcd.

But look at your check:

is_primary(struct usb_hcd *hcd)
{
	if (!hcd->primary_hcd)
        	return true;

	return hcd == hcd->primary_hcd;
}

if you're passing a primary hcd, you're gonna return on the first
branch. If you're passing a secondary hcd, then your equality will
always be false. 

IOW, this can be reduced to:

is_primary(struct usb_hcd *hcd)
{
	return !hcd->primary_hcd;
}

right?

>>>>> +int usb_otg_start_host(struct usb_otg *otg, int on)
>>>>> +{
>>>>> +	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
>>>>> +	int ret;
>>>>> +
>>>>> +	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
>>>>> +	if (!otg->host) {
>>>>> +		WARN_ONCE(1, "otg: fsm running without host\n");
>>>>
>>>> if (WARN_ONCE(!otg->host, "otg: fsm running without host\n"))
>>>> 	return 0;
>>>>
>>>> but, frankly, if you require a 'host' and a 'gadget' don't start this
>>>> layer until you have both.
>>>
>>> We don't start the layer till we have both host and gadget. But
>>> this API is for external use and might be called at any time.
>> 
>> well, if callers call this at the wrong time, it's callers' fault. Let
>> them oops so we catch the error.
>
> So you suggest we allow a NULL pointer dereference here?

yes, it's a clear violation of the API contract. The only situation
where this would ever trigger, is if somebody is calling
usb_otg_start_host() without calling start_fsm() first. That shouldn't
be valid.

>>>>> +		return 0;
>>>>> +	}
>>>>> +
>>>>> +	if (on) {
>>>>> +		if (otg->flags & OTG_FLAG_HOST_RUNNING)
>>>>> +			return 0;
>>>>> +
>>>>> +		/* start host */
>>>>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>>>>> +				   otg->primary_hcd.irqnum,
>>>>> +				   otg->primary_hcd.irqflags);
>>>>
>>>> this is usb_add_hcd(), is it not? Why add an indirection?
>>>
>>> I've introduced the host and gadget ops interface to get around the
>>> circular dependency issue we can't avoid.
>>> otg needs to call host/gadget functions and host/gadget also needs to
>>> call otg functions.
>> 
>> IMO, this shows a fragility of your design. You're, now, lying to
>> usb_hcd and usb_udc and making them register into a virtual layer that
>> doesn't exist. And that layer will end up calling the real registration
>> function when some magic event happens.
>> 
>> This is only really needed for quirky devices like dwc3 (but see more on
>> dwc3 below) where host and peripheral registers shadow each
>> other. Otherwise we would be able to always keep hcd and udc always
>> registered. They would get different interrupt statuses anyway and
>> nothing would ever break.
>
> Well I only had the opportunity to work with dwc3 so I had to ensure
> the design worked with it.

but this is exactly what I'm pointing you to. DWC3 does not need to go
through this because the HW maintains state machine for you.

>> However, when it comes to dwc3, we already have all the code necessary
>> to workaround this issue by destroying the XHCI pdev when OTG interrupt
>> says we should be peripheral (and vice-versa). DWC3 also keeps track of
>> the OTG states for those folks who really care about OTG (Hint: nobody
>> has cared for the past 10 years, why would they do so now?) and we don't
>> need a SW state machine when the HW handles that for us, right?
>
> Where is the code? I'd like to test dual-role on TI platforms.

Well, we just need an OTG IRQ handler to call dwc3_gadget_suspend() (or
that function renamed to match the usage) and something similar for the
host side.

It's all doable in a day or two.

>>> why? The kick could be triggered from an interrupt
>>> context. e.g. otg_irq.
>> 
>> We have threaded IRQ handlers in the kernel, right? Make use of that
>> and, with a little smart locking and IRQ masking, you can run the OTG
>> IRQ thread almost completely lockless ;-)
>
> Not a problem if we have the constraint that usb_otg_sync_inputs()
> needs to be called in thread context only.

that should be the case, right? If you're registering/unregistering
devices, you can't possibly call this from hardirq context.

>>>>> +	if (config->otg_work)	/* custom otg_work ? */
>>>>> +		INIT_WORK(&otg->work, config->otg_work);
>>>>> +	else
>>>>> +		INIT_WORK(&otg->work, usb_drd_work);
>>>>
>>>> why do you need to cope with custom work handlers?
>>>
>>> It was just a provision to provide your own state machine if the generic
>>> one does not meet your needs. But i'm OK to get rid of it as well.
>> 
>> If you allow for this, every time there is a limitation, people will
>> just provide a copy of the state machine with a small change here and
>> there instead of fixing the real issue.
>
> I agree with you here. I'll get rid of the custom_otg_work.

thanks

>>>>> +static void usb_otg_start_fsm(struct usb_otg *otg)
>>>>> +{
>>>>> +	struct otg_fsm *fsm = &otg->fsm;
>>>>> +
>>>>> +	if (fsm->running)
>>>>> +		goto kick_fsm;
>>>>> +
>>>>> +	if (!otg->host) {
>>>>> +		dev_info(otg->dev, "otg: can't start till host registers\n");
>>>>> +		return;
>>>>> +	}
>>>>> +
>>>>> +	if (!otg->gadget) {
>>>>> +		dev_info(otg->dev,
>>>>> +			 "otg: can't start till gadget UDC registers\n");
>>>>> +		return;
>>>>> +	}
>>>>
>>>> okay, so you never kick the FSM until host and gadget are
>>>> registered. Why do you need to test for the case where the FSM is
>>>> running without host/gadget?
>>>
>>> That message in the test was misleading. It could also be a
>>> used as a warning if users did something wrong.
>> 
>> this usb_otg_start_fsm() establishes a contract. That contract says that
>> the USB OTG FSM won't start until host and gadget are running and
>> registered, yada yada yada. Drivers trying to kicking the FSM without
>> calling usb_otg_start_fsm() first deserve to oops.
>
> I'm considering the worst case where OTG controller, host controller
> and gadget controller are 3 independent entities which can get probed
> in any order.

there is no such thing as OTG controller :-) Even in our wildest dreams,
the most we get is a multiplexer inside the SoC to mux signals to HCD or
UDC. DWC3, when configured as a dual-role-capable IP, has its own OTG
block. But that's all self-contained inside DWC3 itself :-)

> OTG controller driver doesn't really know when host and gadget
> register.  All it cares about is getting the hardware events and
> kicking the OTG machine.

Nothing should be kicking the OTG state machine anyways, until all parts
are ready, registered, running, etc.

> (NOTE: when I say OTG controller it might as well be just the
> dual-role bits that handle the ID and VBUS interrupts).

right

> usb_otg_start_fsm() is not public.
> usb_otg_sync_inputs() is the public function that the OTG driver will use.

the outcome is the same, right?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  2:30           ` Yoshihiro Shimoda
  0 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-21  2:30 UTC (permalink / raw)
  To: Roger Quadros, Felipe Balbi, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

Hi Roger,

> From: Roger Quadros
> Sent: Monday, June 20, 2016 7:13 PM
> 
> Hi,
> 
> On 20/06/16 10:45, Felipe Balbi wrote:
< snip >
> >> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> >> index f4fc0aa..1d74fb8 100644
> >> --- a/include/linux/usb/gadget.h
> >> +++ b/include/linux/usb/gadget.h
> >> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >>   * @in_epnum: last used in ep number
> >>   * @mA: last set mA value
> >>   * @otg_caps: OTG capabilities of this gadget.
> >> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >
> > do you really know of any platform which has a separate OTG controller?
> >
> 
> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> and gadget.
> 
> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> 
> Yoshihiro,
> 
> How is the dual-role architecture on your Renesas platform?

About the dual-role architecture, Renesas platform (R-Car H3) has a USB 2.0 host controller (EHCI/OHCI)
with OTG function and a separate USB 2.0 peripheral controller (HS-USB).
The OTG function is related to some PHY control registers, so I intend to add the OTG/Dual-role core
support into the phy driver (drivers/phy/phy-rcar-gen3-usb2.c).

Best regards,
Yoshihiro Shimoda

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  2:30           ` Yoshihiro Shimoda
  0 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-21  2:30 UTC (permalink / raw)
  To: Roger Quadros, Felipe Balbi, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Roger,

> From: Roger Quadros
> Sent: Monday, June 20, 2016 7:13 PM
> 
> Hi,
> 
> On 20/06/16 10:45, Felipe Balbi wrote:
< snip >
> >> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> >> index f4fc0aa..1d74fb8 100644
> >> --- a/include/linux/usb/gadget.h
> >> +++ b/include/linux/usb/gadget.h
> >> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >>   * @in_epnum: last used in ep number
> >>   * @mA: last set mA value
> >>   * @otg_caps: OTG capabilities of this gadget.
> >> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >
> > do you really know of any platform which has a separate OTG controller?
> >
> 
> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> and gadget.
> 
> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> 
> Yoshihiro,
> 
> How is the dual-role architecture on your Renesas platform?

About the dual-role architecture, Renesas platform (R-Car H3) has a USB 2.0 host controller (EHCI/OHCI)
with OTG function and a separate USB 2.0 peripheral controller (HS-USB).
The OTG function is related to some PHY control registers, so I intend to add the OTG/Dual-role core
support into the phy driver (drivers/phy/phy-rcar-gen3-usb2.c).

Best regards,
Yoshihiro Shimoda

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-20 12:08           ` Felipe Balbi
  (?)
@ 2016-06-21  6:05           ` Peter Chen
  2016-06-21  7:26               ` Felipe Balbi
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-21  6:05 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

On Mon, Jun 20, 2016 at 03:08:15PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> Roger Quadros <rogerq@ti.com> writes:
> >> > It provides APIs for the following tasks
> >> >
> >> > - Registering an OTG/dual-role capable controller
> >> > - Registering Host and Gadget controllers to OTG core
> >> > - Providing inputs to and kicking the OTG state machine
> >> 
> >> I think I have already mentioned this, but after over 10 years of OTG,
> >> nobody seems to care about it, why are we still touching at all I don't
> >> know. For common non-OTG role-swapping we really don't need any of this
> >> and, quite frankly, I fail to see enough users for this.
> >> 
> >> Apparently there's only chipidea which, AFAICT, already had working
> >> dual-role before this OTG State Machine was added to the kernel.
> >
> > Some users would like to know if vendor's platform is OTG compliance,
> > so we add it to pass usb.org USB OTG certification test.
> 
> I strongly doubt that's really what they mean. IMHO, users want to know
> if they can swap roles. Ask them if they are really going for OTG
> certification. Ask them if they have an OPT tester. Ask them if they
> really want all those timers. If they want HNP polling, etc etc etc.
> 
> So far, I haven't seen anybody talking about real USB OTG (the spec)
> when they say OTG. Usually they just mean "a method for swapping between
> host and peripheral roles, but we really don't want all the extra cost
> of the OTG specification".
> 

That's what I thought before, but the request from the Marketing guy is
"To prove the SoC is OTG compliance, support HNP and SRP", don't you
see the SoC reference manual say "it supports HNP and SRP"?

If there is no request, who else wants to implement so complicated FSM
but seldom use cases, and go to pass OTG compliance test (tested by PET).

> > For the real use case, some Carplay platforms need it.
> 
> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
> specification which is not OTG-compliant.
> 

Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
states to finish role swap. Notice, it needs to swap role without
disconnect cable.

> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> >> > index f4fc0aa..1d74fb8 100644
> >> > --- a/include/linux/usb/gadget.h
> >> > +++ b/include/linux/usb/gadget.h
> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >> >   * @in_epnum: last used in ep number
> >> >   * @mA: last set mA value
> >> >   * @otg_caps: OTG capabilities of this gadget.
> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> 
> >> do you really know of any platform which has a separate OTG controller?
> >> 
> >
> > It may not be a real separate OTG controller. It can be a hardware part
> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
> > ,id and other signals which are used for role swap.
> 
> That's already solved. EXTCON solved that years back and OMAP has been
> using EXTCON to program its UTMI mailbox.
> 

No, that's not the same thing, it does not include the swap role.
Consider the use case the host driver is at host/ and udc driver is
at gadget/udc, how to finish to role swap?

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-20 12:03         ` Felipe Balbi
  2016-06-20 12:26             ` Roger Quadros
@ 2016-06-21  6:39           ` Peter Chen
  2016-06-21  7:19               ` Felipe Balbi
  1 sibling, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-21  6:39 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Mon, Jun 20, 2016 at 03:03:37PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> >>> +
> >>> +		/* start host */
> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> >>> +				   otg->primary_hcd.irqnum,
> >>> +				   otg->primary_hcd.irqflags);
> >> 
> >> this is usb_add_hcd(), is it not? Why add an indirection?
> >
> > I've introduced the host and gadget ops interface to get around the
> > circular dependency issue we can't avoid.
> > otg needs to call host/gadget functions and host/gadget also needs to
> > call otg functions.
> 
> IMO, this shows a fragility of your design. You're, now, lying to
> usb_hcd and usb_udc and making them register into a virtual layer that
> doesn't exist. And that layer will end up calling the real registration
> function when some magic event happens.
> 
> This is only really needed for quirky devices like dwc3 (but see more on
> dwc3 below) where host and peripheral registers shadow each
> other. Otherwise we would be able to always keep hcd and udc always
> registered. They would get different interrupt statuses anyway and
> nothing would ever break.
> 
> However, when it comes to dwc3, we already have all the code necessary
> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> the OTG states for those folks who really care about OTG (Hint: nobody
> has cared for the past 10 years, why would they do so now?) and we don't
> need a SW state machine when the HW handles that for us, right?
> 
> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> I know very little about that IP and don't even have documentation on
> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> which changes roles automatically in HW based on ID pin state.

Chipidea needs to set register for USB role manually.

> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> 
> >> do you really know of any platform which has a separate OTG controller?
> >> 
> >
> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> > and gadget.
> >
> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> 
> that's not an OTG controller, it's just a mux. No different than Intel's
> mux for swapping between XHCI and peripheral-only DWC3.
> 
> frankly, I would NEVER talk about OTG when type-C comes into play. They
> are two competing standards and, apparently, type-C is winning when it
> comes to role-swapping.
> 

In fact, OTG is mis-used by people. Currently, if the port is dual-role,
It will be considered as an OTG port.

You are right, if the connector is type-c, it will be called as "type-c
port" by people :)

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  6:39           ` Peter Chen
@ 2016-06-21  7:19               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:19 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 3457 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >>> +
>> >>> +		/* start host */
>> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> >>> +				   otg->primary_hcd.irqnum,
>> >>> +				   otg->primary_hcd.irqflags);
>> >> 
>> >> this is usb_add_hcd(), is it not? Why add an indirection?
>> >
>> > I've introduced the host and gadget ops interface to get around the
>> > circular dependency issue we can't avoid.
>> > otg needs to call host/gadget functions and host/gadget also needs to
>> > call otg functions.
>> 
>> IMO, this shows a fragility of your design. You're, now, lying to
>> usb_hcd and usb_udc and making them register into a virtual layer that
>> doesn't exist. And that layer will end up calling the real registration
>> function when some magic event happens.
>> 
>> This is only really needed for quirky devices like dwc3 (but see more on
>> dwc3 below) where host and peripheral registers shadow each
>> other. Otherwise we would be able to always keep hcd and udc always
>> registered. They would get different interrupt statuses anyway and
>> nothing would ever break.
>> 
>> However, when it comes to dwc3, we already have all the code necessary
>> to workaround this issue by destroying the XHCI pdev when OTG interrupt
>> says we should be peripheral (and vice-versa). DWC3 also keeps track of
>> the OTG states for those folks who really care about OTG (Hint: nobody
>> has cared for the past 10 years, why would they do so now?) and we don't
>> need a SW state machine when the HW handles that for us, right?
>> 
>> As for chipidea, IIRC, that doesn't need a SW state machine either, but
>> I know very little about that IP and don't even have documentation on
>> it. My understanding, however, is that chipidea behaves kinda like MUSB,
>> which changes roles automatically in HW based on ID pin state.
>
> Chipidea needs to set register for USB role manually.

okay, so chipidea has private control of role. Much like dwc3. That's good.

>> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> 
>> >> do you really know of any platform which has a separate OTG controller?
>> >> 
>> >
>> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> > and gadget.
>> >
>> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> 
>> that's not an OTG controller, it's just a mux. No different than Intel's
>> mux for swapping between XHCI and peripheral-only DWC3.
>> 
>> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> are two competing standards and, apparently, type-C is winning when it
>> comes to role-swapping.
>> 
>
> In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> It will be considered as an OTG port.

That's because "dual-role" is a non-standard OTG. Seen as people really
didn't care about OTG, we (linux-usb folks) ended up naturally referring
to "non-standard OTG" as "dual-role". Just to avoid confusion.

> You are right, if the connector is type-c, it will be called as "type-c
> port" by people :)

oh no, that's not what I'm talking about. If you read Type-C and PD
specs, they define their own method for data role swapping. USB OTG
doesn't fit on top of a Type-C environment. It's not about what people
will call it, it's really that OTG can't work on top of type-c. For
starters, there's no ID pin ;-)

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  7:19               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:19 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 3487 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >>> +
>> >>> +		/* start host */
>> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> >>> +				   otg->primary_hcd.irqnum,
>> >>> +				   otg->primary_hcd.irqflags);
>> >> 
>> >> this is usb_add_hcd(), is it not? Why add an indirection?
>> >
>> > I've introduced the host and gadget ops interface to get around the
>> > circular dependency issue we can't avoid.
>> > otg needs to call host/gadget functions and host/gadget also needs to
>> > call otg functions.
>> 
>> IMO, this shows a fragility of your design. You're, now, lying to
>> usb_hcd and usb_udc and making them register into a virtual layer that
>> doesn't exist. And that layer will end up calling the real registration
>> function when some magic event happens.
>> 
>> This is only really needed for quirky devices like dwc3 (but see more on
>> dwc3 below) where host and peripheral registers shadow each
>> other. Otherwise we would be able to always keep hcd and udc always
>> registered. They would get different interrupt statuses anyway and
>> nothing would ever break.
>> 
>> However, when it comes to dwc3, we already have all the code necessary
>> to workaround this issue by destroying the XHCI pdev when OTG interrupt
>> says we should be peripheral (and vice-versa). DWC3 also keeps track of
>> the OTG states for those folks who really care about OTG (Hint: nobody
>> has cared for the past 10 years, why would they do so now?) and we don't
>> need a SW state machine when the HW handles that for us, right?
>> 
>> As for chipidea, IIRC, that doesn't need a SW state machine either, but
>> I know very little about that IP and don't even have documentation on
>> it. My understanding, however, is that chipidea behaves kinda like MUSB,
>> which changes roles automatically in HW based on ID pin state.
>
> Chipidea needs to set register for USB role manually.

okay, so chipidea has private control of role. Much like dwc3. That's good.

>> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> 
>> >> do you really know of any platform which has a separate OTG controller?
>> >> 
>> >
>> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> > and gadget.
>> >
>> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> 
>> that's not an OTG controller, it's just a mux. No different than Intel's
>> mux for swapping between XHCI and peripheral-only DWC3.
>> 
>> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> are two competing standards and, apparently, type-C is winning when it
>> comes to role-swapping.
>> 
>
> In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> It will be considered as an OTG port.

That's because "dual-role" is a non-standard OTG. Seen as people really
didn't care about OTG, we (linux-usb folks) ended up naturally referring
to "non-standard OTG" as "dual-role". Just to avoid confusion.

> You are right, if the connector is type-c, it will be called as "type-c
> port" by people :)

oh no, that's not what I'm talking about. If you read Type-C and PD
specs, they define their own method for data role swapping. USB OTG
doesn't fit on top of a Type-C environment. It's not about what people
will call it, it's really that OTG can't work on top of type-c. For
starters, there's no ID pin ;-)

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  7:21             ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:21 UTC (permalink / raw)
  To: Yoshihiro Shimoda, Roger Quadros, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 1464 bytes --]


Hi,

Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> writes:
> Hi Roger,
>
>> From: Roger Quadros
>> Sent: Monday, June 20, 2016 7:13 PM
>> 
>> Hi,
>> 
>> On 20/06/16 10:45, Felipe Balbi wrote:
> < snip >
>> >> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> >> index f4fc0aa..1d74fb8 100644
>> >> --- a/include/linux/usb/gadget.h
>> >> +++ b/include/linux/usb/gadget.h
>> >> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >>   * @in_epnum: last used in ep number
>> >>   * @mA: last set mA value
>> >>   * @otg_caps: OTG capabilities of this gadget.
>> >> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >
>> > do you really know of any platform which has a separate OTG controller?
>> >
>> 
>> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> and gadget.
>> 
>> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> 
>> Yoshihiro,
>> 
>> How is the dual-role architecture on your Renesas platform?
>
> About the dual-role architecture, Renesas platform (R-Car H3) has a
> USB 2.0 host controller (EHCI/OHCI) with OTG function and a separate
> USB 2.0 peripheral controller (HS-USB).  The OTG function is related
> to some PHY control registers, so I intend to add the OTG/Dual-role
> core support into the phy driver (drivers/phy/phy-rcar-gen3-usb2.c).

that looks like a mux to me :-) thanks for the pointer

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  7:21             ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:21 UTC (permalink / raw)
  To: Yoshihiro Shimoda, Roger Quadros, peter.chen@freescale.com
  Cc: tony@atomide.com, gregkh@linuxfoundation.org,
	dan.j.williams@intel.com, mathias.nyman@linux.intel.com,
	Joao.Pinto@synopsys.com, sergei.shtylyov@cogentembedded.com,
	jun.li@freescale.com, grygorii.strashko@ti.com, robh@kernel.org,
	nsekhar@ti.com, b-liu@ti.com, joe@perches.com,
	linux-usb@vger.kernel.org, linux-omap@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org

[-- Attachment #1: Type: text/plain, Size: 1492 bytes --]


Hi,

Yoshihiro Shimoda <yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> writes:
> Hi Roger,
>
>> From: Roger Quadros
>> Sent: Monday, June 20, 2016 7:13 PM
>> 
>> Hi,
>> 
>> On 20/06/16 10:45, Felipe Balbi wrote:
> < snip >
>> >> diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> >> index f4fc0aa..1d74fb8 100644
>> >> --- a/include/linux/usb/gadget.h
>> >> +++ b/include/linux/usb/gadget.h
>> >> @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >>   * @in_epnum: last used in ep number
>> >>   * @mA: last set mA value
>> >>   * @otg_caps: OTG capabilities of this gadget.
>> >> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >
>> > do you really know of any platform which has a separate OTG controller?
>> >
>> 
>> Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> and gadget.
>> 
>> [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> 
>> Yoshihiro,
>> 
>> How is the dual-role architecture on your Renesas platform?
>
> About the dual-role architecture, Renesas platform (R-Car H3) has a
> USB 2.0 host controller (EHCI/OHCI) with OTG function and a separate
> USB 2.0 peripheral controller (HS-USB).  The OTG function is related
> to some PHY control registers, so I intend to add the OTG/Dual-role
> core support into the phy driver (drivers/phy/phy-rcar-gen3-usb2.c).

that looks like a mux to me :-) thanks for the pointer

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  6:05           ` Peter Chen
@ 2016-06-21  7:26               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:26 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 4125 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> > It provides APIs for the following tasks
>> >> >
>> >> > - Registering an OTG/dual-role capable controller
>> >> > - Registering Host and Gadget controllers to OTG core
>> >> > - Providing inputs to and kicking the OTG state machine
>> >> 
>> >> I think I have already mentioned this, but after over 10 years of OTG,
>> >> nobody seems to care about it, why are we still touching at all I don't
>> >> know. For common non-OTG role-swapping we really don't need any of this
>> >> and, quite frankly, I fail to see enough users for this.
>> >> 
>> >> Apparently there's only chipidea which, AFAICT, already had working
>> >> dual-role before this OTG State Machine was added to the kernel.
>> >
>> > Some users would like to know if vendor's platform is OTG compliance,
>> > so we add it to pass usb.org USB OTG certification test.
>> 
>> I strongly doubt that's really what they mean. IMHO, users want to know
>> if they can swap roles. Ask them if they are really going for OTG
>> certification. Ask them if they have an OPT tester. Ask them if they
>> really want all those timers. If they want HNP polling, etc etc etc.
>> 
>> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> when they say OTG. Usually they just mean "a method for swapping between
>> host and peripheral roles, but we really don't want all the extra cost
>> of the OTG specification".
>> 
>
> That's what I thought before, but the request from the Marketing guy is
> "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> see the SoC reference manual say "it supports HNP and SRP"?
>
> If there is no request, who else wants to implement so complicated FSM
> but seldom use cases, and go to pass OTG compliance test (tested by PET).

I stand corrected :-)

So there is one user for this layer. And this user has its own role
control registers. I'm not convinced we need this large generic layer
for one user.

>> > For the real use case, some Carplay platforms need it.
>> 
>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>> specification which is not OTG-compliant.
>> 
>
> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> states to finish role swap.

What are you referring to as "finish role swap"? I don't get that.

> Notice, it needs to swap role without disconnect cable.

right, I can swap role without changing cable, but that's not OTG. The
mechanism for that, AFAICT, is not HNP. I don't know details about
CarPlay because the spec isn't public, but my understanding is that
CarPlay doesn't rely on anything from OTG spec.

>> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> >> > index f4fc0aa..1d74fb8 100644
>> >> > --- a/include/linux/usb/gadget.h
>> >> > +++ b/include/linux/usb/gadget.h
>> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >> >   * @in_epnum: last used in ep number
>> >> >   * @mA: last set mA value
>> >> >   * @otg_caps: OTG capabilities of this gadget.
>> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> 
>> >> do you really know of any platform which has a separate OTG controller?
>> >> 
>> >
>> > It may not be a real separate OTG controller. It can be a hardware part
>> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
>> > ,id and other signals which are used for role swap.
>> 
>> That's already solved. EXTCON solved that years back and OMAP has been
>> using EXTCON to program its UTMI mailbox.
>> 
>
> No, that's not the same thing, it does not include the swap role.

Read your original comment:

"handle vbus, id and other signals which are *used for* role swap"

You didn't include role swap in your original comment. Semantics aside...

> Consider the use case the host driver is at host/ and udc driver is
> at gadget/udc, how to finish to role swap?

... why does the source code placement matter? And what do you mean by
"finish role swap"?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  7:26               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  7:26 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 4155 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> > It provides APIs for the following tasks
>> >> >
>> >> > - Registering an OTG/dual-role capable controller
>> >> > - Registering Host and Gadget controllers to OTG core
>> >> > - Providing inputs to and kicking the OTG state machine
>> >> 
>> >> I think I have already mentioned this, but after over 10 years of OTG,
>> >> nobody seems to care about it, why are we still touching at all I don't
>> >> know. For common non-OTG role-swapping we really don't need any of this
>> >> and, quite frankly, I fail to see enough users for this.
>> >> 
>> >> Apparently there's only chipidea which, AFAICT, already had working
>> >> dual-role before this OTG State Machine was added to the kernel.
>> >
>> > Some users would like to know if vendor's platform is OTG compliance,
>> > so we add it to pass usb.org USB OTG certification test.
>> 
>> I strongly doubt that's really what they mean. IMHO, users want to know
>> if they can swap roles. Ask them if they are really going for OTG
>> certification. Ask them if they have an OPT tester. Ask them if they
>> really want all those timers. If they want HNP polling, etc etc etc.
>> 
>> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> when they say OTG. Usually they just mean "a method for swapping between
>> host and peripheral roles, but we really don't want all the extra cost
>> of the OTG specification".
>> 
>
> That's what I thought before, but the request from the Marketing guy is
> "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> see the SoC reference manual say "it supports HNP and SRP"?
>
> If there is no request, who else wants to implement so complicated FSM
> but seldom use cases, and go to pass OTG compliance test (tested by PET).

I stand corrected :-)

So there is one user for this layer. And this user has its own role
control registers. I'm not convinced we need this large generic layer
for one user.

>> > For the real use case, some Carplay platforms need it.
>> 
>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>> specification which is not OTG-compliant.
>> 
>
> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> states to finish role swap.

What are you referring to as "finish role swap"? I don't get that.

> Notice, it needs to swap role without disconnect cable.

right, I can swap role without changing cable, but that's not OTG. The
mechanism for that, AFAICT, is not HNP. I don't know details about
CarPlay because the spec isn't public, but my understanding is that
CarPlay doesn't rely on anything from OTG spec.

>> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> >> > index f4fc0aa..1d74fb8 100644
>> >> > --- a/include/linux/usb/gadget.h
>> >> > +++ b/include/linux/usb/gadget.h
>> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >> >   * @in_epnum: last used in ep number
>> >> >   * @mA: last set mA value
>> >> >   * @otg_caps: OTG capabilities of this gadget.
>> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> 
>> >> do you really know of any platform which has a separate OTG controller?
>> >> 
>> >
>> > It may not be a real separate OTG controller. It can be a hardware part
>> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
>> > ,id and other signals which are used for role swap.
>> 
>> That's already solved. EXTCON solved that years back and OMAP has been
>> using EXTCON to program its UTMI mailbox.
>> 
>
> No, that's not the same thing, it does not include the swap role.

Read your original comment:

"handle vbus, id and other signals which are *used for* role swap"

You didn't include role swap in your original comment. Semantics aside...

> Consider the use case the host driver is at host/ and udc driver is
> at gadget/udc, how to finish to role swap?

... why does the source code placement matter? And what do you mean by
"finish role swap"?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  7:19               ` Felipe Balbi
  (?)
@ 2016-06-21  8:02               ` Peter Chen
  2016-06-21  8:18                   ` Felipe Balbi
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-21  8:02 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 10:19:32AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >>> +
> >> >>> +		/* start host */
> >> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> >> >>> +				   otg->primary_hcd.irqnum,
> >> >>> +				   otg->primary_hcd.irqflags);
> >> >> 
> >> >> this is usb_add_hcd(), is it not? Why add an indirection?
> >> >
> >> > I've introduced the host and gadget ops interface to get around the
> >> > circular dependency issue we can't avoid.
> >> > otg needs to call host/gadget functions and host/gadget also needs to
> >> > call otg functions.
> >> 
> >> IMO, this shows a fragility of your design. You're, now, lying to
> >> usb_hcd and usb_udc and making them register into a virtual layer that
> >> doesn't exist. And that layer will end up calling the real registration
> >> function when some magic event happens.
> >> 
> >> This is only really needed for quirky devices like dwc3 (but see more on
> >> dwc3 below) where host and peripheral registers shadow each
> >> other. Otherwise we would be able to always keep hcd and udc always
> >> registered. They would get different interrupt statuses anyway and
> >> nothing would ever break.
> >> 
> >> However, when it comes to dwc3, we already have all the code necessary
> >> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> >> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> >> the OTG states for those folks who really care about OTG (Hint: nobody
> >> has cared for the past 10 years, why would they do so now?) and we don't
> >> need a SW state machine when the HW handles that for us, right?
> >> 
> >> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> >> I know very little about that IP and don't even have documentation on
> >> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> >> which changes roles automatically in HW based on ID pin state.
> >
> > Chipidea needs to set register for USB role manually.
> 
> okay, so chipidea has private control of role. Much like dwc3. That's good.
> 
> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> 
> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> 
> >> >
> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> > and gadget.
> >> >
> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> 
> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> 
> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> are two competing standards and, apparently, type-C is winning when it
> >> comes to role-swapping.
> >> 
> >
> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> > It will be considered as an OTG port.
> 
> That's because "dual-role" is a non-standard OTG. Seen as people really
> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> to "non-standard OTG" as "dual-role". Just to avoid confusion.

So, unless we use OTG FSM defined in OTG spec, we should not mention
"OTG" in Linux, right?
 
> 
> > You are right, if the connector is type-c, it will be called as "type-c
> > port" by people :)
> 
> oh no, that's not what I'm talking about. If you read Type-C and PD
> specs, they define their own method for data role swapping. USB OTG
> doesn't fit on top of a Type-C environment. It's not about what people
> will call it, it's really that OTG can't work on top of type-c. For
> starters, there's no ID pin ;-)

I know type-c, yes, there is no relationship between OTG and type-c.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  8:02               ` Peter Chen
@ 2016-06-21  8:18                   ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  8:18 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 4064 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >>> +
>> >> >>> +		/* start host */
>> >> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> >> >>> +				   otg->primary_hcd.irqnum,
>> >> >>> +				   otg->primary_hcd.irqflags);
>> >> >> 
>> >> >> this is usb_add_hcd(), is it not? Why add an indirection?
>> >> >
>> >> > I've introduced the host and gadget ops interface to get around the
>> >> > circular dependency issue we can't avoid.
>> >> > otg needs to call host/gadget functions and host/gadget also needs to
>> >> > call otg functions.
>> >> 
>> >> IMO, this shows a fragility of your design. You're, now, lying to
>> >> usb_hcd and usb_udc and making them register into a virtual layer that
>> >> doesn't exist. And that layer will end up calling the real registration
>> >> function when some magic event happens.
>> >> 
>> >> This is only really needed for quirky devices like dwc3 (but see more on
>> >> dwc3 below) where host and peripheral registers shadow each
>> >> other. Otherwise we would be able to always keep hcd and udc always
>> >> registered. They would get different interrupt statuses anyway and
>> >> nothing would ever break.
>> >> 
>> >> However, when it comes to dwc3, we already have all the code necessary
>> >> to workaround this issue by destroying the XHCI pdev when OTG interrupt
>> >> says we should be peripheral (and vice-versa). DWC3 also keeps track of
>> >> the OTG states for those folks who really care about OTG (Hint: nobody
>> >> has cared for the past 10 years, why would they do so now?) and we don't
>> >> need a SW state machine when the HW handles that for us, right?
>> >> 
>> >> As for chipidea, IIRC, that doesn't need a SW state machine either, but
>> >> I know very little about that IP and don't even have documentation on
>> >> it. My understanding, however, is that chipidea behaves kinda like MUSB,
>> >> which changes roles automatically in HW based on ID pin state.
>> >
>> > Chipidea needs to set register for USB role manually.
>> 
>> okay, so chipidea has private control of role. Much like dwc3. That's good.
>> 
>> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> 
>> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> 
>> >> >
>> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> >> > and gadget.
>> >> >
>> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> >> 
>> >> that's not an OTG controller, it's just a mux. No different than Intel's
>> >> mux for swapping between XHCI and peripheral-only DWC3.
>> >> 
>> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> >> are two competing standards and, apparently, type-C is winning when it
>> >> comes to role-swapping.
>> >> 
>> >
>> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
>> > It will be considered as an OTG port.
>> 
>> That's because "dual-role" is a non-standard OTG. Seen as people really
>> didn't care about OTG, we (linux-usb folks) ended up naturally referring
>> to "non-standard OTG" as "dual-role". Just to avoid confusion.
>
> So, unless we use OTG FSM defined in OTG spec, we should not mention
> "OTG" in Linux, right?

to avoid confusion with the terminology, yes. With that settled, let's
figure out how you can deliver what your marketting guys are asking of
you.

>> > You are right, if the connector is type-c, it will be called as "type-c
>> > port" by people :)
>> 
>> oh no, that's not what I'm talking about. If you read Type-C and PD
>> specs, they define their own method for data role swapping. USB OTG
>> doesn't fit on top of a Type-C environment. It's not about what people
>> will call it, it's really that OTG can't work on top of type-c. For
>> starters, there's no ID pin ;-)
>
> I know type-c, yes, there is no relationship between OTG and type-c.

okay, thanks

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  8:18                   ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21  8:18 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 4124 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> >>> +
>> >> >>> +		/* start host */
>> >> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
>> >> >>> +				   otg->primary_hcd.irqnum,
>> >> >>> +				   otg->primary_hcd.irqflags);
>> >> >> 
>> >> >> this is usb_add_hcd(), is it not? Why add an indirection?
>> >> >
>> >> > I've introduced the host and gadget ops interface to get around the
>> >> > circular dependency issue we can't avoid.
>> >> > otg needs to call host/gadget functions and host/gadget also needs to
>> >> > call otg functions.
>> >> 
>> >> IMO, this shows a fragility of your design. You're, now, lying to
>> >> usb_hcd and usb_udc and making them register into a virtual layer that
>> >> doesn't exist. And that layer will end up calling the real registration
>> >> function when some magic event happens.
>> >> 
>> >> This is only really needed for quirky devices like dwc3 (but see more on
>> >> dwc3 below) where host and peripheral registers shadow each
>> >> other. Otherwise we would be able to always keep hcd and udc always
>> >> registered. They would get different interrupt statuses anyway and
>> >> nothing would ever break.
>> >> 
>> >> However, when it comes to dwc3, we already have all the code necessary
>> >> to workaround this issue by destroying the XHCI pdev when OTG interrupt
>> >> says we should be peripheral (and vice-versa). DWC3 also keeps track of
>> >> the OTG states for those folks who really care about OTG (Hint: nobody
>> >> has cared for the past 10 years, why would they do so now?) and we don't
>> >> need a SW state machine when the HW handles that for us, right?
>> >> 
>> >> As for chipidea, IIRC, that doesn't need a SW state machine either, but
>> >> I know very little about that IP and don't even have documentation on
>> >> it. My understanding, however, is that chipidea behaves kinda like MUSB,
>> >> which changes roles automatically in HW based on ID pin state.
>> >
>> > Chipidea needs to set register for USB role manually.
>> 
>> okay, so chipidea has private control of role. Much like dwc3. That's good.
>> 
>> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> 
>> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> 
>> >> >
>> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> >> > and gadget.
>> >> >
>> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> >> 
>> >> that's not an OTG controller, it's just a mux. No different than Intel's
>> >> mux for swapping between XHCI and peripheral-only DWC3.
>> >> 
>> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> >> are two competing standards and, apparently, type-C is winning when it
>> >> comes to role-swapping.
>> >> 
>> >
>> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
>> > It will be considered as an OTG port.
>> 
>> That's because "dual-role" is a non-standard OTG. Seen as people really
>> didn't care about OTG, we (linux-usb folks) ended up naturally referring
>> to "non-standard OTG" as "dual-role". Just to avoid confusion.
>
> So, unless we use OTG FSM defined in OTG spec, we should not mention
> "OTG" in Linux, right?

to avoid confusion with the terminology, yes. With that settled, let's
figure out how you can deliver what your marketting guys are asking of
you.

>> > You are right, if the connector is type-c, it will be called as "type-c
>> > port" by people :)
>> 
>> oh no, that's not what I'm talking about. If you read Type-C and PD
>> specs, they define their own method for data role swapping. USB OTG
>> doesn't fit on top of a Type-C environment. It's not about what people
>> will call it, it's really that OTG can't work on top of type-c. For
>> starters, there's no ID pin ;-)
>
> I know type-c, yes, there is no relationship between OTG and type-c.

okay, thanks

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  9:07                 ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21  9:07 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 10:26:00AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> >> 
> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
> >> when they say OTG. Usually they just mean "a method for swapping between
> >> host and peripheral roles, but we really don't want all the extra cost
> >> of the OTG specification".
> >> 
> >
> > That's what I thought before, but the request from the Marketing guy is
> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> > see the SoC reference manual say "it supports HNP and SRP"?
> >
> > If there is no request, who else wants to implement so complicated FSM
> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
> 
> I stand corrected :-)
> 
> So there is one user for this layer. And this user has its own role
> control registers. I'm not convinced we need this large generic layer
> for one user.
> 

You mean chipidea or dwc3? I have more comments below.

> >> > For the real use case, some Carplay platforms need it.
> >> 
> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
> >> specification which is not OTG-compliant.
> >> 
> >
> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> > states to finish role swap.
> 
> What are you referring to as "finish role swap"? I don't get that.

Change current role from host to peripheral.

> 
> > Notice, it needs to swap role without disconnect cable.
> 
> right, I can swap role without changing cable, but that's not OTG. The
> mechanism for that, AFAICT, is not HNP. I don't know details about
> CarPlay because the spec isn't public, but my understanding is that
> CarPlay doesn't rely on anything from OTG spec.

Since it is non-public, I can't say much. Some flows of its role-swap
refers to On-The-Go and Embedded Host Supplement to the USB Revision 2.0
Specification. 

But OTG FSM is not the only way, the platform which can do role-swap
without disconnection can support it too.

> 
> >> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> >> >> > index f4fc0aa..1d74fb8 100644
> >> >> > --- a/include/linux/usb/gadget.h
> >> >> > +++ b/include/linux/usb/gadget.h
> >> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >> >> >   * @in_epnum: last used in ep number
> >> >> >   * @mA: last set mA value
> >> >> >   * @otg_caps: OTG capabilities of this gadget.
> >> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> 
> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> 
> >> >
> >> > It may not be a real separate OTG controller. It can be a hardware part
> >> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
> >> > ,id and other signals which are used for role swap.
> >> 
> >> That's already solved. EXTCON solved that years back and OMAP has been
> >> using EXTCON to program its UTMI mailbox.
> >> 
> >
> > No, that's not the same thing, it does not include the swap role.
> 
> Read your original comment:
> 
> "handle vbus, id and other signals which are *used for* role swap"
> 
> You didn't include role swap in your original comment. Semantics aside...
> 
> > Consider the use case the host driver is at host/ and udc driver is
> > at gadget/udc, how to finish to role swap?
> 
> ... why does the source code placement matter? And what do you mean by
> "finish role swap"?
> 

Well, it depends on your driver design, do you want the host driver's
API is still be called when current role is peripheral? One typical
problem you can refer below:

commit 11c011a5e777c83819078a18672543f04482b3ec
Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Date:   Thu May 19 11:12:56 2016 +0100

    usb: echi-hcd: Add ehci_setup check before echi_shutdown
        


In some cases, the USB code (gadget/hcd->start/stop) needs to be called
during the role swap. For example, if you have mux driver, you may
need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
how can we do that?

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  9:07                 ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21  9:07 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, Jun 21, 2016 at 10:26:00AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> >> 
> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
> >> when they say OTG. Usually they just mean "a method for swapping between
> >> host and peripheral roles, but we really don't want all the extra cost
> >> of the OTG specification".
> >> 
> >
> > That's what I thought before, but the request from the Marketing guy is
> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> > see the SoC reference manual say "it supports HNP and SRP"?
> >
> > If there is no request, who else wants to implement so complicated FSM
> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
> 
> I stand corrected :-)
> 
> So there is one user for this layer. And this user has its own role
> control registers. I'm not convinced we need this large generic layer
> for one user.
> 

You mean chipidea or dwc3? I have more comments below.

> >> > For the real use case, some Carplay platforms need it.
> >> 
> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
> >> specification which is not OTG-compliant.
> >> 
> >
> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> > states to finish role swap.
> 
> What are you referring to as "finish role swap"? I don't get that.

Change current role from host to peripheral.

> 
> > Notice, it needs to swap role without disconnect cable.
> 
> right, I can swap role without changing cable, but that's not OTG. The
> mechanism for that, AFAICT, is not HNP. I don't know details about
> CarPlay because the spec isn't public, but my understanding is that
> CarPlay doesn't rely on anything from OTG spec.

Since it is non-public, I can't say much. Some flows of its role-swap
refers to On-The-Go and Embedded Host Supplement to the USB Revision 2.0
Specification. 

But OTG FSM is not the only way, the platform which can do role-swap
without disconnection can support it too.

> 
> >> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
> >> >> > index f4fc0aa..1d74fb8 100644
> >> >> > --- a/include/linux/usb/gadget.h
> >> >> > +++ b/include/linux/usb/gadget.h
> >> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
> >> >> >   * @in_epnum: last used in ep number
> >> >> >   * @mA: last set mA value
> >> >> >   * @otg_caps: OTG capabilities of this gadget.
> >> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> 
> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> 
> >> >
> >> > It may not be a real separate OTG controller. It can be a hardware part
> >> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
> >> > ,id and other signals which are used for role swap.
> >> 
> >> That's already solved. EXTCON solved that years back and OMAP has been
> >> using EXTCON to program its UTMI mailbox.
> >> 
> >
> > No, that's not the same thing, it does not include the swap role.
> 
> Read your original comment:
> 
> "handle vbus, id and other signals which are *used for* role swap"
> 
> You didn't include role swap in your original comment. Semantics aside...
> 
> > Consider the use case the host driver is at host/ and udc driver is
> > at gadget/udc, how to finish to role swap?
> 
> ... why does the source code placement matter? And what do you mean by
> "finish role swap"?
> 

Well, it depends on your driver design, do you want the host driver's
API is still be called when current role is peripheral? One typical
problem you can refer below:

commit 11c011a5e777c83819078a18672543f04482b3ec
Author: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Date:   Thu May 19 11:12:56 2016 +0100

    usb: echi-hcd: Add ehci_setup check before echi_shutdown
        


In some cases, the USB code (gadget/hcd->start/stop) needs to be called
during the role swap. For example, if you have mux driver, you may
need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
how can we do that?

-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  9:14                     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21  9:14 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 11:18:21AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> >>> +
> >> >> >>> +		/* start host */
> >> >> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> >> >> >>> +				   otg->primary_hcd.irqnum,
> >> >> >>> +				   otg->primary_hcd.irqflags);
> >> >> >> 
> >> >> >> this is usb_add_hcd(), is it not? Why add an indirection?
> >> >> >
> >> >> > I've introduced the host and gadget ops interface to get around the
> >> >> > circular dependency issue we can't avoid.
> >> >> > otg needs to call host/gadget functions and host/gadget also needs to
> >> >> > call otg functions.
> >> >> 
> >> >> IMO, this shows a fragility of your design. You're, now, lying to
> >> >> usb_hcd and usb_udc and making them register into a virtual layer that
> >> >> doesn't exist. And that layer will end up calling the real registration
> >> >> function when some magic event happens.
> >> >> 
> >> >> This is only really needed for quirky devices like dwc3 (but see more on
> >> >> dwc3 below) where host and peripheral registers shadow each
> >> >> other. Otherwise we would be able to always keep hcd and udc always
> >> >> registered. They would get different interrupt statuses anyway and
> >> >> nothing would ever break.
> >> >> 
> >> >> However, when it comes to dwc3, we already have all the code necessary
> >> >> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> >> >> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> >> >> the OTG states for those folks who really care about OTG (Hint: nobody
> >> >> has cared for the past 10 years, why would they do so now?) and we don't
> >> >> need a SW state machine when the HW handles that for us, right?
> >> >> 
> >> >> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> >> >> I know very little about that IP and don't even have documentation on
> >> >> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> >> >> which changes roles automatically in HW based on ID pin state.
> >> >
> >> > Chipidea needs to set register for USB role manually.
> >> 
> >> okay, so chipidea has private control of role. Much like dwc3. That's good.
> >> 
> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> >> 
> >> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> >> 
> >> >> >
> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> >> > and gadget.
> >> >> >
> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> >> 
> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> >> 
> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> >> are two competing standards and, apparently, type-C is winning when it
> >> >> comes to role-swapping.
> >> >> 
> >> >
> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> >> > It will be considered as an OTG port.
> >> 
> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> >
> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> > "OTG" in Linux, right?
> 
> to avoid confusion with the terminology, yes. With that settled, let's
> figure out how you can deliver what your marketting guys are asking of
> you.
> 

Since nxp SoC claims they are OTG compliance, we need to pass usb.org
test. The internal bsp has passed PET test, and formal compliance test
is on the way (should pass too). 

The dual-role and OTG compliance use the same zImage, but different
dtb.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21  9:14                     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21  9:14 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, Jun 21, 2016 at 11:18:21AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> >> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> >> >> >>> +
> >> >> >>> +		/* start host */
> >> >> >>> +		ret = hcd_ops->add(otg->primary_hcd.hcd,
> >> >> >>> +				   otg->primary_hcd.irqnum,
> >> >> >>> +				   otg->primary_hcd.irqflags);
> >> >> >> 
> >> >> >> this is usb_add_hcd(), is it not? Why add an indirection?
> >> >> >
> >> >> > I've introduced the host and gadget ops interface to get around the
> >> >> > circular dependency issue we can't avoid.
> >> >> > otg needs to call host/gadget functions and host/gadget also needs to
> >> >> > call otg functions.
> >> >> 
> >> >> IMO, this shows a fragility of your design. You're, now, lying to
> >> >> usb_hcd and usb_udc and making them register into a virtual layer that
> >> >> doesn't exist. And that layer will end up calling the real registration
> >> >> function when some magic event happens.
> >> >> 
> >> >> This is only really needed for quirky devices like dwc3 (but see more on
> >> >> dwc3 below) where host and peripheral registers shadow each
> >> >> other. Otherwise we would be able to always keep hcd and udc always
> >> >> registered. They would get different interrupt statuses anyway and
> >> >> nothing would ever break.
> >> >> 
> >> >> However, when it comes to dwc3, we already have all the code necessary
> >> >> to workaround this issue by destroying the XHCI pdev when OTG interrupt
> >> >> says we should be peripheral (and vice-versa). DWC3 also keeps track of
> >> >> the OTG states for those folks who really care about OTG (Hint: nobody
> >> >> has cared for the past 10 years, why would they do so now?) and we don't
> >> >> need a SW state machine when the HW handles that for us, right?
> >> >> 
> >> >> As for chipidea, IIRC, that doesn't need a SW state machine either, but
> >> >> I know very little about that IP and don't even have documentation on
> >> >> it. My understanding, however, is that chipidea behaves kinda like MUSB,
> >> >> which changes roles automatically in HW based on ID pin state.
> >> >
> >> > Chipidea needs to set register for USB role manually.
> >> 
> >> okay, so chipidea has private control of role. Much like dwc3. That's good.
> >> 
> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> >> 
> >> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> >> 
> >> >> >
> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> >> > and gadget.
> >> >> >
> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> >> 
> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> >> 
> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> >> are two competing standards and, apparently, type-C is winning when it
> >> >> comes to role-swapping.
> >> >> 
> >> >
> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> >> > It will be considered as an OTG port.
> >> 
> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> >
> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> > "OTG" in Linux, right?
> 
> to avoid confusion with the terminology, yes. With that settled, let's
> figure out how you can deliver what your marketting guys are asking of
> you.
> 

Since nxp SoC claims they are OTG compliance, we need to pass usb.org
test. The internal bsp has passed PET test, and formal compliance test
is on the way (should pass too). 

The dual-role and OTG compliance use the same zImage, but different
dtb.

-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  9:07                 ` Peter Chen
  (?)
@ 2016-06-21 10:02                 ` Felipe Balbi
  2016-06-21 10:43                     ` Tony Lindgren
  2016-06-21 13:05                     ` Peter Chen
  -1 siblings, 2 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21 10:02 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 7149 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> >> when they say OTG. Usually they just mean "a method for swapping between
>> >> host and peripheral roles, but we really don't want all the extra cost
>> >> of the OTG specification".
>> >> 
>> >
>> > That's what I thought before, but the request from the Marketing guy is
>> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>> > see the SoC reference manual say "it supports HNP and SRP"?
>> >
>> > If there is no request, who else wants to implement so complicated FSM
>> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
>> 
>> I stand corrected :-)
>> 
>> So there is one user for this layer. And this user has its own role
>> control registers. I'm not convinced we need this large generic layer
>> for one user.
>> 
>
> You mean chipidea or dwc3? I have more comments below.

chipidea. From the point of OTG (or DRD) dwc3 is very
self-sufficient. HW itself tracks state machine, much like MUSB does.

>> >> > For the real use case, some Carplay platforms need it.
>> >> 
>> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>> >> specification which is not OTG-compliant.
>> >> 
>> >
>> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>> > states to finish role swap.
>> 
>> What are you referring to as "finish role swap"? I don't get that.
>
> Change current role from host to peripheral.

Okay, we have two scenarios here:

1. You need full OTG compliance

	For this, granted, you need the state machine if your HW doesn't
	track it. This is a given. With only one user, however, perhaps
	we don't need a generic layer. There are not enough different
	setups to design a good enough generic layer. We will end up
	with a pseudo-generic framework which is coupled with its only
	user.

2. Dual-role support, without OTG compliance

	In this case, you don't need a stack. All you need is a signal
	to tell you state of ID pin and another to tell you state of
	VBUS level. If you have those, you don't need to walk an OTG
	state machine at all. You don't need any of those quirky OTG
	timers, agreed?

	Given the above, why would you even want to use a subset of OTG
	state machine to implement something that's _usually_ as simple
	as:

8<----------------------------------------------------------------------
	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
        id = read(ID_STATE); /* could be a gpio_get_value() */

        set_role(id);
        set_vbus(vbus);
------------------------------------------------------------------------

>> > Notice, it needs to swap role without disconnect cable.
>> 
>> right, I can swap role without changing cable, but that's not OTG. The
>> mechanism for that, AFAICT, is not HNP. I don't know details about
>> CarPlay because the spec isn't public, but my understanding is that
>> CarPlay doesn't rely on anything from OTG spec.
>
> Since it is non-public, I can't say much. Some flows of its role-swap
> refers to On-The-Go and Embedded Host Supplement to the USB Revision 2.0
> Specification. 
>
> But OTG FSM is not the only way, the platform which can do role-swap
> without disconnection can support it too.

Right, all you need for CarPlay is what I wrote above. You don't need
full OTG compliance for that, right?

>> >> >> > diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
>> >> >> > index f4fc0aa..1d74fb8 100644
>> >> >> > --- a/include/linux/usb/gadget.h
>> >> >> > +++ b/include/linux/usb/gadget.h
>> >> >> > @@ -328,6 +328,7 @@ struct usb_gadget_ops {
>> >> >> >   * @in_epnum: last used in ep number
>> >> >> >   * @mA: last set mA value
>> >> >> >   * @otg_caps: OTG capabilities of this gadget.
>> >> >> > + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> 
>> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> 
>> >> >
>> >> > It may not be a real separate OTG controller. It can be a hardware part
>> >> > (external connector, external IC, SoC OTG register area, etc) to handle vbus
>> >> > ,id and other signals which are used for role swap.
>> >> 
>> >> That's already solved. EXTCON solved that years back and OMAP has been
>> >> using EXTCON to program its UTMI mailbox.
>> >> 
>> >
>> > No, that's not the same thing, it does not include the swap role.
>> 
>> Read your original comment:
>> 
>> "handle vbus, id and other signals which are *used for* role swap"
>> 
>> You didn't include role swap in your original comment. Semantics aside...
>> 
>> > Consider the use case the host driver is at host/ and udc driver is
>> > at gadget/udc, how to finish to role swap?
>> 
>> ... why does the source code placement matter? And what do you mean by
>> "finish role swap"?
>> 
>
> Well, it depends on your driver design, do you want the host driver's
> API is still be called when current role is peripheral? One typical
> problem you can refer below:

That's a driver bug and those needs to be fixed. This has nothing to do
with an OTG FSM, or lack thereof.

Here's what I plan on doing for dwc3 (as soon as I get some time):

request_threaded_irq(dwc->otg_irq, ...);

irqreturn_t dwc3_otg_irq_thread(int irq, void *_dwc)
{
	struct dwc3 *dwc = _dwc;
        u32 reg;

        reg = readl(OSTS);
        if (reg & PERIPHERAL)
        	dwc3_gadget_init(dwc);

	if (reg & HOST)
        	dwc3_host_init(dwc);

	if (reg & SESSION_END)
        	dwc3_disable_host_and_peripheral(dwc);

	return IRQ_HANDLED;
}

Then, when building the driver with OTG support, we never start Host or
peripheral by default. Only the OTG IRQ handler, since that becomes the
entry point.

That's all we need for DRD support on DWC3. As for OTG, it won't be much
different because the HW tracks OTG state machine. The only difference
will be implemeting HNP (just another big in IRQ handler) and SRP
(already implemented as gadget_wakeup())

> commit 11c011a5e777c83819078a18672543f04482b3ec
> Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Date:   Thu May 19 11:12:56 2016 +0100
>
>     usb: echi-hcd: Add ehci_setup check before echi_shutdown
>         
>
>
> In some cases, the USB code (gadget/hcd->start/stop) needs to be called
> during the role swap. For example, if you have mux driver, you may
> need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
> how can we do that?

You don't really need to remove the gadget. Just mask its interrupts and
ignore any calls to any gadget_driver ops, right? Likewise for
XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
the point of view of dwc3, it's simpler to unregister the platform
device we create for xhci-plat.c. I need no changes in XHCI to do that
and driver model will make sure to call xhci-plat's ->remove() which
will handle everything for me correctly.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21 10:43                     ` Tony Lindgren
  0 siblings, 0 replies; 172+ messages in thread
From: Tony Lindgren @ 2016-06-21 10:43 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Peter Chen, Roger Quadros, peter.chen, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

* Felipe Balbi <balbi@kernel.org> [160621 03:06]:
> 8<----------------------------------------------------------------------
> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>         id = read(ID_STATE); /* could be a gpio_get_value() */
> 
>         set_role(id);
>         set_vbus(vbus);

We should use regulator framework API for set_vbus() because of
the delays involved bringing it up. And we already have separate
PHY and charger chips where VBUS is provided by the charger chip.

Regards,

Tony

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21 10:43                     ` Tony Lindgren
  0 siblings, 0 replies; 172+ messages in thread
From: Tony Lindgren @ 2016-06-21 10:43 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Peter Chen, Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

* Felipe Balbi <balbi-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> [160621 03:06]:
> 8<----------------------------------------------------------------------
> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>         id = read(ID_STATE); /* could be a gpio_get_value() */
> 
>         set_role(id);
>         set_vbus(vbus);

We should use regulator framework API for set_vbus() because of
the delays involved bringing it up. And we already have separate
PHY and charger chips where VBUS is provided by the charger chip.

Regards,

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21 10:43                     ` Tony Lindgren
  (?)
@ 2016-06-21 10:56                     ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21 10:56 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Peter Chen, Roger Quadros, peter.chen, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 621 bytes --]


Hi,

Tony Lindgren <tony@atomide.com> writes:
> * Felipe Balbi <balbi@kernel.org> [160621 03:06]:
>> 8<----------------------------------------------------------------------
>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>> 
>>         set_role(id);
>>         set_vbus(vbus);
>
> We should use regulator framework API for set_vbus() because of
> the delays involved bringing it up. And we already have separate
> PHY and charger chips where VBUS is provided by the charger chip.

yeah, no arguments there.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21  9:14                     ` Peter Chen
@ 2016-06-21 12:35                       ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21 12:35 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 3047 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> >> 
>> >> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> >> 
>> >> >> >
>> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> >> >> > and gadget.
>> >> >> >
>> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> >> >> 
>> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
>> >> >> mux for swapping between XHCI and peripheral-only DWC3.
>> >> >> 
>> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> >> >> are two competing standards and, apparently, type-C is winning when it
>> >> >> comes to role-swapping.
>> >> >> 
>> >> >
>> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
>> >> > It will be considered as an OTG port.
>> >> 
>> >> That's because "dual-role" is a non-standard OTG. Seen as people really
>> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
>> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
>> >
>> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> > "OTG" in Linux, right?
>> 
>> to avoid confusion with the terminology, yes. With that settled, let's
>> figure out how you can deliver what your marketting guys are asking of
>> you.
>> 
>
> Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> test. The internal bsp has passed PET test, and formal compliance test
> is on the way (should pass too). 
>
> The dual-role and OTG compliance use the same zImage, but different
> dtb.

okay, that's good to know. Now, the question really is: considering we
only have one user for this generic OTG FSM layer, do we really need to
make it generic at all? I mean, just look at how invasive a change that
is.

My fear is that, as stated before, we don't have enough variance to be
able to design something that many could use. On top of that, most folks
are moving to type-c connector which, in reality, can't really implement
OTG.

Considering that Apple/Intel have already announced [1] that they will
use type-c connector, it's not too farfetched to speculate that CarPlay
will, eventually, rely on Power Delivery for role swapping. IOW, OTG has
its days counted. In 2 years' time, the market will have moved on to
Type-C and the generic OTG layer will be left to bit rot as time goes
by.

This is why I think that these changes should be local to chipidea,
considering chipidea is the only user for them. As for dwc3, we can get
something much simpler since, at least so far, there's no full OTG
requirement from anywhere I know and, even if OTG becomes a requirement
for any of dwc3 users, the HW handles the state machine for us.

What do you think?

[1] https://thunderbolttechnology.net/blog/thunderbolt-3-usb-c-does-it-all

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21 12:35                       ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21 12:35 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 3077 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> >> 
>> >> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> >> 
>> >> >> >
>> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> >> >> > and gadget.
>> >> >> >
>> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> >> >> 
>> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
>> >> >> mux for swapping between XHCI and peripheral-only DWC3.
>> >> >> 
>> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> >> >> are two competing standards and, apparently, type-C is winning when it
>> >> >> comes to role-swapping.
>> >> >> 
>> >> >
>> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
>> >> > It will be considered as an OTG port.
>> >> 
>> >> That's because "dual-role" is a non-standard OTG. Seen as people really
>> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
>> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
>> >
>> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> > "OTG" in Linux, right?
>> 
>> to avoid confusion with the terminology, yes. With that settled, let's
>> figure out how you can deliver what your marketting guys are asking of
>> you.
>> 
>
> Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> test. The internal bsp has passed PET test, and formal compliance test
> is on the way (should pass too). 
>
> The dual-role and OTG compliance use the same zImage, but different
> dtb.

okay, that's good to know. Now, the question really is: considering we
only have one user for this generic OTG FSM layer, do we really need to
make it generic at all? I mean, just look at how invasive a change that
is.

My fear is that, as stated before, we don't have enough variance to be
able to design something that many could use. On top of that, most folks
are moving to type-c connector which, in reality, can't really implement
OTG.

Considering that Apple/Intel have already announced [1] that they will
use type-c connector, it's not too farfetched to speculate that CarPlay
will, eventually, rely on Power Delivery for role swapping. IOW, OTG has
its days counted. In 2 years' time, the market will have moved on to
Type-C and the generic OTG layer will be left to bit rot as time goes
by.

This is why I think that these changes should be local to chipidea,
considering chipidea is the only user for them. As for dwc3, we can get
something much simpler since, at least so far, there's no full OTG
requirement from anywhere I know and, even if OTG becomes a requirement
for any of dwc3 users, the HW handles the state machine for us.

What do you think?

[1] https://thunderbolttechnology.net/blog/thunderbolt-3-usb-c-does-it-all

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21 13:05                     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21 13:05 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 01:02:59PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
> >> >> when they say OTG. Usually they just mean "a method for swapping between
> >> >> host and peripheral roles, but we really don't want all the extra cost
> >> >> of the OTG specification".
> >> >> 
> >> >
> >> > That's what I thought before, but the request from the Marketing guy is
> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> >> > see the SoC reference manual say "it supports HNP and SRP"?
> >> >
> >> > If there is no request, who else wants to implement so complicated FSM
> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
> >> 
> >> I stand corrected :-)
> >> 
> >> So there is one user for this layer. And this user has its own role
> >> control registers. I'm not convinced we need this large generic layer
> >> for one user.
> >> 
> >
> > You mean chipidea or dwc3? I have more comments below.
> 
> chipidea. From the point of OTG (or DRD) dwc3 is very
> self-sufficient. HW itself tracks state machine, much like MUSB does.

You mean HW can do state machine switch? If we are A device,
- Does the hardware knows if B device is HNP enabled or not?
- And if B device is HNP enabled, does it can switch itself from host
to peripheral when the B device is disconnected (a_suspend->a_peripheral)

Does hardware can really follow Figure 7-1: OTG A-device with HNP State
Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
2.0 Specification? And can pass PET test?

> 
> >> >> > For the real use case, some Carplay platforms need it.
> >> >> 
> >> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
> >> >> specification which is not OTG-compliant.
> >> >> 
> >> >
> >> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> >> > states to finish role swap.
> >> 
> >> What are you referring to as "finish role swap"? I don't get that.
> >
> > Change current role from host to peripheral.
> 
> Okay, we have two scenarios here:
> 
> 1. You need full OTG compliance
> 
> 	For this, granted, you need the state machine if your HW doesn't
> 	track it. This is a given. With only one user, however, perhaps
> 	we don't need a generic layer. There are not enough different
> 	setups to design a good enough generic layer. We will end up
> 	with a pseudo-generic framework which is coupled with its only
> 	user.
> 
> 2. Dual-role support, without OTG compliance
> 
> 	In this case, you don't need a stack. All you need is a signal
> 	to tell you state of ID pin and another to tell you state of
> 	VBUS level. If you have those, you don't need to walk an OTG
> 	state machine at all. You don't need any of those quirky OTG
> 	timers, agreed?
> 
> 	Given the above, why would you even want to use a subset of OTG
> 	state machine to implement something that's _usually_ as simple
> 	as:
> 
> 8<----------------------------------------------------------------------
> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>         id = read(ID_STATE); /* could be a gpio_get_value() */
> 
>         set_role(id);
>         set_vbus(vbus);
> ------------------------------------------------------------------------
> 

In fact, the individual driver can do it by itself. The chipidea driver
handles OTG and dual-role well currently. By considering this OTG/DRD
framework is worthwhile or not, we would like to see if it can
simplify DRD design for each driver, and can benefit the platforms which
has different drivers for host and peripheral to finish the role switch
well.

- The common start/stop host and peripheral operation
eg, when switch from host to peripheral, all drivers can use
usb_remove_hcd to finish it.
- A common workqueue to handle vbus and id event
- sysfs for role switch

> >> > Notice, it needs to swap role without disconnect cable.
> >> 
> >> right, I can swap role without changing cable, but that's not OTG. The
> >> mechanism for that, AFAICT, is not HNP. I don't know details about
> >> CarPlay because the spec isn't public, but my understanding is that
> >> CarPlay doesn't rely on anything from OTG spec.
> >
> > Since it is non-public, I can't say much. Some flows of its role-swap
> > refers to On-The-Go and Embedded Host Supplement to the USB Revision 2.0
> > Specification. 
> >
> > But OTG FSM is not the only way, the platform which can do role-swap
> > without disconnection can support it too.
> 
> Right, all you need for CarPlay is what I wrote above. You don't need
> full OTG compliance for that, right?
> 

OTG FSM is not necessary, other dual-role switch also can satisfy its
requirement.

> >> 
> >> > Consider the use case the host driver is at host/ and udc driver is
> >> > at gadget/udc, how to finish to role swap?
> >> 
> >> ... why does the source code placement matter? And what do you mean by
> >> "finish role swap"?
> >> 
> >
> > Well, it depends on your driver design, do you want the host driver's
> > API is still be called when current role is peripheral? One typical
> > problem you can refer below:
> 
> That's a driver bug and those needs to be fixed. This has nothing to do
> with an OTG FSM, or lack thereof.
> 

To simplify the discussion, we consider dual-role switch first. If dual-role
needs a framework, then OTG can use the same one just different state
machine.

> (already implemented as gadget_wakeup())
> 
> > commit 11c011a5e777c83819078a18672543f04482b3ec
> > Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> > Date:   Thu May 19 11:12:56 2016 +0100
> >
> >     usb: echi-hcd: Add ehci_setup check before echi_shutdown
> >         
> >
> >
> > In some cases, the USB code (gadget/hcd->start/stop) needs to be called
> > during the role swap. For example, if you have mux driver, you may
> > need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
> > how can we do that?
> 
> You don't really need to remove the gadget. Just mask its interrupts and
> ignore any calls to any gadget_driver ops, right? Likewise for
> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
> the point of view of dwc3, it's simpler to unregister the platform
> device we create for xhci-plat.c. I need no changes in XHCI to do that
> and driver model will make sure to call xhci-plat's ->remove() which
> will handle everything for me correctly.
> 

I admit it can do in a IP driver, eg both host and peripheral for the
single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
or what else for HCD at mux driver?

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-21 13:05                     ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-21 13:05 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, Jun 21, 2016 at 01:02:59PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
> >> >> when they say OTG. Usually they just mean "a method for swapping between
> >> >> host and peripheral roles, but we really don't want all the extra cost
> >> >> of the OTG specification".
> >> >> 
> >> >
> >> > That's what I thought before, but the request from the Marketing guy is
> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> >> > see the SoC reference manual say "it supports HNP and SRP"?
> >> >
> >> > If there is no request, who else wants to implement so complicated FSM
> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
> >> 
> >> I stand corrected :-)
> >> 
> >> So there is one user for this layer. And this user has its own role
> >> control registers. I'm not convinced we need this large generic layer
> >> for one user.
> >> 
> >
> > You mean chipidea or dwc3? I have more comments below.
> 
> chipidea. From the point of OTG (or DRD) dwc3 is very
> self-sufficient. HW itself tracks state machine, much like MUSB does.

You mean HW can do state machine switch? If we are A device,
- Does the hardware knows if B device is HNP enabled or not?
- And if B device is HNP enabled, does it can switch itself from host
to peripheral when the B device is disconnected (a_suspend->a_peripheral)

Does hardware can really follow Figure 7-1: OTG A-device with HNP State
Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
2.0 Specification? And can pass PET test?

> 
> >> >> > For the real use case, some Carplay platforms need it.
> >> >> 
> >> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
> >> >> specification which is not OTG-compliant.
> >> >> 
> >> >
> >> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
> >> > states to finish role swap.
> >> 
> >> What are you referring to as "finish role swap"? I don't get that.
> >
> > Change current role from host to peripheral.
> 
> Okay, we have two scenarios here:
> 
> 1. You need full OTG compliance
> 
> 	For this, granted, you need the state machine if your HW doesn't
> 	track it. This is a given. With only one user, however, perhaps
> 	we don't need a generic layer. There are not enough different
> 	setups to design a good enough generic layer. We will end up
> 	with a pseudo-generic framework which is coupled with its only
> 	user.
> 
> 2. Dual-role support, without OTG compliance
> 
> 	In this case, you don't need a stack. All you need is a signal
> 	to tell you state of ID pin and another to tell you state of
> 	VBUS level. If you have those, you don't need to walk an OTG
> 	state machine at all. You don't need any of those quirky OTG
> 	timers, agreed?
> 
> 	Given the above, why would you even want to use a subset of OTG
> 	state machine to implement something that's _usually_ as simple
> 	as:
> 
> 8<----------------------------------------------------------------------
> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>         id = read(ID_STATE); /* could be a gpio_get_value() */
> 
>         set_role(id);
>         set_vbus(vbus);
> ------------------------------------------------------------------------
> 

In fact, the individual driver can do it by itself. The chipidea driver
handles OTG and dual-role well currently. By considering this OTG/DRD
framework is worthwhile or not, we would like to see if it can
simplify DRD design for each driver, and can benefit the platforms which
has different drivers for host and peripheral to finish the role switch
well.

- The common start/stop host and peripheral operation
eg, when switch from host to peripheral, all drivers can use
usb_remove_hcd to finish it.
- A common workqueue to handle vbus and id event
- sysfs for role switch

> >> > Notice, it needs to swap role without disconnect cable.
> >> 
> >> right, I can swap role without changing cable, but that's not OTG. The
> >> mechanism for that, AFAICT, is not HNP. I don't know details about
> >> CarPlay because the spec isn't public, but my understanding is that
> >> CarPlay doesn't rely on anything from OTG spec.
> >
> > Since it is non-public, I can't say much. Some flows of its role-swap
> > refers to On-The-Go and Embedded Host Supplement to the USB Revision 2.0
> > Specification. 
> >
> > But OTG FSM is not the only way, the platform which can do role-swap
> > without disconnection can support it too.
> 
> Right, all you need for CarPlay is what I wrote above. You don't need
> full OTG compliance for that, right?
> 

OTG FSM is not necessary, other dual-role switch also can satisfy its
requirement.

> >> 
> >> > Consider the use case the host driver is at host/ and udc driver is
> >> > at gadget/udc, how to finish to role swap?
> >> 
> >> ... why does the source code placement matter? And what do you mean by
> >> "finish role swap"?
> >> 
> >
> > Well, it depends on your driver design, do you want the host driver's
> > API is still be called when current role is peripheral? One typical
> > problem you can refer below:
> 
> That's a driver bug and those needs to be fixed. This has nothing to do
> with an OTG FSM, or lack thereof.
> 

To simplify the discussion, we consider dual-role switch first. If dual-role
needs a framework, then OTG can use the same one just different state
machine.

> (already implemented as gadget_wakeup())
> 
> > commit 11c011a5e777c83819078a18672543f04482b3ec
> > Author: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > Date:   Thu May 19 11:12:56 2016 +0100
> >
> >     usb: echi-hcd: Add ehci_setup check before echi_shutdown
> >         
> >
> >
> > In some cases, the USB code (gadget/hcd->start/stop) needs to be called
> > during the role swap. For example, if you have mux driver, you may
> > need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
> > how can we do that?
> 
> You don't really need to remove the gadget. Just mask its interrupts and
> ignore any calls to any gadget_driver ops, right? Likewise for
> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
> the point of view of dwc3, it's simpler to unregister the platform
> device we create for xhci-plat.c. I need no changes in XHCI to do that
> and driver model will make sure to call xhci-plat's ->remove() which
> will handle everything for me correctly.
> 

I admit it can do in a IP driver, eg both host and peripheral for the
single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
or what else for HCD at mux driver?

-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21 12:35                       ` Felipe Balbi
  (?)
@ 2016-06-21 13:12                       ` Peter Chen
  2016-06-21 14:47                         ` Felipe Balbi
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-21 13:12 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 03:35:00PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> >> >> 
> >> >> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> >> >> 
> >> >> >> >
> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> >> >> > and gadget.
> >> >> >> >
> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> >> >> 
> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> >> >> 
> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> >> >> are two competing standards and, apparently, type-C is winning when it
> >> >> >> comes to role-swapping.
> >> >> >> 
> >> >> >
> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> >> >> > It will be considered as an OTG port.
> >> >> 
> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> >> >
> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> >> > "OTG" in Linux, right?
> >> 
> >> to avoid confusion with the terminology, yes. With that settled, let's
> >> figure out how you can deliver what your marketting guys are asking of
> >> you.
> >> 
> >
> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> > test. The internal bsp has passed PET test, and formal compliance test
> > is on the way (should pass too). 
> >
> > The dual-role and OTG compliance use the same zImage, but different
> > dtb.
> 
> okay, that's good to know. Now, the question really is: considering we
> only have one user for this generic OTG FSM layer, do we really need to
> make it generic at all? I mean, just look at how invasive a change that
> is.
> 

If the chipidea is the only user for this roger's framework, I don't
think it is necessary. In fact, Roger introduces this framework, and
the first user is dwc3, we think it can be used for others. Let's
just discuss if it is necessary for dual-role switch.

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21 13:12                       ` Peter Chen
@ 2016-06-21 14:47                         ` Felipe Balbi
  2016-06-22  3:33                             ` Peter Chen
  0 siblings, 1 reply; 172+ messages in thread
From: Felipe Balbi @ 2016-06-21 14:47 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 3914 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
>> >> >> >> >> 
>> >> >> >> >> do you really know of any platform which has a separate OTG controller?
>> >> >> >> >> 
>> >> >> >> >
>> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
>> >> >> >> > and gadget.
>> >> >> >> >
>> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
>> >> >> >> 
>> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
>> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
>> >> >> >> 
>> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
>> >> >> >> are two competing standards and, apparently, type-C is winning when it
>> >> >> >> comes to role-swapping.
>> >> >> >> 
>> >> >> >
>> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
>> >> >> > It will be considered as an OTG port.
>> >> >> 
>> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
>> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
>> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
>> >> >
>> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> >> > "OTG" in Linux, right?
>> >> 
>> >> to avoid confusion with the terminology, yes. With that settled, let's
>> >> figure out how you can deliver what your marketting guys are asking of
>> >> you.
>> >> 
>> >
>> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
>> > test. The internal bsp has passed PET test, and formal compliance test
>> > is on the way (should pass too). 
>> >
>> > The dual-role and OTG compliance use the same zImage, but different
>> > dtb.
>> 
>> okay, that's good to know. Now, the question really is: considering we
>> only have one user for this generic OTG FSM layer, do we really need to
>> make it generic at all? I mean, just look at how invasive a change that
>> is.
>
> If the chipidea is the only user for this roger's framework, I don't
> think it is necessary. In fact, Roger introduces this framework, and
> the first user is dwc3, we think it can be used for others. Let's

Right, we need to look at the history of dwc3 to figure out why the
conclusion that dwc3 needs this was made.

Roger started working on this framework when Power on Reset section of
databook had some details which weren't always clear and, for safety, we
always had reset asserted for a really long time. It was so long (about
400 ms) that resetting dwc3 for each role swap was just too much.

Coupled with that, the OTG chapter wasn't very clear either on
expections from Host and Peripheral side initialization in OTG/DRD
systems.

More recent version of dwc3 databook have a much better description of
how and which reset bits _must_ be asserted and which shouldn't be
touched unless it's for debugging purposes. When I implemented that, our
->probe() went from 400ms down to about 50us.

Coupled with that, the OTG chapter also became a lot clearer to the
point that it states you just don't initialize anything other than the
OTG block, and just wait for OTG interrupt to do whatever it is you need
to do.

This meant that we could actually afford to do full reinitialization of
dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
roles properly.

(The reason for needing soft-reset during role swap is kinda long. But
in summary dwc3 shadows register writes to both host and peripheral
sides)

> just discuss if it is necessary for dual-role switch.

fair. However, if we have a single user we don't have a Generic
layer. There's not enough variance to come up with truly generic
architecture for this.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  3:33                             ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-22  3:33 UTC (permalink / raw)
  To: Felipe Balbi, yoshihiro.shimoda.uh
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Tue, Jun 21, 2016 at 05:47:47PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> >> >> >> 
> >> >> >> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> >> >> >> 
> >> >> >> >> >
> >> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> >> >> >> > and gadget.
> >> >> >> >> >
> >> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> >> >> >> 
> >> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> >> >> >> 
> >> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> >> >> >> are two competing standards and, apparently, type-C is winning when it
> >> >> >> >> comes to role-swapping.
> >> >> >> >> 
> >> >> >> >
> >> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> >> >> >> > It will be considered as an OTG port.
> >> >> >> 
> >> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> >> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> >> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> >> >> >
> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> >> >> > "OTG" in Linux, right?
> >> >> 
> >> >> to avoid confusion with the terminology, yes. With that settled, let's
> >> >> figure out how you can deliver what your marketting guys are asking of
> >> >> you.
> >> >> 
> >> >
> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> >> > test. The internal bsp has passed PET test, and formal compliance test
> >> > is on the way (should pass too). 
> >> >
> >> > The dual-role and OTG compliance use the same zImage, but different
> >> > dtb.
> >> 
> >> okay, that's good to know. Now, the question really is: considering we
> >> only have one user for this generic OTG FSM layer, do we really need to
> >> make it generic at all? I mean, just look at how invasive a change that
> >> is.
> >
> > If the chipidea is the only user for this roger's framework, I don't
> > think it is necessary. In fact, Roger introduces this framework, and
> > the first user is dwc3, we think it can be used for others. Let's
> 
> Right, we need to look at the history of dwc3 to figure out why the
> conclusion that dwc3 needs this was made.
> 
> Roger started working on this framework when Power on Reset section of
> databook had some details which weren't always clear and, for safety, we
> always had reset asserted for a really long time. It was so long (about
> 400 ms) that resetting dwc3 for each role swap was just too much.
> 
> Coupled with that, the OTG chapter wasn't very clear either on
> expections from Host and Peripheral side initialization in OTG/DRD
> systems.
> 
> More recent version of dwc3 databook have a much better description of
> how and which reset bits _must_ be asserted and which shouldn't be
> touched unless it's for debugging purposes. When I implemented that, our
> ->probe() went from 400ms down to about 50us.
> 
> Coupled with that, the OTG chapter also became a lot clearer to the
> point that it states you just don't initialize anything other than the
> OTG block, and just wait for OTG interrupt to do whatever it is you need
> to do.
> 
> This meant that we could actually afford to do full reinitialization of
> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> roles properly.
> 
> (The reason for needing soft-reset during role swap is kinda long. But
> in summary dwc3 shadows register writes to both host and peripheral
> sides)
> 
> > just discuss if it is necessary for dual-role switch.
> 
> fair. However, if we have a single user we don't have a Generic
> layer. There's not enough variance to come up with truly generic
> architecture for this.
> 
> -- 

I have put some points in my last reply [1], I summery it here to
see if a generic framework is deserved or not?

1. If there are some parts we can use during the role switch
- The common start/stop host and peripheral operation
eg, when switch from host to peripheral, all drivers can use
usb_remove_hcd to finish it.
- A common workqueue to handle vbus and id event
- sysfs for role switch

2. Does a mux driver can do it well? Yoshihiro, here we need your
point. The main point is if we need to call USB API to change
roles (eg, usb_remove_hcd) during the role switch, thanks.


[1] http://www.spinics.net/lists/linux-usb/msg142974.html
-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  3:33                             ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-22  3:33 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, Jun 21, 2016 at 05:47:47PM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> >> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> >> >> >> >> >> 
> >> >> >> >> >> do you really know of any platform which has a separate OTG controller?
> >> >> >> >> >> 
> >> >> >> >> >
> >> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> >> >> >> >> > and gadget.
> >> >> >> >> >
> >> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> >> >> >> >> 
> >> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> >> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> >> >> >> >> 
> >> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> >> >> >> >> are two competing standards and, apparently, type-C is winning when it
> >> >> >> >> comes to role-swapping.
> >> >> >> >> 
> >> >> >> >
> >> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> >> >> >> > It will be considered as an OTG port.
> >> >> >> 
> >> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> >> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> >> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> >> >> >
> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> >> >> > "OTG" in Linux, right?
> >> >> 
> >> >> to avoid confusion with the terminology, yes. With that settled, let's
> >> >> figure out how you can deliver what your marketting guys are asking of
> >> >> you.
> >> >> 
> >> >
> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> >> > test. The internal bsp has passed PET test, and formal compliance test
> >> > is on the way (should pass too). 
> >> >
> >> > The dual-role and OTG compliance use the same zImage, but different
> >> > dtb.
> >> 
> >> okay, that's good to know. Now, the question really is: considering we
> >> only have one user for this generic OTG FSM layer, do we really need to
> >> make it generic at all? I mean, just look at how invasive a change that
> >> is.
> >
> > If the chipidea is the only user for this roger's framework, I don't
> > think it is necessary. In fact, Roger introduces this framework, and
> > the first user is dwc3, we think it can be used for others. Let's
> 
> Right, we need to look at the history of dwc3 to figure out why the
> conclusion that dwc3 needs this was made.
> 
> Roger started working on this framework when Power on Reset section of
> databook had some details which weren't always clear and, for safety, we
> always had reset asserted for a really long time. It was so long (about
> 400 ms) that resetting dwc3 for each role swap was just too much.
> 
> Coupled with that, the OTG chapter wasn't very clear either on
> expections from Host and Peripheral side initialization in OTG/DRD
> systems.
> 
> More recent version of dwc3 databook have a much better description of
> how and which reset bits _must_ be asserted and which shouldn't be
> touched unless it's for debugging purposes. When I implemented that, our
> ->probe() went from 400ms down to about 50us.
> 
> Coupled with that, the OTG chapter also became a lot clearer to the
> point that it states you just don't initialize anything other than the
> OTG block, and just wait for OTG interrupt to do whatever it is you need
> to do.
> 
> This meant that we could actually afford to do full reinitialization of
> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> roles properly.
> 
> (The reason for needing soft-reset during role swap is kinda long. But
> in summary dwc3 shadows register writes to both host and peripheral
> sides)
> 
> > just discuss if it is necessary for dual-role switch.
> 
> fair. However, if we have a single user we don't have a Generic
> layer. There's not enough variance to come up with truly generic
> architecture for this.
> 
> -- 

I have put some points in my last reply [1], I summery it here to
see if a generic framework is deserved or not?

1. If there are some parts we can use during the role switch
- The common start/stop host and peripheral operation
eg, when switch from host to peripheral, all drivers can use
usb_remove_hcd to finish it.
- A common workqueue to handle vbus and id event
- sysfs for role switch

2. Does a mux driver can do it well? Yoshihiro, here we need your
point. The main point is if we need to call USB API to change
roles (eg, usb_remove_hcd) during the role switch, thanks.


[1] http://www.spinics.net/lists/linux-usb/msg142974.html
-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  3:33                             ` Peter Chen
@ 2016-06-22  6:51                               ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  6:51 UTC (permalink / raw)
  To: Peter Chen, yoshihiro.shimoda.uh
  Cc: Roger Quadros, peter.chen, yoshihiro.shimoda.uh, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 3783 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> >> >> > "OTG" in Linux, right?
>> >> >> 
>> >> >> to avoid confusion with the terminology, yes. With that settled, let's
>> >> >> figure out how you can deliver what your marketting guys are asking of
>> >> >> you.
>> >> >> 
>> >> >
>> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
>> >> > test. The internal bsp has passed PET test, and formal compliance test
>> >> > is on the way (should pass too). 
>> >> >
>> >> > The dual-role and OTG compliance use the same zImage, but different
>> >> > dtb.
>> >> 
>> >> okay, that's good to know. Now, the question really is: considering we
>> >> only have one user for this generic OTG FSM layer, do we really need to
>> >> make it generic at all? I mean, just look at how invasive a change that
>> >> is.
>> >
>> > If the chipidea is the only user for this roger's framework, I don't
>> > think it is necessary. In fact, Roger introduces this framework, and
>> > the first user is dwc3, we think it can be used for others. Let's
>> 
>> Right, we need to look at the history of dwc3 to figure out why the
>> conclusion that dwc3 needs this was made.
>> 
>> Roger started working on this framework when Power on Reset section of
>> databook had some details which weren't always clear and, for safety, we
>> always had reset asserted for a really long time. It was so long (about
>> 400 ms) that resetting dwc3 for each role swap was just too much.
>> 
>> Coupled with that, the OTG chapter wasn't very clear either on
>> expections from Host and Peripheral side initialization in OTG/DRD
>> systems.
>> 
>> More recent version of dwc3 databook have a much better description of
>> how and which reset bits _must_ be asserted and which shouldn't be
>> touched unless it's for debugging purposes. When I implemented that, our
>> ->probe() went from 400ms down to about 50us.
>> 
>> Coupled with that, the OTG chapter also became a lot clearer to the
>> point that it states you just don't initialize anything other than the
>> OTG block, and just wait for OTG interrupt to do whatever it is you need
>> to do.
>> 
>> This meant that we could actually afford to do full reinitialization of
>> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
>> roles properly.
>> 
>> (The reason for needing soft-reset during role swap is kinda long. But
>> in summary dwc3 shadows register writes to both host and peripheral
>> sides)
>> 
>> > just discuss if it is necessary for dual-role switch.
>> 
>> fair. However, if we have a single user we don't have a Generic
>> layer. There's not enough variance to come up with truly generic
>> architecture for this.
>> 
>> -- 
>
> I have put some points in my last reply [1], I summery it here to
> see if a generic framework is deserved or not?
>
> 1. If there are some parts we can use during the role switch
> - The common start/stop host and peripheral operation
> eg, when switch from host to peripheral, all drivers can use
> usb_remove_hcd to finish it.

a UDC such as dwc3 already implements start/stop for peripheral and
host. Why would go through and indirection layer that just comes back to
us? (well, dwc3's host side, start/stop translates to adding/removing
xhci-plat's device)

> - A common workqueue to handle vbus and id event

I already have a threaded IRQ handler. Why do I need a workqueue?

> - sysfs for role switch

A generic sysfs is desirable, but I really don't know where to put it.
Maybe it's enough to go down the hwmon route and just have an agreement
of filename and contents to be written to.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  6:51                               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  6:51 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 3813 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> >> >> > "OTG" in Linux, right?
>> >> >> 
>> >> >> to avoid confusion with the terminology, yes. With that settled, let's
>> >> >> figure out how you can deliver what your marketting guys are asking of
>> >> >> you.
>> >> >> 
>> >> >
>> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
>> >> > test. The internal bsp has passed PET test, and formal compliance test
>> >> > is on the way (should pass too). 
>> >> >
>> >> > The dual-role and OTG compliance use the same zImage, but different
>> >> > dtb.
>> >> 
>> >> okay, that's good to know. Now, the question really is: considering we
>> >> only have one user for this generic OTG FSM layer, do we really need to
>> >> make it generic at all? I mean, just look at how invasive a change that
>> >> is.
>> >
>> > If the chipidea is the only user for this roger's framework, I don't
>> > think it is necessary. In fact, Roger introduces this framework, and
>> > the first user is dwc3, we think it can be used for others. Let's
>> 
>> Right, we need to look at the history of dwc3 to figure out why the
>> conclusion that dwc3 needs this was made.
>> 
>> Roger started working on this framework when Power on Reset section of
>> databook had some details which weren't always clear and, for safety, we
>> always had reset asserted for a really long time. It was so long (about
>> 400 ms) that resetting dwc3 for each role swap was just too much.
>> 
>> Coupled with that, the OTG chapter wasn't very clear either on
>> expections from Host and Peripheral side initialization in OTG/DRD
>> systems.
>> 
>> More recent version of dwc3 databook have a much better description of
>> how and which reset bits _must_ be asserted and which shouldn't be
>> touched unless it's for debugging purposes. When I implemented that, our
>> ->probe() went from 400ms down to about 50us.
>> 
>> Coupled with that, the OTG chapter also became a lot clearer to the
>> point that it states you just don't initialize anything other than the
>> OTG block, and just wait for OTG interrupt to do whatever it is you need
>> to do.
>> 
>> This meant that we could actually afford to do full reinitialization of
>> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
>> roles properly.
>> 
>> (The reason for needing soft-reset during role swap is kinda long. But
>> in summary dwc3 shadows register writes to both host and peripheral
>> sides)
>> 
>> > just discuss if it is necessary for dual-role switch.
>> 
>> fair. However, if we have a single user we don't have a Generic
>> layer. There's not enough variance to come up with truly generic
>> architecture for this.
>> 
>> -- 
>
> I have put some points in my last reply [1], I summery it here to
> see if a generic framework is deserved or not?
>
> 1. If there are some parts we can use during the role switch
> - The common start/stop host and peripheral operation
> eg, when switch from host to peripheral, all drivers can use
> usb_remove_hcd to finish it.

a UDC such as dwc3 already implements start/stop for peripheral and
host. Why would go through and indirection layer that just comes back to
us? (well, dwc3's host side, start/stop translates to adding/removing
xhci-plat's device)

> - A common workqueue to handle vbus and id event

I already have a threaded IRQ handler. Why do I need a workqueue?

> - sysfs for role switch

A generic sysfs is desirable, but I really don't know where to put it.
Maybe it's enough to go down the hwmon route and just have an agreement
of filename and contents to be written to.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-21 13:05                     ` Peter Chen
@ 2016-06-22  6:56                       ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  6:56 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 5690 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> >> >> when they say OTG. Usually they just mean "a method for swapping between
>> >> >> host and peripheral roles, but we really don't want all the extra cost
>> >> >> of the OTG specification".
>> >> >> 
>> >> >
>> >> > That's what I thought before, but the request from the Marketing guy is
>> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>> >> > see the SoC reference manual say "it supports HNP and SRP"?
>> >> >
>> >> > If there is no request, who else wants to implement so complicated FSM
>> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
>> >> 
>> >> I stand corrected :-)
>> >> 
>> >> So there is one user for this layer. And this user has its own role
>> >> control registers. I'm not convinced we need this large generic layer
>> >> for one user.
>> >> 
>> >
>> > You mean chipidea or dwc3? I have more comments below.
>> 
>> chipidea. From the point of OTG (or DRD) dwc3 is very
>> self-sufficient. HW itself tracks state machine, much like MUSB does.
>
> You mean HW can do state machine switch? If we are A device,
> - Does the hardware knows if B device is HNP enabled or not?

that's enabled through control message, keep a flag.

> - And if B device is HNP enabled, does it can switch itself from host
> to peripheral when the B device is disconnected (a_suspend->a_peripheral)

It cannot. It must rely on hnp polling which is, again, a control message.

> Does hardware can really follow Figure 7-1: OTG A-device with HNP State
> Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
> 2.0 Specification? And can pass PET test?

Seriously, what does this add to the conversation? It has already been
stated that there's nobody asking for OTG certification on dwc3. So all
of this is vaporware from the point of view of dwc3.

>> >> >> > For the real use case, some Carplay platforms need it.
>> >> >> 
>> >> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>> >> >> specification which is not OTG-compliant.
>> >> >> 
>> >> >
>> >> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>> >> > states to finish role swap.
>> >> 
>> >> What are you referring to as "finish role swap"? I don't get that.
>> >
>> > Change current role from host to peripheral.
>> 
>> Okay, we have two scenarios here:
>> 
>> 1. You need full OTG compliance
>> 
>> 	For this, granted, you need the state machine if your HW doesn't
>> 	track it. This is a given. With only one user, however, perhaps
>> 	we don't need a generic layer. There are not enough different
>> 	setups to design a good enough generic layer. We will end up
>> 	with a pseudo-generic framework which is coupled with its only
>> 	user.
>> 
>> 2. Dual-role support, without OTG compliance
>> 
>> 	In this case, you don't need a stack. All you need is a signal
>> 	to tell you state of ID pin and another to tell you state of
>> 	VBUS level. If you have those, you don't need to walk an OTG
>> 	state machine at all. You don't need any of those quirky OTG
>> 	timers, agreed?
>> 
>> 	Given the above, why would you even want to use a subset of OTG
>> 	state machine to implement something that's _usually_ as simple
>> 	as:
>> 
>> 8<----------------------------------------------------------------------
>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>> 
>>         set_role(id);
>>         set_vbus(vbus);
>> ------------------------------------------------------------------------
>> 
>
> In fact, the individual driver can do it by itself. The chipidea driver
> handles OTG and dual-role well currently. By considering this OTG/DRD
> framework is worthwhile or not, we would like to see if it can
> simplify DRD design for each driver, and can benefit the platforms which
> has different drivers for host and peripheral to finish the role switch
> well.

simplify how?  By adding unnecessary workqueues and a level indirection
that just goes back to the same driver?

>> > commit 11c011a5e777c83819078a18672543f04482b3ec
>> > Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> > Date:   Thu May 19 11:12:56 2016 +0100
>> >
>> >     usb: echi-hcd: Add ehci_setup check before echi_shutdown
>> >         
>> >
>> >
>> > In some cases, the USB code (gadget/hcd->start/stop) needs to be called
>> > during the role swap. For example, if you have mux driver, you may
>> > need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
>> > how can we do that?
>> 
>> You don't really need to remove the gadget. Just mask its interrupts and
>> ignore any calls to any gadget_driver ops, right? Likewise for
>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
>> the point of view of dwc3, it's simpler to unregister the platform
>> device we create for xhci-plat.c. I need no changes in XHCI to do that
>> and driver model will make sure to call xhci-plat's ->remove() which
>> will handle everything for me correctly.
>> 
>
> I admit it can do in a IP driver, eg both host and peripheral for the
> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
> or what else for HCD at mux driver?

dwc3's OTG block has control of that, however, what I'll do is
platform_device_del() xhci-plat's device. Not one line changes inside
XHCI.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  6:56                       ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  6:56 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 5779 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> >> >> when they say OTG. Usually they just mean "a method for swapping between
>> >> >> host and peripheral roles, but we really don't want all the extra cost
>> >> >> of the OTG specification".
>> >> >> 
>> >> >
>> >> > That's what I thought before, but the request from the Marketing guy is
>> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>> >> > see the SoC reference manual say "it supports HNP and SRP"?
>> >> >
>> >> > If there is no request, who else wants to implement so complicated FSM
>> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
>> >> 
>> >> I stand corrected :-)
>> >> 
>> >> So there is one user for this layer. And this user has its own role
>> >> control registers. I'm not convinced we need this large generic layer
>> >> for one user.
>> >> 
>> >
>> > You mean chipidea or dwc3? I have more comments below.
>> 
>> chipidea. From the point of OTG (or DRD) dwc3 is very
>> self-sufficient. HW itself tracks state machine, much like MUSB does.
>
> You mean HW can do state machine switch? If we are A device,
> - Does the hardware knows if B device is HNP enabled or not?

that's enabled through control message, keep a flag.

> - And if B device is HNP enabled, does it can switch itself from host
> to peripheral when the B device is disconnected (a_suspend->a_peripheral)

It cannot. It must rely on hnp polling which is, again, a control message.

> Does hardware can really follow Figure 7-1: OTG A-device with HNP State
> Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
> 2.0 Specification? And can pass PET test?

Seriously, what does this add to the conversation? It has already been
stated that there's nobody asking for OTG certification on dwc3. So all
of this is vaporware from the point of view of dwc3.

>> >> >> > For the real use case, some Carplay platforms need it.
>> >> >> 
>> >> >> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>> >> >> specification which is not OTG-compliant.
>> >> >> 
>> >> >
>> >> > Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>> >> > states to finish role swap.
>> >> 
>> >> What are you referring to as "finish role swap"? I don't get that.
>> >
>> > Change current role from host to peripheral.
>> 
>> Okay, we have two scenarios here:
>> 
>> 1. You need full OTG compliance
>> 
>> 	For this, granted, you need the state machine if your HW doesn't
>> 	track it. This is a given. With only one user, however, perhaps
>> 	we don't need a generic layer. There are not enough different
>> 	setups to design a good enough generic layer. We will end up
>> 	with a pseudo-generic framework which is coupled with its only
>> 	user.
>> 
>> 2. Dual-role support, without OTG compliance
>> 
>> 	In this case, you don't need a stack. All you need is a signal
>> 	to tell you state of ID pin and another to tell you state of
>> 	VBUS level. If you have those, you don't need to walk an OTG
>> 	state machine at all. You don't need any of those quirky OTG
>> 	timers, agreed?
>> 
>> 	Given the above, why would you even want to use a subset of OTG
>> 	state machine to implement something that's _usually_ as simple
>> 	as:
>> 
>> 8<----------------------------------------------------------------------
>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>> 
>>         set_role(id);
>>         set_vbus(vbus);
>> ------------------------------------------------------------------------
>> 
>
> In fact, the individual driver can do it by itself. The chipidea driver
> handles OTG and dual-role well currently. By considering this OTG/DRD
> framework is worthwhile or not, we would like to see if it can
> simplify DRD design for each driver, and can benefit the platforms which
> has different drivers for host and peripheral to finish the role switch
> well.

simplify how?  By adding unnecessary workqueues and a level indirection
that just goes back to the same driver?

>> > commit 11c011a5e777c83819078a18672543f04482b3ec
>> > Author: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> > Date:   Thu May 19 11:12:56 2016 +0100
>> >
>> >     usb: echi-hcd: Add ehci_setup check before echi_shutdown
>> >         
>> >
>> >
>> > In some cases, the USB code (gadget/hcd->start/stop) needs to be called
>> > during the role swap. For example, if you have mux driver, you may
>> > need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
>> > how can we do that?
>> 
>> You don't really need to remove the gadget. Just mask its interrupts and
>> ignore any calls to any gadget_driver ops, right? Likewise for
>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
>> the point of view of dwc3, it's simpler to unregister the platform
>> device we create for xhci-plat.c. I need no changes in XHCI to do that
>> and driver model will make sure to call xhci-plat's ->remove() which
>> will handle everything for me correctly.
>> 
>
> I admit it can do in a IP driver, eg both host and peripheral for the
> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
> or what else for HCD at mux driver?

dwc3's OTG block has control of that, however, what I'll do is
platform_device_del() xhci-plat's device. Not one line changes inside
XHCI.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  7:30                                 ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-22  7:30 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: yoshihiro.shimoda.uh, Roger Quadros, peter.chen, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

On Wed, Jun 22, 2016 at 09:51:19AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> >> >> >> > "OTG" in Linux, right?
> >> >> >> 
> >> >> >> to avoid confusion with the terminology, yes. With that settled, let's
> >> >> >> figure out how you can deliver what your marketting guys are asking of
> >> >> >> you.
> >> >> >> 
> >> >> >
> >> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> >> >> > test. The internal bsp has passed PET test, and formal compliance test
> >> >> > is on the way (should pass too). 
> >> >> >
> >> >> > The dual-role and OTG compliance use the same zImage, but different
> >> >> > dtb.
> >> >> 
> >> >> okay, that's good to know. Now, the question really is: considering we
> >> >> only have one user for this generic OTG FSM layer, do we really need to
> >> >> make it generic at all? I mean, just look at how invasive a change that
> >> >> is.
> >> >
> >> > If the chipidea is the only user for this roger's framework, I don't
> >> > think it is necessary. In fact, Roger introduces this framework, and
> >> > the first user is dwc3, we think it can be used for others. Let's
> >> 
> >> Right, we need to look at the history of dwc3 to figure out why the
> >> conclusion that dwc3 needs this was made.
> >> 
> >> Roger started working on this framework when Power on Reset section of
> >> databook had some details which weren't always clear and, for safety, we
> >> always had reset asserted for a really long time. It was so long (about
> >> 400 ms) that resetting dwc3 for each role swap was just too much.
> >> 
> >> Coupled with that, the OTG chapter wasn't very clear either on
> >> expections from Host and Peripheral side initialization in OTG/DRD
> >> systems.
> >> 
> >> More recent version of dwc3 databook have a much better description of
> >> how and which reset bits _must_ be asserted and which shouldn't be
> >> touched unless it's for debugging purposes. When I implemented that, our
> >> ->probe() went from 400ms down to about 50us.
> >> 
> >> Coupled with that, the OTG chapter also became a lot clearer to the
> >> point that it states you just don't initialize anything other than the
> >> OTG block, and just wait for OTG interrupt to do whatever it is you need
> >> to do.
> >> 
> >> This meant that we could actually afford to do full reinitialization of
> >> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> >> roles properly.
> >> 
> >> (The reason for needing soft-reset during role swap is kinda long. But
> >> in summary dwc3 shadows register writes to both host and peripheral
> >> sides)
> >> 
> >> > just discuss if it is necessary for dual-role switch.
> >> 
> >> fair. However, if we have a single user we don't have a Generic
> >> layer. There's not enough variance to come up with truly generic
> >> architecture for this.
> >> 
> >> -- 
> >
> > I have put some points in my last reply [1], I summery it here to
> > see if a generic framework is deserved or not?
> >
> > 1. If there are some parts we can use during the role switch
> > - The common start/stop host and peripheral operation
> > eg, when switch from host to peripheral, all drivers can use
> > usb_remove_hcd to finish it.
> 
> a UDC such as dwc3 already implements start/stop for peripheral and
> host. Why would go through and indirection layer that just comes back to
> us? (well, dwc3's host side, start/stop translates to adding/removing
> xhci-plat's device)
> 
> > - A common workqueue to handle vbus and id event
> 
> I already have a threaded IRQ handler. Why do I need a workqueue?
> 

I know it can be done in individual driver, don't you think
we need a common part to manage the dual-role switch process,
since dual-role switch is used more and more common, and
there are so many switch methods:

- ID pin
- sysfs
- type-c
- OTG FSM
- Registers

Maybe Roger's framework is a little complicated, but if it is the
correct direction, we can improve it.
  
> > - sysfs for role switch
> 
> A generic sysfs is desirable, but I really don't know where to put it.
> Maybe it's enough to go down the hwmon route and just have an agreement
> of filename and contents to be written to.
> 
> -- 
> balbi



-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  7:30                                 ` Peter Chen
  0 siblings, 0 replies; 172+ messages in thread
From: Peter Chen @ 2016-06-22  7:30 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ, Roger Quadros,
	peter.chen-KZfg59tc24xl57MIdRCFDg, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Jun 22, 2016 at 09:51:19AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> >> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> >> >> >> > "OTG" in Linux, right?
> >> >> >> 
> >> >> >> to avoid confusion with the terminology, yes. With that settled, let's
> >> >> >> figure out how you can deliver what your marketting guys are asking of
> >> >> >> you.
> >> >> >> 
> >> >> >
> >> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> >> >> > test. The internal bsp has passed PET test, and formal compliance test
> >> >> > is on the way (should pass too). 
> >> >> >
> >> >> > The dual-role and OTG compliance use the same zImage, but different
> >> >> > dtb.
> >> >> 
> >> >> okay, that's good to know. Now, the question really is: considering we
> >> >> only have one user for this generic OTG FSM layer, do we really need to
> >> >> make it generic at all? I mean, just look at how invasive a change that
> >> >> is.
> >> >
> >> > If the chipidea is the only user for this roger's framework, I don't
> >> > think it is necessary. In fact, Roger introduces this framework, and
> >> > the first user is dwc3, we think it can be used for others. Let's
> >> 
> >> Right, we need to look at the history of dwc3 to figure out why the
> >> conclusion that dwc3 needs this was made.
> >> 
> >> Roger started working on this framework when Power on Reset section of
> >> databook had some details which weren't always clear and, for safety, we
> >> always had reset asserted for a really long time. It was so long (about
> >> 400 ms) that resetting dwc3 for each role swap was just too much.
> >> 
> >> Coupled with that, the OTG chapter wasn't very clear either on
> >> expections from Host and Peripheral side initialization in OTG/DRD
> >> systems.
> >> 
> >> More recent version of dwc3 databook have a much better description of
> >> how and which reset bits _must_ be asserted and which shouldn't be
> >> touched unless it's for debugging purposes. When I implemented that, our
> >> ->probe() went from 400ms down to about 50us.
> >> 
> >> Coupled with that, the OTG chapter also became a lot clearer to the
> >> point that it states you just don't initialize anything other than the
> >> OTG block, and just wait for OTG interrupt to do whatever it is you need
> >> to do.
> >> 
> >> This meant that we could actually afford to do full reinitialization of
> >> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> >> roles properly.
> >> 
> >> (The reason for needing soft-reset during role swap is kinda long. But
> >> in summary dwc3 shadows register writes to both host and peripheral
> >> sides)
> >> 
> >> > just discuss if it is necessary for dual-role switch.
> >> 
> >> fair. However, if we have a single user we don't have a Generic
> >> layer. There's not enough variance to come up with truly generic
> >> architecture for this.
> >> 
> >> -- 
> >
> > I have put some points in my last reply [1], I summery it here to
> > see if a generic framework is deserved or not?
> >
> > 1. If there are some parts we can use during the role switch
> > - The common start/stop host and peripheral operation
> > eg, when switch from host to peripheral, all drivers can use
> > usb_remove_hcd to finish it.
> 
> a UDC such as dwc3 already implements start/stop for peripheral and
> host. Why would go through and indirection layer that just comes back to
> us? (well, dwc3's host side, start/stop translates to adding/removing
> xhci-plat's device)
> 
> > - A common workqueue to handle vbus and id event
> 
> I already have a threaded IRQ handler. Why do I need a workqueue?
> 

I know it can be done in individual driver, don't you think
we need a common part to manage the dual-role switch process,
since dual-role switch is used more and more common, and
there are so many switch methods:

- ID pin
- sysfs
- type-c
- OTG FSM
- Registers

Maybe Roger's framework is a little complicated, but if it is the
correct direction, we can improve it.
  
> > - sysfs for role switch
> 
> A generic sysfs is desirable, but I really don't know where to put it.
> Maybe it's enough to go down the hwmon route and just have an agreement
> of filename and contents to be written to.
> 
> -- 
> balbi



-- 

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  6:56                       ` Felipe Balbi
  (?)
@ 2016-06-22  7:33                       ` Peter Chen
  2016-06-22  8:03                         ` Felipe Balbi
  -1 siblings, 1 reply; 172+ messages in thread
From: Peter Chen @ 2016-06-22  7:33 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

On Wed, Jun 22, 2016 at 09:56:22AM +0300, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
> >> Peter Chen <hzpeterchen@gmail.com> writes:
> >> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
> >> >> >> when they say OTG. Usually they just mean "a method for swapping between
> >> >> >> host and peripheral roles, but we really don't want all the extra cost
> >> >> >> of the OTG specification".
> >> >> >> 
> >> >> >
> >> >> > That's what I thought before, but the request from the Marketing guy is
> >> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
> >> >> > see the SoC reference manual say "it supports HNP and SRP"?
> >> >> >
> >> >> > If there is no request, who else wants to implement so complicated FSM
> >> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
> >> >> 
> >> >> I stand corrected :-)
> >> >> 
> >> >> So there is one user for this layer. And this user has its own role
> >> >> control registers. I'm not convinced we need this large generic layer
> >> >> for one user.
> >> >> 
> >> >
> >> > You mean chipidea or dwc3? I have more comments below.
> >> 
> >> chipidea. From the point of OTG (or DRD) dwc3 is very
> >> self-sufficient. HW itself tracks state machine, much like MUSB does.
> >
> > You mean HW can do state machine switch? If we are A device,
> > - Does the hardware knows if B device is HNP enabled or not?
> 
> that's enabled through control message, keep a flag.
> 
> > - And if B device is HNP enabled, does it can switch itself from host
> > to peripheral when the B device is disconnected (a_suspend->a_peripheral)
> 
> It cannot. It must rely on hnp polling which is, again, a control message.
> 
> > Does hardware can really follow Figure 7-1: OTG A-device with HNP State
> > Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
> > 2.0 Specification? And can pass PET test?
> 
> Seriously, what does this add to the conversation? It has already been
> stated that there's nobody asking for OTG certification on dwc3. So all
> of this is vaporware from the point of view of dwc3.

This is just a technical question that I can't understand your words
"HW itself tracks state machine"?

-- 

Best Regards,
Peter Chen

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  6:56                       ` Felipe Balbi
@ 2016-06-22  7:49                         ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-22  7:49 UTC (permalink / raw)
  To: Felipe Balbi, Peter Chen, yoshihiro.shimoda.uh
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 6823 bytes --]

Hi Felipe,

On 22/06/16 09:56, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
>>> Peter Chen <hzpeterchen@gmail.com> writes:
>>>>>>> So far, I haven't seen anybody talking about real USB OTG (the spec)
>>>>>>> when they say OTG. Usually they just mean "a method for swapping between
>>>>>>> host and peripheral roles, but we really don't want all the extra cost
>>>>>>> of the OTG specification".
>>>>>>>
>>>>>>
>>>>>> That's what I thought before, but the request from the Marketing guy is
>>>>>> "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>>>>>> see the SoC reference manual say "it supports HNP and SRP"?
>>>>>>
>>>>>> If there is no request, who else wants to implement so complicated FSM
>>>>>> but seldom use cases, and go to pass OTG compliance test (tested by PET).
>>>>>
>>>>> I stand corrected :-)
>>>>>
>>>>> So there is one user for this layer. And this user has its own role
>>>>> control registers. I'm not convinced we need this large generic layer
>>>>> for one user.
>>>>>
>>>>
>>>> You mean chipidea or dwc3? I have more comments below.
>>>
>>> chipidea. From the point of OTG (or DRD) dwc3 is very
>>> self-sufficient. HW itself tracks state machine, much like MUSB does.
>>
>> You mean HW can do state machine switch? If we are A device,
>> - Does the hardware knows if B device is HNP enabled or not?
> 
> that's enabled through control message, keep a flag.
> 
>> - And if B device is HNP enabled, does it can switch itself from host
>> to peripheral when the B device is disconnected (a_suspend->a_peripheral)
> 
> It cannot. It must rely on hnp polling which is, again, a control message.
> 
>> Does hardware can really follow Figure 7-1: OTG A-device with HNP State
>> Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
>> 2.0 Specification? And can pass PET test?
> 
> Seriously, what does this add to the conversation? It has already been
> stated that there's nobody asking for OTG certification on dwc3. So all
> of this is vaporware from the point of view of dwc3.
> 
>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>
>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>> specification which is not OTG-compliant.
>>>>>>>
>>>>>>
>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>> states to finish role swap.
>>>>>
>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>
>>>> Change current role from host to peripheral.
>>>
>>> Okay, we have two scenarios here:
>>>
>>> 1. You need full OTG compliance
>>>
>>> 	For this, granted, you need the state machine if your HW doesn't
>>> 	track it. This is a given. With only one user, however, perhaps
>>> 	we don't need a generic layer. There are not enough different
>>> 	setups to design a good enough generic layer. We will end up
>>> 	with a pseudo-generic framework which is coupled with its only
>>> 	user.
>>>
>>> 2. Dual-role support, without OTG compliance
>>>
>>> 	In this case, you don't need a stack. All you need is a signal
>>> 	to tell you state of ID pin and another to tell you state of
>>> 	VBUS level. If you have those, you don't need to walk an OTG
>>> 	state machine at all. You don't need any of those quirky OTG
>>> 	timers, agreed?
>>>
>>> 	Given the above, why would you even want to use a subset of OTG
>>> 	state machine to implement something that's _usually_ as simple
>>> 	as:
>>>
>>> 8<----------------------------------------------------------------------
>>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>
>>>         set_role(id);
>>>         set_vbus(vbus);
>>> ------------------------------------------------------------------------
>>>
>>
>> In fact, the individual driver can do it by itself. The chipidea driver
>> handles OTG and dual-role well currently. By considering this OTG/DRD
>> framework is worthwhile or not, we would like to see if it can
>> simplify DRD design for each driver, and can benefit the platforms which
>> has different drivers for host and peripheral to finish the role switch
>> well.
> 
> simplify how?  By adding unnecessary workqueues and a level indirection
> that just goes back to the same driver?

What do you mean by same driver?
Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can be 3 totally
independent drivers unlike dwc3 where you have a single driver in control of
both host and gadget.

Questions not clear to me are:
1) Which driver handles ID/VBUS events and makes a decision to do the role swap?
Probably the PHY/MUX driver?
2) How does it perform the role swap? Probably a register write to the PHY/MUX
without needing to stop/start controllers? Easy case is both controllers can
run in co-existence without interference. Is there any platform other than dwc3
where this is not the case?
3) Even if host and gadget controllers can operate in coexistence, there is no need for
both to be running for embedded applications which are usually power conservative.
How can we achieve that?

> 
>>>> commit 11c011a5e777c83819078a18672543f04482b3ec
>>>> Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>>> Date:   Thu May 19 11:12:56 2016 +0100
>>>>
>>>>     usb: echi-hcd: Add ehci_setup check before echi_shutdown
>>>>         
>>>>
>>>>
>>>> In some cases, the USB code (gadget/hcd->start/stop) needs to be called
>>>> during the role swap. For example, if you have mux driver, you may
>>>> need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
>>>> how can we do that?
>>>
>>> You don't really need to remove the gadget. Just mask its interrupts and
>>> ignore any calls to any gadget_driver ops, right? Likewise for
>>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
>>> the point of view of dwc3, it's simpler to unregister the platform
>>> device we create for xhci-plat.c. I need no changes in XHCI to do that
>>> and driver model will make sure to call xhci-plat's ->remove() which
>>> will handle everything for me correctly.
>>>
>>
>> I admit it can do in a IP driver, eg both host and peripheral for the
>> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
>> or what else for HCD at mux driver?
> 
> dwc3's OTG block has control of that, however, what I'll do is
> platform_device_del() xhci-plat's device. Not one line changes inside
> XHCI.
> 

Let's talk about how non dwc3 based platforms can get it done.

Yoshihiro-san, could you please share your platform requirements from dual-role
perspective?

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  7:49                         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-22  7:49 UTC (permalink / raw)
  To: Felipe Balbi, Peter Chen, yoshihiro.shimoda.uh
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 6823 bytes --]

Hi Felipe,

On 22/06/16 09:56, Felipe Balbi wrote:
> 
> Hi,
> 
> Peter Chen <hzpeterchen@gmail.com> writes:
>>> Peter Chen <hzpeterchen@gmail.com> writes:
>>>>>>> So far, I haven't seen anybody talking about real USB OTG (the spec)
>>>>>>> when they say OTG. Usually they just mean "a method for swapping between
>>>>>>> host and peripheral roles, but we really don't want all the extra cost
>>>>>>> of the OTG specification".
>>>>>>>
>>>>>>
>>>>>> That's what I thought before, but the request from the Marketing guy is
>>>>>> "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>>>>>> see the SoC reference manual say "it supports HNP and SRP"?
>>>>>>
>>>>>> If there is no request, who else wants to implement so complicated FSM
>>>>>> but seldom use cases, and go to pass OTG compliance test (tested by PET).
>>>>>
>>>>> I stand corrected :-)
>>>>>
>>>>> So there is one user for this layer. And this user has its own role
>>>>> control registers. I'm not convinced we need this large generic layer
>>>>> for one user.
>>>>>
>>>>
>>>> You mean chipidea or dwc3? I have more comments below.
>>>
>>> chipidea. From the point of OTG (or DRD) dwc3 is very
>>> self-sufficient. HW itself tracks state machine, much like MUSB does.
>>
>> You mean HW can do state machine switch? If we are A device,
>> - Does the hardware knows if B device is HNP enabled or not?
> 
> that's enabled through control message, keep a flag.
> 
>> - And if B device is HNP enabled, does it can switch itself from host
>> to peripheral when the B device is disconnected (a_suspend->a_peripheral)
> 
> It cannot. It must rely on hnp polling which is, again, a control message.
> 
>> Does hardware can really follow Figure 7-1: OTG A-device with HNP State
>> Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
>> 2.0 Specification? And can pass PET test?
> 
> Seriously, what does this add to the conversation? It has already been
> stated that there's nobody asking for OTG certification on dwc3. So all
> of this is vaporware from the point of view of dwc3.
> 
>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>
>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>> specification which is not OTG-compliant.
>>>>>>>
>>>>>>
>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>> states to finish role swap.
>>>>>
>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>
>>>> Change current role from host to peripheral.
>>>
>>> Okay, we have two scenarios here:
>>>
>>> 1. You need full OTG compliance
>>>
>>> 	For this, granted, you need the state machine if your HW doesn't
>>> 	track it. This is a given. With only one user, however, perhaps
>>> 	we don't need a generic layer. There are not enough different
>>> 	setups to design a good enough generic layer. We will end up
>>> 	with a pseudo-generic framework which is coupled with its only
>>> 	user.
>>>
>>> 2. Dual-role support, without OTG compliance
>>>
>>> 	In this case, you don't need a stack. All you need is a signal
>>> 	to tell you state of ID pin and another to tell you state of
>>> 	VBUS level. If you have those, you don't need to walk an OTG
>>> 	state machine at all. You don't need any of those quirky OTG
>>> 	timers, agreed?
>>>
>>> 	Given the above, why would you even want to use a subset of OTG
>>> 	state machine to implement something that's _usually_ as simple
>>> 	as:
>>>
>>> 8<----------------------------------------------------------------------
>>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>
>>>         set_role(id);
>>>         set_vbus(vbus);
>>> ------------------------------------------------------------------------
>>>
>>
>> In fact, the individual driver can do it by itself. The chipidea driver
>> handles OTG and dual-role well currently. By considering this OTG/DRD
>> framework is worthwhile or not, we would like to see if it can
>> simplify DRD design for each driver, and can benefit the platforms which
>> has different drivers for host and peripheral to finish the role switch
>> well.
> 
> simplify how?  By adding unnecessary workqueues and a level indirection
> that just goes back to the same driver?

What do you mean by same driver?
Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can be 3 totally
independent drivers unlike dwc3 where you have a single driver in control of
both host and gadget.

Questions not clear to me are:
1) Which driver handles ID/VBUS events and makes a decision to do the role swap?
Probably the PHY/MUX driver?
2) How does it perform the role swap? Probably a register write to the PHY/MUX
without needing to stop/start controllers? Easy case is both controllers can
run in co-existence without interference. Is there any platform other than dwc3
where this is not the case?
3) Even if host and gadget controllers can operate in coexistence, there is no need for
both to be running for embedded applications which are usually power conservative.
How can we achieve that?

> 
>>>> commit 11c011a5e777c83819078a18672543f04482b3ec
>>>> Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>>> Date:   Thu May 19 11:12:56 2016 +0100
>>>>
>>>>     usb: echi-hcd: Add ehci_setup check before echi_shutdown
>>>>         
>>>>
>>>>
>>>> In some cases, the USB code (gadget/hcd->start/stop) needs to be called
>>>> during the role swap. For example, if you have mux driver, you may
>>>> need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
>>>> how can we do that?
>>>
>>> You don't really need to remove the gadget. Just mask its interrupts and
>>> ignore any calls to any gadget_driver ops, right? Likewise for
>>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
>>> the point of view of dwc3, it's simpler to unregister the platform
>>> device we create for xhci-plat.c. I need no changes in XHCI to do that
>>> and driver model will make sure to call xhci-plat's ->remove() which
>>> will handle everything for me correctly.
>>>
>>
>> I admit it can do in a IP driver, eg both host and peripheral for the
>> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
>> or what else for HCD at mux driver?
> 
> dwc3's OTG block has control of that, however, what I'll do is
> platform_device_del() xhci-plat's device. Not one line changes inside
> XHCI.
> 

Let's talk about how non dwc3 based platforms can get it done.

Yoshihiro-san, could you please share your platform requirements from dual-role
perspective?

cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  7:30                                 ` Peter Chen
@ 2016-06-22  8:00                                   ` Felipe Balbi
  -1 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  8:00 UTC (permalink / raw)
  To: Peter Chen
  Cc: yoshihiro.shimoda.uh, Roger Quadros, peter.chen, tony, gregkh,
	dan.j.williams, mathias.nyman, Joao.Pinto, sergei.shtylyov,
	jun.li, grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 4386 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> >> >> >> > "OTG" in Linux, right?
>> >> >> >> 
>> >> >> >> to avoid confusion with the terminology, yes. With that settled, let's
>> >> >> >> figure out how you can deliver what your marketting guys are asking of
>> >> >> >> you.
>> >> >> >> 
>> >> >> >
>> >> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
>> >> >> > test. The internal bsp has passed PET test, and formal compliance test
>> >> >> > is on the way (should pass too). 
>> >> >> >
>> >> >> > The dual-role and OTG compliance use the same zImage, but different
>> >> >> > dtb.
>> >> >> 
>> >> >> okay, that's good to know. Now, the question really is: considering we
>> >> >> only have one user for this generic OTG FSM layer, do we really need to
>> >> >> make it generic at all? I mean, just look at how invasive a change that
>> >> >> is.
>> >> >
>> >> > If the chipidea is the only user for this roger's framework, I don't
>> >> > think it is necessary. In fact, Roger introduces this framework, and
>> >> > the first user is dwc3, we think it can be used for others. Let's
>> >> 
>> >> Right, we need to look at the history of dwc3 to figure out why the
>> >> conclusion that dwc3 needs this was made.
>> >> 
>> >> Roger started working on this framework when Power on Reset section of
>> >> databook had some details which weren't always clear and, for safety, we
>> >> always had reset asserted for a really long time. It was so long (about
>> >> 400 ms) that resetting dwc3 for each role swap was just too much.
>> >> 
>> >> Coupled with that, the OTG chapter wasn't very clear either on
>> >> expections from Host and Peripheral side initialization in OTG/DRD
>> >> systems.
>> >> 
>> >> More recent version of dwc3 databook have a much better description of
>> >> how and which reset bits _must_ be asserted and which shouldn't be
>> >> touched unless it's for debugging purposes. When I implemented that, our
>> >> ->probe() went from 400ms down to about 50us.
>> >> 
>> >> Coupled with that, the OTG chapter also became a lot clearer to the
>> >> point that it states you just don't initialize anything other than the
>> >> OTG block, and just wait for OTG interrupt to do whatever it is you need
>> >> to do.
>> >> 
>> >> This meant that we could actually afford to do full reinitialization of
>> >> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
>> >> roles properly.
>> >> 
>> >> (The reason for needing soft-reset during role swap is kinda long. But
>> >> in summary dwc3 shadows register writes to both host and peripheral
>> >> sides)
>> >> 
>> >> > just discuss if it is necessary for dual-role switch.
>> >> 
>> >> fair. However, if we have a single user we don't have a Generic
>> >> layer. There's not enough variance to come up with truly generic
>> >> architecture for this.
>> >> 
>> >> -- 
>> >
>> > I have put some points in my last reply [1], I summery it here to
>> > see if a generic framework is deserved or not?
>> >
>> > 1. If there are some parts we can use during the role switch
>> > - The common start/stop host and peripheral operation
>> > eg, when switch from host to peripheral, all drivers can use
>> > usb_remove_hcd to finish it.
>> 
>> a UDC such as dwc3 already implements start/stop for peripheral and
>> host. Why would go through and indirection layer that just comes back to
>> us? (well, dwc3's host side, start/stop translates to adding/removing
>> xhci-plat's device)
>> 
>> > - A common workqueue to handle vbus and id event
>> 
>> I already have a threaded IRQ handler. Why do I need a workqueue?
>> 
>
> I know it can be done in individual driver, don't you think
> we need a common part to manage the dual-role switch process,

A common part will be a requirement when we have at least 3 users for
it. Right now there's only one. So how can this be common at all?

> since dual-role switch is used more and more common, and
> there are so many switch methods:
>
> - ID pin
> - sysfs
> - type-c
> - OTG FSM
> - Registers
>
> Maybe Roger's framework is a little complicated, but if it is the
> correct direction, we can improve it.

IMO, we don't have enough users

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  8:00                                   ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  8:00 UTC (permalink / raw)
  To: Peter Chen
  Cc: yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ, Roger Quadros,
	peter.chen-KZfg59tc24xl57MIdRCFDg, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 4416 bytes --]


Hi,

Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>> >> >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
>> >> >> >> > "OTG" in Linux, right?
>> >> >> >> 
>> >> >> >> to avoid confusion with the terminology, yes. With that settled, let's
>> >> >> >> figure out how you can deliver what your marketting guys are asking of
>> >> >> >> you.
>> >> >> >> 
>> >> >> >
>> >> >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
>> >> >> > test. The internal bsp has passed PET test, and formal compliance test
>> >> >> > is on the way (should pass too). 
>> >> >> >
>> >> >> > The dual-role and OTG compliance use the same zImage, but different
>> >> >> > dtb.
>> >> >> 
>> >> >> okay, that's good to know. Now, the question really is: considering we
>> >> >> only have one user for this generic OTG FSM layer, do we really need to
>> >> >> make it generic at all? I mean, just look at how invasive a change that
>> >> >> is.
>> >> >
>> >> > If the chipidea is the only user for this roger's framework, I don't
>> >> > think it is necessary. In fact, Roger introduces this framework, and
>> >> > the first user is dwc3, we think it can be used for others. Let's
>> >> 
>> >> Right, we need to look at the history of dwc3 to figure out why the
>> >> conclusion that dwc3 needs this was made.
>> >> 
>> >> Roger started working on this framework when Power on Reset section of
>> >> databook had some details which weren't always clear and, for safety, we
>> >> always had reset asserted for a really long time. It was so long (about
>> >> 400 ms) that resetting dwc3 for each role swap was just too much.
>> >> 
>> >> Coupled with that, the OTG chapter wasn't very clear either on
>> >> expections from Host and Peripheral side initialization in OTG/DRD
>> >> systems.
>> >> 
>> >> More recent version of dwc3 databook have a much better description of
>> >> how and which reset bits _must_ be asserted and which shouldn't be
>> >> touched unless it's for debugging purposes. When I implemented that, our
>> >> ->probe() went from 400ms down to about 50us.
>> >> 
>> >> Coupled with that, the OTG chapter also became a lot clearer to the
>> >> point that it states you just don't initialize anything other than the
>> >> OTG block, and just wait for OTG interrupt to do whatever it is you need
>> >> to do.
>> >> 
>> >> This meant that we could actually afford to do full reinitialization of
>> >> dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
>> >> roles properly.
>> >> 
>> >> (The reason for needing soft-reset during role swap is kinda long. But
>> >> in summary dwc3 shadows register writes to both host and peripheral
>> >> sides)
>> >> 
>> >> > just discuss if it is necessary for dual-role switch.
>> >> 
>> >> fair. However, if we have a single user we don't have a Generic
>> >> layer. There's not enough variance to come up with truly generic
>> >> architecture for this.
>> >> 
>> >> -- 
>> >
>> > I have put some points in my last reply [1], I summery it here to
>> > see if a generic framework is deserved or not?
>> >
>> > 1. If there are some parts we can use during the role switch
>> > - The common start/stop host and peripheral operation
>> > eg, when switch from host to peripheral, all drivers can use
>> > usb_remove_hcd to finish it.
>> 
>> a UDC such as dwc3 already implements start/stop for peripheral and
>> host. Why would go through and indirection layer that just comes back to
>> us? (well, dwc3's host side, start/stop translates to adding/removing
>> xhci-plat's device)
>> 
>> > - A common workqueue to handle vbus and id event
>> 
>> I already have a threaded IRQ handler. Why do I need a workqueue?
>> 
>
> I know it can be done in individual driver, don't you think
> we need a common part to manage the dual-role switch process,

A common part will be a requirement when we have at least 3 users for
it. Right now there's only one. So how can this be common at all?

> since dual-role switch is used more and more common, and
> there are so many switch methods:
>
> - ID pin
> - sysfs
> - type-c
> - OTG FSM
> - Registers
>
> Maybe Roger's framework is a little complicated, but if it is the
> correct direction, we can improve it.

IMO, we don't have enough users

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  7:33                       ` Peter Chen
@ 2016-06-22  8:03                         ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  8:03 UTC (permalink / raw)
  To: Peter Chen
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	joe, linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 2642 bytes --]


Hi,

Peter Chen <hzpeterchen@gmail.com> writes:
>> >> >> >> So far, I haven't seen anybody talking about real USB OTG (the spec)
>> >> >> >> when they say OTG. Usually they just mean "a method for swapping between
>> >> >> >> host and peripheral roles, but we really don't want all the extra cost
>> >> >> >> of the OTG specification".
>> >> >> >> 
>> >> >> >
>> >> >> > That's what I thought before, but the request from the Marketing guy is
>> >> >> > "To prove the SoC is OTG compliance, support HNP and SRP", don't you
>> >> >> > see the SoC reference manual say "it supports HNP and SRP"?
>> >> >> >
>> >> >> > If there is no request, who else wants to implement so complicated FSM
>> >> >> > but seldom use cases, and go to pass OTG compliance test (tested by PET).
>> >> >> 
>> >> >> I stand corrected :-)
>> >> >> 
>> >> >> So there is one user for this layer. And this user has its own role
>> >> >> control registers. I'm not convinced we need this large generic layer
>> >> >> for one user.
>> >> >> 
>> >> >
>> >> > You mean chipidea or dwc3? I have more comments below.
>> >> 
>> >> chipidea. From the point of OTG (or DRD) dwc3 is very
>> >> self-sufficient. HW itself tracks state machine, much like MUSB does.
>> >
>> > You mean HW can do state machine switch? If we are A device,
>> > - Does the hardware knows if B device is HNP enabled or not?
>> 
>> that's enabled through control message, keep a flag.
>> 
>> > - And if B device is HNP enabled, does it can switch itself from host
>> > to peripheral when the B device is disconnected (a_suspend->a_peripheral)
>> 
>> It cannot. It must rely on hnp polling which is, again, a control message.
>> 
>> > Does hardware can really follow Figure 7-1: OTG A-device with HNP State
>> > Diagram at On-The-Go and Embedded Host Supplement to the USB Revision
>> > 2.0 Specification? And can pass PET test?
>> 
>> Seriously, what does this add to the conversation? It has already been
>> stated that there's nobody asking for OTG certification on dwc3. So all
>> of this is vaporware from the point of view of dwc3.
>
> This is just a technical question that I can't understand your words
> "HW itself tracks state machine"?

It's simple, really: HW knows that it starts in B_IDLE. All automatic
state changes, HW will do:

B_IDLE -> A_IDLE -> A_WAIT_VRISE -> A_WAIT_BCON -> A_HOST
B_IDLE -> B_WAIT_ACON -> B_PERIPHERAL

Some state changes need SW intervention, for those you need to kick the
correct event so HW makes the state change. But register will still tell
you correct state after HW switches to it.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  7:49                         ` Roger Quadros
  (?)
@ 2016-06-22  8:14                         ` Felipe Balbi
  2016-06-22  8:30                             ` Roger Quadros
  -1 siblings, 1 reply; 172+ messages in thread
From: Felipe Balbi @ 2016-06-22  8:14 UTC (permalink / raw)
  To: Roger Quadros, Peter Chen, yoshihiro.shimoda.uh
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

[-- Attachment #1: Type: text/plain, Size: 5113 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>
>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>
>>>>>>>
>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>> states to finish role swap.
>>>>>>
>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>
>>>>> Change current role from host to peripheral.
>>>>
>>>> Okay, we have two scenarios here:
>>>>
>>>> 1. You need full OTG compliance
>>>>
>>>> 	For this, granted, you need the state machine if your HW doesn't
>>>> 	track it. This is a given. With only one user, however, perhaps
>>>> 	we don't need a generic layer. There are not enough different
>>>> 	setups to design a good enough generic layer. We will end up
>>>> 	with a pseudo-generic framework which is coupled with its only
>>>> 	user.
>>>>
>>>> 2. Dual-role support, without OTG compliance
>>>>
>>>> 	In this case, you don't need a stack. All you need is a signal
>>>> 	to tell you state of ID pin and another to tell you state of
>>>> 	VBUS level. If you have those, you don't need to walk an OTG
>>>> 	state machine at all. You don't need any of those quirky OTG
>>>> 	timers, agreed?
>>>>
>>>> 	Given the above, why would you even want to use a subset of OTG
>>>> 	state machine to implement something that's _usually_ as simple
>>>> 	as:
>>>>
>>>> 8<----------------------------------------------------------------------
>>>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>
>>>>         set_role(id);
>>>>         set_vbus(vbus);
>>>> ------------------------------------------------------------------------
>>>>
>>>
>>> In fact, the individual driver can do it by itself. The chipidea driver
>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>> framework is worthwhile or not, we would like to see if it can
>>> simplify DRD design for each driver, and can benefit the platforms which
>>> has different drivers for host and peripheral to finish the role switch
>>> well.
>> 
>> simplify how?  By adding unnecessary workqueues and a level indirection
>> that just goes back to the same driver?
>
> What do you mean by same driver?

dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
layer jumps to a callback that goes back to dwc3 to e.g. start
peripheral side.

See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.

> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
> be 3 totally independent drivers unlike dwc3 where you have a single
> driver in control of both host and gadget.

That's a totally different issue and one not being tackled by OTG
layer, because there are no such users yet. We can't design anything
based solely on speculation of what might happen.

If there aren't enough users, there is no way to design a good generic
layer.

> Questions not clear to me are:
>
> 1) Which driver handles ID/VBUS events and makes a decision to do the
> role swap?  Probably the PHY/MUX driver?

This is implementation dependent. For TI's USB subsystem, we have PMIC
sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
has no intervention.

For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
internal mux (much like TI's UTMI mailbox, but slightly different) to
switch between a separate XHCI or a separate dwc3. The same mux can be
put in HW-mode where SW has no intervention.

In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
driver just detects role (at least for Type-C based plats) and executes
_DSM with correct arguments [1]. _DSM will program internal MUX, toggle
VBUS and, for type-C, toggle VCONN when needed.

> 2) How does it perform the role swap? Probably a register write to the
> PHY/MUX without needing to stop/start controllers? Easy case is both
> controllers can run in co-existence without interference. Is there any
> platform other than dwc3 where this is not the case?

Again speculation. But to answer your question, only dwc3 is in such a
case today. But even for dwc3 we can have DRD with a much, much simpler
setup as I have already explained.

> 3) Even if host and gadget controllers can operate in coexistence,
> there is no need for both to be running for embedded applications
> which are usually power conservative.  How can we achieve that?

Now you're also speculating that you're running on embedded applications
and that we _can_ power off parts of the IP. I happen to know that we
can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
Clocks and power rails as the peripheral side.

[1] https://lkml.org/lkml/2016/6/21/658

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  8:14                         ` Felipe Balbi
@ 2016-06-22  8:30                             ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-22  8:30 UTC (permalink / raw)
  To: Felipe Balbi, Peter Chen, yoshihiro.shimoda.uh
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 5630 bytes --]

On 22/06/16 11:14, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>
>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>> states to finish role swap.
>>>>>>>
>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>
>>>>>> Change current role from host to peripheral.
>>>>>
>>>>> Okay, we have two scenarios here:
>>>>>
>>>>> 1. You need full OTG compliance
>>>>>
>>>>> 	For this, granted, you need the state machine if your HW doesn't
>>>>> 	track it. This is a given. With only one user, however, perhaps
>>>>> 	we don't need a generic layer. There are not enough different
>>>>> 	setups to design a good enough generic layer. We will end up
>>>>> 	with a pseudo-generic framework which is coupled with its only
>>>>> 	user.
>>>>>
>>>>> 2. Dual-role support, without OTG compliance
>>>>>
>>>>> 	In this case, you don't need a stack. All you need is a signal
>>>>> 	to tell you state of ID pin and another to tell you state of
>>>>> 	VBUS level. If you have those, you don't need to walk an OTG
>>>>> 	state machine at all. You don't need any of those quirky OTG
>>>>> 	timers, agreed?
>>>>>
>>>>> 	Given the above, why would you even want to use a subset of OTG
>>>>> 	state machine to implement something that's _usually_ as simple
>>>>> 	as:
>>>>>
>>>>> 8<----------------------------------------------------------------------
>>>>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>
>>>>>         set_role(id);
>>>>>         set_vbus(vbus);
>>>>> ------------------------------------------------------------------------
>>>>>
>>>>
>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>> framework is worthwhile or not, we would like to see if it can
>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>> has different drivers for host and peripheral to finish the role switch
>>>> well.
>>>
>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>> that just goes back to the same driver?
>>
>> What do you mean by same driver?
> 
> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
> layer jumps to a callback that goes back to dwc3 to e.g. start
> peripheral side.
> 
> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
> 
>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>> be 3 totally independent drivers unlike dwc3 where you have a single
>> driver in control of both host and gadget.
> 
> That's a totally different issue and one not being tackled by OTG
> layer, because there are no such users yet. We can't design anything
> based solely on speculation of what might happen.
> 
> If there aren't enough users, there is no way to design a good generic
> layer.
> 
>> Questions not clear to me are:
>>
>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>> role swap?  Probably the PHY/MUX driver?
> 
> This is implementation dependent. For TI's USB subsystem, we have PMIC
> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
> has no intervention.
> 
> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
> internal mux (much like TI's UTMI mailbox, but slightly different) to
> switch between a separate XHCI or a separate dwc3. The same mux can be
> put in HW-mode where SW has no intervention.
> 
> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
> driver just detects role (at least for Type-C based plats) and executes
> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
> VBUS and, for type-C, toggle VCONN when needed.
> 
>> 2) How does it perform the role swap? Probably a register write to the
>> PHY/MUX without needing to stop/start controllers? Easy case is both
>> controllers can run in co-existence without interference. Is there any
>> platform other than dwc3 where this is not the case?
> 
> Again speculation. But to answer your question, only dwc3 is in such a
> case today. But even for dwc3 we can have DRD with a much, much simpler
> setup as I have already explained.
> 
>> 3) Even if host and gadget controllers can operate in coexistence,
>> there is no need for both to be running for embedded applications
>> which are usually power conservative.  How can we achieve that?
> 
> Now you're also speculating that you're running on embedded applications
> and that we _can_ power off parts of the IP. I happen to know that we
> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
> Clocks and power rails as the peripheral side.
> 
> [1] https://lkml.org/lkml/2016/6/21/658
> 
For TI's case it is dwc3 and you are implementing the role swap in the dwc3
driver where you do intend to remove the XHCI platform device. So I'm not
much concerned about that.

I was concerned about other platforms. I guess I'll let the other platform
people speak up as to what they need.

--
cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-22  8:30                             ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-22  8:30 UTC (permalink / raw)
  To: Felipe Balbi, Peter Chen, yoshihiro.shimoda.uh
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree


[-- Attachment #1.1: Type: text/plain, Size: 5630 bytes --]

On 22/06/16 11:14, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>
>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>> states to finish role swap.
>>>>>>>
>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>
>>>>>> Change current role from host to peripheral.
>>>>>
>>>>> Okay, we have two scenarios here:
>>>>>
>>>>> 1. You need full OTG compliance
>>>>>
>>>>> 	For this, granted, you need the state machine if your HW doesn't
>>>>> 	track it. This is a given. With only one user, however, perhaps
>>>>> 	we don't need a generic layer. There are not enough different
>>>>> 	setups to design a good enough generic layer. We will end up
>>>>> 	with a pseudo-generic framework which is coupled with its only
>>>>> 	user.
>>>>>
>>>>> 2. Dual-role support, without OTG compliance
>>>>>
>>>>> 	In this case, you don't need a stack. All you need is a signal
>>>>> 	to tell you state of ID pin and another to tell you state of
>>>>> 	VBUS level. If you have those, you don't need to walk an OTG
>>>>> 	state machine at all. You don't need any of those quirky OTG
>>>>> 	timers, agreed?
>>>>>
>>>>> 	Given the above, why would you even want to use a subset of OTG
>>>>> 	state machine to implement something that's _usually_ as simple
>>>>> 	as:
>>>>>
>>>>> 8<----------------------------------------------------------------------
>>>>> 	vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>
>>>>>         set_role(id);
>>>>>         set_vbus(vbus);
>>>>> ------------------------------------------------------------------------
>>>>>
>>>>
>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>> framework is worthwhile or not, we would like to see if it can
>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>> has different drivers for host and peripheral to finish the role switch
>>>> well.
>>>
>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>> that just goes back to the same driver?
>>
>> What do you mean by same driver?
> 
> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
> layer jumps to a callback that goes back to dwc3 to e.g. start
> peripheral side.
> 
> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
> 
>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>> be 3 totally independent drivers unlike dwc3 where you have a single
>> driver in control of both host and gadget.
> 
> That's a totally different issue and one not being tackled by OTG
> layer, because there are no such users yet. We can't design anything
> based solely on speculation of what might happen.
> 
> If there aren't enough users, there is no way to design a good generic
> layer.
> 
>> Questions not clear to me are:
>>
>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>> role swap?  Probably the PHY/MUX driver?
> 
> This is implementation dependent. For TI's USB subsystem, we have PMIC
> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
> has no intervention.
> 
> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
> internal mux (much like TI's UTMI mailbox, but slightly different) to
> switch between a separate XHCI or a separate dwc3. The same mux can be
> put in HW-mode where SW has no intervention.
> 
> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
> driver just detects role (at least for Type-C based plats) and executes
> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
> VBUS and, for type-C, toggle VCONN when needed.
> 
>> 2) How does it perform the role swap? Probably a register write to the
>> PHY/MUX without needing to stop/start controllers? Easy case is both
>> controllers can run in co-existence without interference. Is there any
>> platform other than dwc3 where this is not the case?
> 
> Again speculation. But to answer your question, only dwc3 is in such a
> case today. But even for dwc3 we can have DRD with a much, much simpler
> setup as I have already explained.
> 
>> 3) Even if host and gadget controllers can operate in coexistence,
>> there is no need for both to be running for embedded applications
>> which are usually power conservative.  How can we achieve that?
> 
> Now you're also speculating that you're running on embedded applications
> and that we _can_ power off parts of the IP. I happen to know that we
> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
> Clocks and power rails as the peripheral side.
> 
> [1] https://lkml.org/lkml/2016/6/21/658
> 
For TI's case it is dwc3 and you are implementing the role swap in the dwc3
driver where you do intend to remove the XHCI platform device. So I'm not
much concerned about that.

I was concerned about other platforms. I guess I'll let the other platform
people speak up as to what they need.

--
cheers,
-roger


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  3:33                             ` Peter Chen
@ 2016-06-23  7:41                               ` Yoshihiro Shimoda
  -1 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-23  7:41 UTC (permalink / raw)
  To: Peter Chen, Felipe Balbi
  Cc: Roger Quadros, peter.chen, tony, gregkh, dan.j.williams,
	mathias.nyman, Joao.Pinto, sergei.shtylyov, jun.li,
	grygorii.strashko, robh, nsekhar, b-liu, joe, linux-usb,
	linux-omap, linux-kernel, devicetree

Hi,

> From: Peter Chen
> Sent: Wednesday, June 22, 2016 12:34 PM
> 
> On Tue, Jun 21, 2016 at 05:47:47PM +0300, Felipe Balbi wrote:
> >
> > Hi,
> >
> > Peter Chen <hzpeterchen@gmail.com> writes:
> > >> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> > >> >> >> >> >>
> > >> >> >> >> >> do you really know of any platform which has a separate OTG controller?
> > >> >> >> >> >>
> > >> >> >> >> >
> > >> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> > >> >> >> >> > and gadget.
> > >> >> >> >> >
> > >> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> > >> >> >> >>
> > >> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> > >> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> > >> >> >> >>
> > >> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> > >> >> >> >> are two competing standards and, apparently, type-C is winning when it
> > >> >> >> >> comes to role-swapping.
> > >> >> >> >>
> > >> >> >> >
> > >> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> > >> >> >> > It will be considered as an OTG port.
> > >> >> >>
> > >> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> > >> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> > >> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> > >> >> >
> > >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> > >> >> > "OTG" in Linux, right?
> > >> >>
> > >> >> to avoid confusion with the terminology, yes. With that settled, let's
> > >> >> figure out how you can deliver what your marketting guys are asking of
> > >> >> you.
> > >> >>
> > >> >
> > >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> > >> > test. The internal bsp has passed PET test, and formal compliance test
> > >> > is on the way (should pass too).
> > >> >
> > >> > The dual-role and OTG compliance use the same zImage, but different
> > >> > dtb.
> > >>
> > >> okay, that's good to know. Now, the question really is: considering we
> > >> only have one user for this generic OTG FSM layer, do we really need to
> > >> make it generic at all? I mean, just look at how invasive a change that
> > >> is.
> > >
> > > If the chipidea is the only user for this roger's framework, I don't
> > > think it is necessary. In fact, Roger introduces this framework, and
> > > the first user is dwc3, we think it can be used for others. Let's
> >
> > Right, we need to look at the history of dwc3 to figure out why the
> > conclusion that dwc3 needs this was made.
> >
> > Roger started working on this framework when Power on Reset section of
> > databook had some details which weren't always clear and, for safety, we
> > always had reset asserted for a really long time. It was so long (about
> > 400 ms) that resetting dwc3 for each role swap was just too much.
> >
> > Coupled with that, the OTG chapter wasn't very clear either on
> > expections from Host and Peripheral side initialization in OTG/DRD
> > systems.
> >
> > More recent version of dwc3 databook have a much better description of
> > how and which reset bits _must_ be asserted and which shouldn't be
> > touched unless it's for debugging purposes. When I implemented that, our
> > ->probe() went from 400ms down to about 50us.
> >
> > Coupled with that, the OTG chapter also became a lot clearer to the
> > point that it states you just don't initialize anything other than the
> > OTG block, and just wait for OTG interrupt to do whatever it is you need
> > to do.
> >
> > This meant that we could actually afford to do full reinitialization of
> > dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> > roles properly.
> >
> > (The reason for needing soft-reset during role swap is kinda long. But
> > in summary dwc3 shadows register writes to both host and peripheral
> > sides)
> >
> > > just discuss if it is necessary for dual-role switch.
> >
> > fair. However, if we have a single user we don't have a Generic
> > layer. There's not enough variance to come up with truly generic
> > architecture for this.
> >
> > --
> 
> I have put some points in my last reply [1], I summery it here to
> see if a generic framework is deserved or not?
> 
> 1. If there are some parts we can use during the role switch
> - The common start/stop host and peripheral operation
> eg, when switch from host to peripheral, all drivers can use
> usb_remove_hcd to finish it.
> - A common workqueue to handle vbus and id event
> - sysfs for role switch
> 
> 2. Does a mux driver can do it well? Yoshihiro, here we need your
> point. The main point is if we need to call USB API to change
> roles (eg, usb_remove_hcd) during the role switch, thanks.

In my platform, it doesn't need to call USB API (usb_remove_hcd) when
"A-host" is changed to "A-peripheral".
(Since this is a prototype local code, the code is not upstreaming yet though.)

Best regards,
Yoshihiro Shimoda

> 
> [1] http://www.spinics.net/lists/linux-usb/msg142974.html
> --
> 
> Best Regards,
> Peter Chen

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-23  7:41                               ` Yoshihiro Shimoda
  0 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-23  7:41 UTC (permalink / raw)
  To: Peter Chen, Felipe Balbi
  Cc: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg,
	tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TbrhsbdSgBK9A

Hi,

> From: Peter Chen
> Sent: Wednesday, June 22, 2016 12:34 PM
> 
> On Tue, Jun 21, 2016 at 05:47:47PM +0300, Felipe Balbi wrote:
> >
> > Hi,
> >
> > Peter Chen <hzpeterchen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> > >> >> >> >> >>> + * @otg_dev: OTG controller device, if needs to be used with OTG core.
> > >> >> >> >> >>
> > >> >> >> >> >> do you really know of any platform which has a separate OTG controller?
> > >> >> >> >> >>
> > >> >> >> >> >
> > >> >> >> >> > Andrew had pointed out in [1] that Tegra210 has separate blocks for OTG, host
> > >> >> >> >> > and gadget.
> > >> >> >> >> >
> > >> >> >> >> > [1] http://article.gmane.org/gmane.linux.ports.tegra/22969
> > >> >> >> >>
> > >> >> >> >> that's not an OTG controller, it's just a mux. No different than Intel's
> > >> >> >> >> mux for swapping between XHCI and peripheral-only DWC3.
> > >> >> >> >>
> > >> >> >> >> frankly, I would NEVER talk about OTG when type-C comes into play. They
> > >> >> >> >> are two competing standards and, apparently, type-C is winning when it
> > >> >> >> >> comes to role-swapping.
> > >> >> >> >>
> > >> >> >> >
> > >> >> >> > In fact, OTG is mis-used by people. Currently, if the port is dual-role,
> > >> >> >> > It will be considered as an OTG port.
> > >> >> >>
> > >> >> >> That's because "dual-role" is a non-standard OTG. Seen as people really
> > >> >> >> didn't care about OTG, we (linux-usb folks) ended up naturally referring
> > >> >> >> to "non-standard OTG" as "dual-role". Just to avoid confusion.
> > >> >> >
> > >> >> > So, unless we use OTG FSM defined in OTG spec, we should not mention
> > >> >> > "OTG" in Linux, right?
> > >> >>
> > >> >> to avoid confusion with the terminology, yes. With that settled, let's
> > >> >> figure out how you can deliver what your marketting guys are asking of
> > >> >> you.
> > >> >>
> > >> >
> > >> > Since nxp SoC claims they are OTG compliance, we need to pass usb.org
> > >> > test. The internal bsp has passed PET test, and formal compliance test
> > >> > is on the way (should pass too).
> > >> >
> > >> > The dual-role and OTG compliance use the same zImage, but different
> > >> > dtb.
> > >>
> > >> okay, that's good to know. Now, the question really is: considering we
> > >> only have one user for this generic OTG FSM layer, do we really need to
> > >> make it generic at all? I mean, just look at how invasive a change that
> > >> is.
> > >
> > > If the chipidea is the only user for this roger's framework, I don't
> > > think it is necessary. In fact, Roger introduces this framework, and
> > > the first user is dwc3, we think it can be used for others. Let's
> >
> > Right, we need to look at the history of dwc3 to figure out why the
> > conclusion that dwc3 needs this was made.
> >
> > Roger started working on this framework when Power on Reset section of
> > databook had some details which weren't always clear and, for safety, we
> > always had reset asserted for a really long time. It was so long (about
> > 400 ms) that resetting dwc3 for each role swap was just too much.
> >
> > Coupled with that, the OTG chapter wasn't very clear either on
> > expections from Host and Peripheral side initialization in OTG/DRD
> > systems.
> >
> > More recent version of dwc3 databook have a much better description of
> > how and which reset bits _must_ be asserted and which shouldn't be
> > touched unless it's for debugging purposes. When I implemented that, our
> > ->probe() went from 400ms down to about 50us.
> >
> > Coupled with that, the OTG chapter also became a lot clearer to the
> > point that it states you just don't initialize anything other than the
> > OTG block, and just wait for OTG interrupt to do whatever it is you need
> > to do.
> >
> > This meant that we could actually afford to do full reinitialization of
> > dwc3 on role swap (it's now only 50us anyway) and we knew how to swap
> > roles properly.
> >
> > (The reason for needing soft-reset during role swap is kinda long. But
> > in summary dwc3 shadows register writes to both host and peripheral
> > sides)
> >
> > > just discuss if it is necessary for dual-role switch.
> >
> > fair. However, if we have a single user we don't have a Generic
> > layer. There's not enough variance to come up with truly generic
> > architecture for this.
> >
> > --
> 
> I have put some points in my last reply [1], I summery it here to
> see if a generic framework is deserved or not?
> 
> 1. If there are some parts we can use during the role switch
> - The common start/stop host and peripheral operation
> eg, when switch from host to peripheral, all drivers can use
> usb_remove_hcd to finish it.
> - A common workqueue to handle vbus and id event
> - sysfs for role switch
> 
> 2. Does a mux driver can do it well? Yoshihiro, here we need your
> point. The main point is if we need to call USB API to change
> roles (eg, usb_remove_hcd) during the role switch, thanks.

In my platform, it doesn't need to call USB API (usb_remove_hcd) when
"A-host" is changed to "A-peripheral".
(Since this is a prototype local code, the code is not upstreaming yet though.)

Best regards,
Yoshihiro Shimoda

> 
> [1] http://www.spinics.net/lists/linux-usb/msg142974.html
> --
> 
> Best Regards,
> Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-23  7:42                           ` Yoshihiro Shimoda
  0 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-23  7:42 UTC (permalink / raw)
  To: Roger Quadros, Felipe Balbi, Peter Chen
  Cc: peter.chen, tony, gregkh, dan.j.williams, mathias.nyman,
	Joao.Pinto, sergei.shtylyov, jun.li, grygorii.strashko, robh,
	nsekhar, b-liu, joe, linux-usb, linux-omap, linux-kernel,
	devicetree

Hi Roger-san,

< snip >
> >>>> commit 11c011a5e777c83819078a18672543f04482b3ec
> >>>> Author: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> >>>> Date:   Thu May 19 11:12:56 2016 +0100
> >>>>
> >>>>     usb: echi-hcd: Add ehci_setup check before echi_shutdown
> >>>>
> >>>>
> >>>>
> >>>> In some cases, the USB code (gadget/hcd->start/stop) needs to be called
> >>>> during the role swap. For example, if you have mux driver, you may
> >>>> need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
> >>>> how can we do that?
> >>>
> >>> You don't really need to remove the gadget. Just mask its interrupts and
> >>> ignore any calls to any gadget_driver ops, right? Likewise for
> >>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
> >>> the point of view of dwc3, it's simpler to unregister the platform
> >>> device we create for xhci-plat.c. I need no changes in XHCI to do that
> >>> and driver model will make sure to call xhci-plat's ->remove() which
> >>> will handle everything for me correctly.
> >>>
> >>
> >> I admit it can do in a IP driver, eg both host and peripheral for the
> >> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
> >> or what else for HCD at mux driver?
> >
> > dwc3's OTG block has control of that, however, what I'll do is
> > platform_device_del() xhci-plat's device. Not one line changes inside
> > XHCI.
> >
> 
> Let's talk about how non dwc3 based platforms can get it done.
> 
> Yoshihiro-san, could you please share your platform requirements from dual-role
> perspective?

My platform requirements about dual-role are:
- Initial settings of all host, gadget and OTG IP registers are needed before enters [AB]-device recognition procedure.
- In the recognition procedures, a software needs:
 - to check ID pin related register in OTG
 - to set OTG IP registers to change the role
  - and then host or gadget can start.
- In the disconnect detection procedures, a software needs similar checkings/settings with the recognition.

Best regards,
Yoshihiro Shimoda

> cheers,
> -roger

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

* RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-23  7:42                           ` Yoshihiro Shimoda
  0 siblings, 0 replies; 172+ messages in thread
From: Yoshihiro Shimoda @ 2016-06-23  7:42 UTC (permalink / raw)
  To: Roger Quadros, Felipe Balbi, Peter Chen
  Cc: peter.chen-KZfg59tc24xl57MIdRCFDg, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, joe-6d6DIl74uiNBDgjK7y7TUQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Roger-san,

< snip >
> >>>> commit 11c011a5e777c83819078a18672543f04482b3ec
> >>>> Author: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> >>>> Date:   Thu May 19 11:12:56 2016 +0100
> >>>>
> >>>>     usb: echi-hcd: Add ehci_setup check before echi_shutdown
> >>>>
> >>>>
> >>>>
> >>>> In some cases, the USB code (gadget/hcd->start/stop) needs to be called
> >>>> during the role swap. For example, if you have mux driver, you may
> >>>> need to call usb_remove_hcd when ID from 0 to 1. Without Roger's framework,
> >>>> how can we do that?
> >>>
> >>> You don't really need to remove the gadget. Just mask its interrupts and
> >>> ignore any calls to any gadget_driver ops, right? Likewise for
> >>> XHCI. Just clear RUN/STOP and no events will ever reach XHCI. But, from
> >>> the point of view of dwc3, it's simpler to unregister the platform
> >>> device we create for xhci-plat.c. I need no changes in XHCI to do that
> >>> and driver model will make sure to call xhci-plat's ->remove() which
> >>> will handle everything for me correctly.
> >>>
> >>
> >> I admit it can do in a IP driver, eg both host and peripheral for the
> >> single IP, eg chipidea, dwc3, etc. But how can we clear RUN/STOP bit
> >> or what else for HCD at mux driver?
> >
> > dwc3's OTG block has control of that, however, what I'll do is
> > platform_device_del() xhci-plat's device. Not one line changes inside
> > XHCI.
> >
> 
> Let's talk about how non dwc3 based platforms can get it done.
> 
> Yoshihiro-san, could you please share your platform requirements from dual-role
> perspective?

My platform requirements about dual-role are:
- Initial settings of all host, gadget and OTG IP registers are needed before enters [AB]-device recognition procedure.
- In the recognition procedures, a software needs:
 - to check ID pin related register in OTG
 - to set OTG IP registers to change the role
  - and then host or gadget can start.
- In the disconnect detection procedures, a software needs similar checkings/settings with the recognition.

Best regards,
Yoshihiro Shimoda

> cheers,
> -roger

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2016-06-22  8:30                             ` Roger Quadros
  (?)
@ 2017-01-19 11:56                             ` Vivek Gautam
  2017-01-19 12:15                                 ` Roger Quadros
  -1 siblings, 1 reply; 172+ messages in thread
From: Vivek Gautam @ 2017-01-19 11:56 UTC (permalink / raw)
  To: Roger Quadros, Felipe Balbi
  Cc: Peter Chen, Yoshihiro Shimoda, peter.chen, Tony Lindgren,
	Greg KH, dan.j.williams, Mathias Nyman, Joao.Pinto,
	Sergei Shtylyov, jun.li, grygorii.strashko, Rob Herring, nsekhar,
	b-liu, Joe Perches, Linux USB Mailing List, linux-omap,
	linux-kernel, devicetree

Hi,


On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

> On 22/06/16 11:14, Felipe Balbi wrote:
>>
>> Hi,
>>
>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>
>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>> states to finish role swap.
>>>>>>>>
>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>
>>>>>>> Change current role from host to peripheral.
>>>>>>
>>>>>> Okay, we have two scenarios here:
>>>>>>
>>>>>> 1. You need full OTG compliance
>>>>>>
>>>>>>   For this, granted, you need the state machine if your HW doesn't
>>>>>>   track it. This is a given. With only one user, however, perhaps
>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>   user.
>>>>>>
>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>
>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>   timers, agreed?
>>>>>>
>>>>>>   Given the above, why would you even want to use a subset of OTG
>>>>>>   state machine to implement something that's _usually_ as simple
>>>>>>   as:
>>>>>>
>>>>>> 8<----------------------------------------------------------------------
>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>
>>>>>>         set_role(id);
>>>>>>         set_vbus(vbus);
>>>>>> ------------------------------------------------------------------------
>>>>>>
>>>>>
>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>> framework is worthwhile or not, we would like to see if it can
>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>> has different drivers for host and peripheral to finish the role switch
>>>>> well.
>>>>
>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>> that just goes back to the same driver?
>>>
>>> What do you mean by same driver?
>>
>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>> layer jumps to a callback that goes back to dwc3 to e.g. start
>> peripheral side.
>>
>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>
>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>> driver in control of both host and gadget.
>>
>> That's a totally different issue and one not being tackled by OTG
>> layer, because there are no such users yet. We can't design anything
>> based solely on speculation of what might happen.
>>
>> If there aren't enough users, there is no way to design a good generic
>> layer.
>>
>>> Questions not clear to me are:
>>>
>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>> role swap?  Probably the PHY/MUX driver?
>>
>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>> has no intervention.
>>
>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>> switch between a separate XHCI or a separate dwc3. The same mux can be
>> put in HW-mode where SW has no intervention.
>>
>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>> driver just detects role (at least for Type-C based plats) and executes
>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>> VBUS and, for type-C, toggle VCONN when needed.
>>
>>> 2) How does it perform the role swap? Probably a register write to the
>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>> controllers can run in co-existence without interference. Is there any
>>> platform other than dwc3 where this is not the case?
>>
>> Again speculation. But to answer your question, only dwc3 is in such a
>> case today. But even for dwc3 we can have DRD with a much, much simpler
>> setup as I have already explained.
>>
>>> 3) Even if host and gadget controllers can operate in coexistence,
>>> there is no need for both to be running for embedded applications
>>> which are usually power conservative.  How can we achieve that?
>>
>> Now you're also speculating that you're running on embedded applications
>> and that we _can_ power off parts of the IP. I happen to know that we
>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>> Clocks and power rails as the peripheral side.
>>
>> [1] https://lkml.org/lkml/2016/6/21/658
>>
> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
> driver where you do intend to remove the XHCI platform device. So I'm not
> much concerned about that.
>
> I was concerned about other platforms. I guess I'll let the other platform
> people speak up as to what they need.

I will talk about the msm platforms using dwc3 hardware.
DWC3 controller on msm doesn't seem to have full otg functionality,
and the driver makes use of switching between host and device
using PRTCAPDIR register in of the core [1].

We plan to support this DRD role switching (swapping host and device
functionality based on id/vbus interrupts) in upstream.

Do we see a valid case to have this framework?
Or, may be add a 'drd' layer for dwc3 that handles
role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.


[1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
     "dwc3_otg_start_host()"
     "dwc3_otg_start_peripheral()"


Regards
Vivek
-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2017-01-19 11:56                             ` Vivek Gautam
@ 2017-01-19 12:15                                 ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2017-01-19 12:15 UTC (permalink / raw)
  To: Vivek Gautam, Felipe Balbi
  Cc: Peter Chen, Yoshihiro Shimoda, peter.chen, Tony Lindgren,
	Greg KH, dan.j.williams, Mathias Nyman, Joao.Pinto,
	Sergei Shtylyov, jun.li, grygorii.strashko, Rob Herring, nsekhar,
	b-liu, Joe Perches, Linux USB Mailing List, linux-omap,
	linux-kernel, devicetree

Vivek,

On 19/01/17 13:56, Vivek Gautam wrote:
> Hi,
> 
> 
> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:
> 
> Luckily hit this thread while checking about DRD role functionality for DWC3.
> 
>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>
>>> Hi,
>>>
>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>
>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>>> states to finish role swap.
>>>>>>>>>
>>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>>
>>>>>>>> Change current role from host to peripheral.
>>>>>>>
>>>>>>> Okay, we have two scenarios here:
>>>>>>>
>>>>>>> 1. You need full OTG compliance
>>>>>>>
>>>>>>>   For this, granted, you need the state machine if your HW doesn't
>>>>>>>   track it. This is a given. With only one user, however, perhaps
>>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>>   user.
>>>>>>>
>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>
>>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>>   timers, agreed?
>>>>>>>
>>>>>>>   Given the above, why would you even want to use a subset of OTG
>>>>>>>   state machine to implement something that's _usually_ as simple
>>>>>>>   as:
>>>>>>>
>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>
>>>>>>>         set_role(id);
>>>>>>>         set_vbus(vbus);
>>>>>>> ------------------------------------------------------------------------
>>>>>>>
>>>>>>
>>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>>> has different drivers for host and peripheral to finish the role switch
>>>>>> well.
>>>>>
>>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>>> that just goes back to the same driver?
>>>>
>>>> What do you mean by same driver?
>>>
>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>> peripheral side.
>>>
>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>
>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>>> driver in control of both host and gadget.
>>>
>>> That's a totally different issue and one not being tackled by OTG
>>> layer, because there are no such users yet. We can't design anything
>>> based solely on speculation of what might happen.
>>>
>>> If there aren't enough users, there is no way to design a good generic
>>> layer.
>>>
>>>> Questions not clear to me are:
>>>>
>>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>>> role swap?  Probably the PHY/MUX driver?
>>>
>>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>>> has no intervention.
>>>
>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>>> switch between a separate XHCI or a separate dwc3. The same mux can be
>>> put in HW-mode where SW has no intervention.
>>>
>>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>>> driver just detects role (at least for Type-C based plats) and executes
>>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>>> VBUS and, for type-C, toggle VCONN when needed.
>>>
>>>> 2) How does it perform the role swap? Probably a register write to the
>>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>>> controllers can run in co-existence without interference. Is there any
>>>> platform other than dwc3 where this is not the case?
>>>
>>> Again speculation. But to answer your question, only dwc3 is in such a
>>> case today. But even for dwc3 we can have DRD with a much, much simpler
>>> setup as I have already explained.
>>>
>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>> there is no need for both to be running for embedded applications
>>>> which are usually power conservative.  How can we achieve that?
>>>
>>> Now you're also speculating that you're running on embedded applications
>>> and that we _can_ power off parts of the IP. I happen to know that we
>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>>> Clocks and power rails as the peripheral side.
>>>
>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>
>> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
>> driver where you do intend to remove the XHCI platform device. So I'm not
>> much concerned about that.
>>
>> I was concerned about other platforms. I guess I'll let the other platform
>> people speak up as to what they need.
> 
> I will talk about the msm platforms using dwc3 hardware.
> DWC3 controller on msm doesn't seem to have full otg functionality,
> and the driver makes use of switching between host and device
> using PRTCAPDIR register in of the core [1].
> 
> We plan to support this DRD role switching (swapping host and device
> functionality based on id/vbus interrupts) in upstream.
> 
> Do we see a valid case to have this framework?

Felipe wanted to have a minimal dual-role logic inside dwc3 which is
independent of any DRD/OTG framework.

I have implemented this and will send out patches today for review.

> Or, may be add a 'drd' layer for dwc3 that handles
> role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.
> 
> 
> [1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>      "dwc3_otg_start_host()"
>      "dwc3_otg_start_peripheral()"
> 
> 

regards,
-roger

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2017-01-19 12:15                                 ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2017-01-19 12:15 UTC (permalink / raw)
  To: Vivek Gautam, Felipe Balbi
  Cc: Peter Chen, Yoshihiro Shimoda, peter.chen, Tony Lindgren,
	Greg KH, dan.j.williams, Mathias Nyman, Joao.Pinto,
	Sergei Shtylyov, jun.li, grygorii.strashko, Rob Herring, nsekhar,
	b-liu, Joe Perches, Linux USB Mailing List, linux-omap,
	linux-kernel, devicetree

Vivek,

On 19/01/17 13:56, Vivek Gautam wrote:
> Hi,
> 
> 
> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:
> 
> Luckily hit this thread while checking about DRD role functionality for DWC3.
> 
>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>
>>> Hi,
>>>
>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>
>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>>> states to finish role swap.
>>>>>>>>>
>>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>>
>>>>>>>> Change current role from host to peripheral.
>>>>>>>
>>>>>>> Okay, we have two scenarios here:
>>>>>>>
>>>>>>> 1. You need full OTG compliance
>>>>>>>
>>>>>>>   For this, granted, you need the state machine if your HW doesn't
>>>>>>>   track it. This is a given. With only one user, however, perhaps
>>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>>   user.
>>>>>>>
>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>
>>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>>   timers, agreed?
>>>>>>>
>>>>>>>   Given the above, why would you even want to use a subset of OTG
>>>>>>>   state machine to implement something that's _usually_ as simple
>>>>>>>   as:
>>>>>>>
>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>
>>>>>>>         set_role(id);
>>>>>>>         set_vbus(vbus);
>>>>>>> ------------------------------------------------------------------------
>>>>>>>
>>>>>>
>>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>>> has different drivers for host and peripheral to finish the role switch
>>>>>> well.
>>>>>
>>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>>> that just goes back to the same driver?
>>>>
>>>> What do you mean by same driver?
>>>
>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>> peripheral side.
>>>
>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>
>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>>> driver in control of both host and gadget.
>>>
>>> That's a totally different issue and one not being tackled by OTG
>>> layer, because there are no such users yet. We can't design anything
>>> based solely on speculation of what might happen.
>>>
>>> If there aren't enough users, there is no way to design a good generic
>>> layer.
>>>
>>>> Questions not clear to me are:
>>>>
>>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>>> role swap?  Probably the PHY/MUX driver?
>>>
>>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>>> has no intervention.
>>>
>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>>> switch between a separate XHCI or a separate dwc3. The same mux can be
>>> put in HW-mode where SW has no intervention.
>>>
>>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>>> driver just detects role (at least for Type-C based plats) and executes
>>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>>> VBUS and, for type-C, toggle VCONN when needed.
>>>
>>>> 2) How does it perform the role swap? Probably a register write to the
>>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>>> controllers can run in co-existence without interference. Is there any
>>>> platform other than dwc3 where this is not the case?
>>>
>>> Again speculation. But to answer your question, only dwc3 is in such a
>>> case today. But even for dwc3 we can have DRD with a much, much simpler
>>> setup as I have already explained.
>>>
>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>> there is no need for both to be running for embedded applications
>>>> which are usually power conservative.  How can we achieve that?
>>>
>>> Now you're also speculating that you're running on embedded applications
>>> and that we _can_ power off parts of the IP. I happen to know that we
>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>>> Clocks and power rails as the peripheral side.
>>>
>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>
>> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
>> driver where you do intend to remove the XHCI platform device. So I'm not
>> much concerned about that.
>>
>> I was concerned about other platforms. I guess I'll let the other platform
>> people speak up as to what they need.
> 
> I will talk about the msm platforms using dwc3 hardware.
> DWC3 controller on msm doesn't seem to have full otg functionality,
> and the driver makes use of switching between host and device
> using PRTCAPDIR register in of the core [1].
> 
> We plan to support this DRD role switching (swapping host and device
> functionality based on id/vbus interrupts) in upstream.
> 
> Do we see a valid case to have this framework?

Felipe wanted to have a minimal dual-role logic inside dwc3 which is
independent of any DRD/OTG framework.

I have implemented this and will send out patches today for review.

> Or, may be add a 'drd' layer for dwc3 that handles
> role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.
> 
> 
> [1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>      "dwc3_otg_start_host()"
>      "dwc3_otg_start_peripheral()"
> 
> 

regards,
-roger

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2017-01-19 12:15                                 ` Roger Quadros
  (?)
@ 2017-01-19 15:15                                 ` vivek.gautam
  2017-01-20  8:30                                     ` Roger Quadros
  -1 siblings, 1 reply; 172+ messages in thread
From: vivek.gautam @ 2017-01-19 15:15 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Felipe Balbi, Peter Chen, Yoshihiro Shimoda, peter.chen,
	Tony Lindgren, Greg KH, dan.j.williams, Mathias Nyman,
	Joao.Pinto, Sergei Shtylyov, jun.li, grygorii.strashko,
	Rob Herring, nsekhar, b-liu, Joe Perches, Linux USB Mailing List,
	linux-omap, linux-kernel, devicetree

Hi Roger,

On 2017-01-19 17:45, Roger Quadros wrote:
> Vivek,
> 
> On 19/01/17 13:56, Vivek Gautam wrote:
>> Hi,
>> 
>> 
>> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:
>> 
>> Luckily hit this thread while checking about DRD role functionality 
>> for DWC3.
>> 
>>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>> 
>>>> Hi,
>>>> 
>>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>> 
>>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own 
>>>>>>>>>>>> proprietary and closed
>>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some 
>>>>>>>>>>> standard OTG FSM
>>>>>>>>>>> states to finish role swap.
>>>>>>>>>> 
>>>>>>>>>> What are you referring to as "finish role swap"? I don't get 
>>>>>>>>>> that.
>>>>>>>>> 
>>>>>>>>> Change current role from host to peripheral.
>>>>>>>> 
>>>>>>>> Okay, we have two scenarios here:
>>>>>>>> 
>>>>>>>> 1. You need full OTG compliance
>>>>>>>> 
>>>>>>>>   For this, granted, you need the state machine if your HW 
>>>>>>>> doesn't
>>>>>>>>   track it. This is a given. With only one user, however, 
>>>>>>>> perhaps
>>>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>>>   user.
>>>>>>>> 
>>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>> 
>>>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>>>   timers, agreed?
>>>>>>>> 
>>>>>>>>   Given the above, why would you even want to use a subset of 
>>>>>>>> OTG
>>>>>>>>   state machine to implement something that's _usually_ as 
>>>>>>>> simple
>>>>>>>>   as:
>>>>>>>> 
>>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>> 
>>>>>>>>         set_role(id);
>>>>>>>>         set_vbus(vbus);
>>>>>>>> ------------------------------------------------------------------------
>>>>>>>> 
>>>>>>> 
>>>>>>> In fact, the individual driver can do it by itself. The chipidea 
>>>>>>> driver
>>>>>>> handles OTG and dual-role well currently. By considering this 
>>>>>>> OTG/DRD
>>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>>> simplify DRD design for each driver, and can benefit the 
>>>>>>> platforms which
>>>>>>> has different drivers for host and peripheral to finish the role 
>>>>>>> switch
>>>>>>> well.
>>>>>> 
>>>>>> simplify how?  By adding unnecessary workqueues and a level 
>>>>>> indirection
>>>>>> that just goes back to the same driver?
>>>>> 
>>>>> What do you mean by same driver?
>>>> 
>>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and 
>>>> OTG
>>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>>> peripheral side.
>>>> 
>>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>> 
>>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) 
>>>>> can
>>>>> be 3 totally independent drivers unlike dwc3 where you have a 
>>>>> single
>>>>> driver in control of both host and gadget.
>>>> 
>>>> That's a totally different issue and one not being tackled by OTG
>>>> layer, because there are no such users yet. We can't design anything
>>>> based solely on speculation of what might happen.
>>>> 
>>>> If there aren't enough users, there is no way to design a good 
>>>> generic
>>>> layer.
>>>> 
>>>>> Questions not clear to me are:
>>>>> 
>>>>> 1) Which driver handles ID/VBUS events and makes a decision to do 
>>>>> the
>>>>> role swap?  Probably the PHY/MUX driver?
>>>> 
>>>> This is implementation dependent. For TI's USB subsystem, we have 
>>>> PMIC
>>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program 
>>>> UTMI
>>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where 
>>>> SW
>>>> has no intervention.
>>>> 
>>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>>> internal mux (much like TI's UTMI mailbox, but slightly different) 
>>>> to
>>>> switch between a separate XHCI or a separate dwc3. The same mux can 
>>>> be
>>>> put in HW-mode where SW has no intervention.
>>>> 
>>>> In any case, for Intel's stuff most of the magic happens in ASL. Our 
>>>> PHY
>>>> driver just detects role (at least for Type-C based plats) and 
>>>> executes
>>>> _DSM with correct arguments [1]. _DSM will program internal MUX, 
>>>> toggle
>>>> VBUS and, for type-C, toggle VCONN when needed.
>>>> 
>>>>> 2) How does it perform the role swap? Probably a register write to 
>>>>> the
>>>>> PHY/MUX without needing to stop/start controllers? Easy case is 
>>>>> both
>>>>> controllers can run in co-existence without interference. Is there 
>>>>> any
>>>>> platform other than dwc3 where this is not the case?
>>>> 
>>>> Again speculation. But to answer your question, only dwc3 is in such 
>>>> a
>>>> case today. But even for dwc3 we can have DRD with a much, much 
>>>> simpler
>>>> setup as I have already explained.
>>>> 
>>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>>> there is no need for both to be running for embedded applications
>>>>> which are usually power conservative.  How can we achieve that?
>>>> 
>>>> Now you're also speculating that you're running on embedded 
>>>> applications
>>>> and that we _can_ power off parts of the IP. I happen to know that 
>>>> we
>>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by 
>>>> same
>>>> Clocks and power rails as the peripheral side.
>>>> 
>>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>> 
>>> For TI's case it is dwc3 and you are implementing the role swap in 
>>> the dwc3
>>> driver where you do intend to remove the XHCI platform device. So I'm 
>>> not
>>> much concerned about that.
>>> 
>>> I was concerned about other platforms. I guess I'll let the other 
>>> platform
>>> people speak up as to what they need.
>> 
>> I will talk about the msm platforms using dwc3 hardware.
>> DWC3 controller on msm doesn't seem to have full otg functionality,
>> and the driver makes use of switching between host and device
>> using PRTCAPDIR register in of the core [1].
>> test
>> We plan to support this DRD role switching (swapping host and device
>> functionality based on id/vbus interrupts) in upstream.
>> 
>> Do we see a valid case to have this framework?
> 
> Felipe wanted to have a minimal dual-role logic inside dwc3 which is
> independent of any DRD/OTG framework.
> 
> I have implemented this and will send out patches today for review.

Okay, good to know that. I will be happy to take a look at the
patches and test them for msm.

Thanks for sharing the info.

> 
>> Or, may be add a 'drd' layer for dwc3 that handles
>> role switching (using PRTCAPDIR) based on the id/vbus extcon 
>> notifications.
>> 
>> 
>> [1] 
>> https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>>      "dwc3_otg_start_host()"
>>      "dwc3_otg_start_peripheral()"
>> 
>> 
> 
> regards,
> -roger


Regards
Vivek

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2017-01-20  8:30                                     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2017-01-20  8:30 UTC (permalink / raw)
  To: vivek.gautam
  Cc: Felipe Balbi, Peter Chen, Yoshihiro Shimoda, peter.chen,
	Tony Lindgren, Greg KH, dan.j.williams, Mathias Nyman,
	Joao.Pinto, Sergei Shtylyov, jun.li, grygorii.strashko,
	Rob Herring, nsekhar, b-liu, Joe Perches, Linux USB Mailing List,
	linux-omap, linux-kernel, devicetree

Vivek,

On 19/01/17 17:15, vivek.gautam@codeaurora.org wrote:
> Hi Roger,
> 
> On 2017-01-19 17:45, Roger Quadros wrote:
>> Vivek,
>>
>> On 19/01/17 13:56, Vivek Gautam wrote:
>>> Hi,
>>>
>>>
>>> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:
>>>
>>> Luckily hit this thread while checking about DRD role functionality for DWC3.
>>>
>>>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>>>>> states to finish role swap.
>>>>>>>>>>>
>>>>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>>>>
>>>>>>>>>> Change current role from host to peripheral.
>>>>>>>>>
>>>>>>>>> Okay, we have two scenarios here:
>>>>>>>>>
>>>>>>>>> 1. You need full OTG compliance
>>>>>>>>>
>>>>>>>>>   For this, granted, you need the state machine if your HW doesn't
>>>>>>>>>   track it. This is a given. With only one user, however, perhaps
>>>>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>>>>   user.
>>>>>>>>>
>>>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>>>
>>>>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>>>>   timers, agreed?
>>>>>>>>>
>>>>>>>>>   Given the above, why would you even want to use a subset of OTG
>>>>>>>>>   state machine to implement something that's _usually_ as simple
>>>>>>>>>   as:
>>>>>>>>>
>>>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>>>
>>>>>>>>>         set_role(id);
>>>>>>>>>         set_vbus(vbus);
>>>>>>>>> ------------------------------------------------------------------------
>>>>>>>>>
>>>>>>>>
>>>>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>>>>> has different drivers for host and peripheral to finish the role switch
>>>>>>>> well.
>>>>>>>
>>>>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>>>>> that just goes back to the same driver?
>>>>>>
>>>>>> What do you mean by same driver?
>>>>>
>>>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>>>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>>>> peripheral side.
>>>>>
>>>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>>>
>>>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>>>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>>>>> driver in control of both host and gadget.
>>>>>
>>>>> That's a totally different issue and one not being tackled by OTG
>>>>> layer, because there are no such users yet. We can't design anything
>>>>> based solely on speculation of what might happen.
>>>>>
>>>>> If there aren't enough users, there is no way to design a good generic
>>>>> layer.
>>>>>
>>>>>> Questions not clear to me are:
>>>>>>
>>>>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>>>>> role swap?  Probably the PHY/MUX driver?
>>>>>
>>>>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>>>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>>>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>>>>> has no intervention.
>>>>>
>>>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>>>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>>>>> switch between a separate XHCI or a separate dwc3. The same mux can be
>>>>> put in HW-mode where SW has no intervention.
>>>>>
>>>>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>>>>> driver just detects role (at least for Type-C based plats) and executes
>>>>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>>>>> VBUS and, for type-C, toggle VCONN when needed.
>>>>>
>>>>>> 2) How does it perform the role swap? Probably a register write to the
>>>>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>>>>> controllers can run in co-existence without interference. Is there any
>>>>>> platform other than dwc3 where this is not the case?
>>>>>
>>>>> Again speculation. But to answer your question, only dwc3 is in such a
>>>>> case today. But even for dwc3 we can have DRD with a much, much simpler
>>>>> setup as I have already explained.
>>>>>
>>>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>>>> there is no need for both to be running for embedded applications
>>>>>> which are usually power conservative.  How can we achieve that?
>>>>>
>>>>> Now you're also speculating that you're running on embedded applications
>>>>> and that we _can_ power off parts of the IP. I happen to know that we
>>>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>>>>> Clocks and power rails as the peripheral side.
>>>>>
>>>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>>>
>>>> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
>>>> driver where you do intend to remove the XHCI platform device. So I'm not
>>>> much concerned about that.
>>>>
>>>> I was concerned about other platforms. I guess I'll let the other platform
>>>> people speak up as to what they need.
>>>
>>> I will talk about the msm platforms using dwc3 hardware.
>>> DWC3 controller on msm doesn't seem to have full otg functionality,
>>> and the driver makes use of switching between host and device
>>> using PRTCAPDIR register in of the core [1].
>>> test
>>> We plan to support this DRD role switching (swapping host and device
>>> functionality based on id/vbus interrupts) in upstream.
>>>
>>> Do we see a valid case to have this framework?
>>
>> Felipe wanted to have a minimal dual-role logic inside dwc3 which is
>> independent of any DRD/OTG framework.
>>
>> I have implemented this and will send out patches today for review.
> 
> Okay, good to know that. I will be happy to take a look at the
> patches and test them for msm.

At least for now, I'm relying on the OTG controller to know about the VBUS and ID
line state and switch controller roles between host and peripheral.
i.e. I'm keeping the PRTCAPDIR register as OTG always.

Does the msm SoC have the dwc3 OTG controller IP?

> 
> Thanks for sharing the info.
> 
>>
>>> Or, may be add a 'drd' layer for dwc3 that handles
>>> role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.
>>>
>>>
>>> [1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>>>      "dwc3_otg_start_host()"
>>>      "dwc3_otg_start_peripheral()"
>>>
>>>
>>

--
cheers,
-roger

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
@ 2017-01-20  8:30                                     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2017-01-20  8:30 UTC (permalink / raw)
  To: vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: Felipe Balbi, Peter Chen, Yoshihiro Shimoda,
	peter.chen-KZfg59tc24xl57MIdRCFDg, Tony Lindgren, Greg KH,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w, Mathias Nyman,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w, Sergei Shtylyov,
	jun.li-KZfg59tc24xl57MIdRCFDg, grygorii.strashko-l0cyMroinI0,
	Rob Herring, nsekhar-l0cyMroinI0, b-liu-l0cyMroinI0, Joe Perches,
	Linux USB Mailing List, linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Vivek,

On 19/01/17 17:15, vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org wrote:
> Hi Roger,
> 
> On 2017-01-19 17:45, Roger Quadros wrote:
>> Vivek,
>>
>> On 19/01/17 13:56, Vivek Gautam wrote:
>>> Hi,
>>>
>>>
>>> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> wrote:
>>>
>>> Luckily hit this thread while checking about DRD role functionality for DWC3.
>>>
>>>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>>>>> states to finish role swap.
>>>>>>>>>>>
>>>>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>>>>
>>>>>>>>>> Change current role from host to peripheral.
>>>>>>>>>
>>>>>>>>> Okay, we have two scenarios here:
>>>>>>>>>
>>>>>>>>> 1. You need full OTG compliance
>>>>>>>>>
>>>>>>>>>   For this, granted, you need the state machine if your HW doesn't
>>>>>>>>>   track it. This is a given. With only one user, however, perhaps
>>>>>>>>>   we don't need a generic layer. There are not enough different
>>>>>>>>>   setups to design a good enough generic layer. We will end up
>>>>>>>>>   with a pseudo-generic framework which is coupled with its only
>>>>>>>>>   user.
>>>>>>>>>
>>>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>>>
>>>>>>>>>   In this case, you don't need a stack. All you need is a signal
>>>>>>>>>   to tell you state of ID pin and another to tell you state of
>>>>>>>>>   VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>>>   state machine at all. You don't need any of those quirky OTG
>>>>>>>>>   timers, agreed?
>>>>>>>>>
>>>>>>>>>   Given the above, why would you even want to use a subset of OTG
>>>>>>>>>   state machine to implement something that's _usually_ as simple
>>>>>>>>>   as:
>>>>>>>>>
>>>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>>>   vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>>>         id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>>>
>>>>>>>>>         set_role(id);
>>>>>>>>>         set_vbus(vbus);
>>>>>>>>> ------------------------------------------------------------------------
>>>>>>>>>
>>>>>>>>
>>>>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>>>>> has different drivers for host and peripheral to finish the role switch
>>>>>>>> well.
>>>>>>>
>>>>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>>>>> that just goes back to the same driver?
>>>>>>
>>>>>> What do you mean by same driver?
>>>>>
>>>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>>>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>>>> peripheral side.
>>>>>
>>>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>>>
>>>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>>>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>>>>> driver in control of both host and gadget.
>>>>>
>>>>> That's a totally different issue and one not being tackled by OTG
>>>>> layer, because there are no such users yet. We can't design anything
>>>>> based solely on speculation of what might happen.
>>>>>
>>>>> If there aren't enough users, there is no way to design a good generic
>>>>> layer.
>>>>>
>>>>>> Questions not clear to me are:
>>>>>>
>>>>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>>>>> role swap?  Probably the PHY/MUX driver?
>>>>>
>>>>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>>>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>>>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>>>>> has no intervention.
>>>>>
>>>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>>>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>>>>> switch between a separate XHCI or a separate dwc3. The same mux can be
>>>>> put in HW-mode where SW has no intervention.
>>>>>
>>>>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>>>>> driver just detects role (at least for Type-C based plats) and executes
>>>>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>>>>> VBUS and, for type-C, toggle VCONN when needed.
>>>>>
>>>>>> 2) How does it perform the role swap? Probably a register write to the
>>>>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>>>>> controllers can run in co-existence without interference. Is there any
>>>>>> platform other than dwc3 where this is not the case?
>>>>>
>>>>> Again speculation. But to answer your question, only dwc3 is in such a
>>>>> case today. But even for dwc3 we can have DRD with a much, much simpler
>>>>> setup as I have already explained.
>>>>>
>>>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>>>> there is no need for both to be running for embedded applications
>>>>>> which are usually power conservative.  How can we achieve that?
>>>>>
>>>>> Now you're also speculating that you're running on embedded applications
>>>>> and that we _can_ power off parts of the IP. I happen to know that we
>>>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>>>>> Clocks and power rails as the peripheral side.
>>>>>
>>>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>>>
>>>> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
>>>> driver where you do intend to remove the XHCI platform device. So I'm not
>>>> much concerned about that.
>>>>
>>>> I was concerned about other platforms. I guess I'll let the other platform
>>>> people speak up as to what they need.
>>>
>>> I will talk about the msm platforms using dwc3 hardware.
>>> DWC3 controller on msm doesn't seem to have full otg functionality,
>>> and the driver makes use of switching between host and device
>>> using PRTCAPDIR register in of the core [1].
>>> test
>>> We plan to support this DRD role switching (swapping host and device
>>> functionality based on id/vbus interrupts) in upstream.
>>>
>>> Do we see a valid case to have this framework?
>>
>> Felipe wanted to have a minimal dual-role logic inside dwc3 which is
>> independent of any DRD/OTG framework.
>>
>> I have implemented this and will send out patches today for review.
> 
> Okay, good to know that. I will be happy to take a look at the
> patches and test them for msm.

At least for now, I'm relying on the OTG controller to know about the VBUS and ID
line state and switch controller roles between host and peripheral.
i.e. I'm keeping the PRTCAPDIR register as OTG always.

Does the msm SoC have the dwc3 OTG controller IP?

> 
> Thanks for sharing the info.
> 
>>
>>> Or, may be add a 'drd' layer for dwc3 that handles
>>> role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.
>>>
>>>
>>> [1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>>>      "dwc3_otg_start_host()"
>>>      "dwc3_otg_start_peripheral()"
>>>
>>>
>>

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

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

* Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core
  2017-01-20  8:30                                     ` Roger Quadros
  (?)
@ 2017-01-20 11:39                                     ` Vivek Gautam
  -1 siblings, 0 replies; 172+ messages in thread
From: Vivek Gautam @ 2017-01-20 11:39 UTC (permalink / raw)
  To: Roger Quadros
  Cc: Felipe Balbi, Peter Chen, Yoshihiro Shimoda, peter.chen,
	Tony Lindgren, Greg KH, dan.j.williams, Mathias Nyman,
	Joao.Pinto, Sergei Shtylyov, jun.li, grygorii.strashko,
	Rob Herring, nsekhar, b-liu, Joe Perches, Linux USB Mailing List,
	linux-omap, linux-kernel, devicetree



On 01/20/2017 02:00 PM, Roger Quadros wrote:
> Vivek,
>
> On 19/01/17 17:15, vivek.gautam@codeaurora.org wrote:
>> Hi Roger,
>>
>> On 2017-01-19 17:45, Roger Quadros wrote:
>>> Vivek,
>>>
>>> On 19/01/17 13:56, Vivek Gautam wrote:
>>>> Hi,
>>>>
>>>>
>>>> On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <rogerq@ti.com> wrote:
>>>>
>>>> Luckily hit this thread while checking about DRD role functionality for DWC3.
>>>>
>>>>> On 22/06/16 11:14, Felipe Balbi wrote:
>>>>>> Hi,
>>>>>>
>>>>>> Roger Quadros <rogerq@ti.com> writes:
>>>>>>>>>>>>>>> For the real use case, some Carplay platforms need it.
>>>>>>>>>>>>>> Carplay does *NOT* rely on OTG. Apple has its own proprietary and closed
>>>>>>>>>>>>>> specification which is not OTG-compliant.
>>>>>>>>>>>>>>
>>>>>>>>>>>>> Yes, it is not OTG-compliant, but it can co-work with some standard OTG FSM
>>>>>>>>>>>>> states to finish role swap.
>>>>>>>>>>>> What are you referring to as "finish role swap"? I don't get that.
>>>>>>>>>>> Change current role from host to peripheral.
>>>>>>>>>> Okay, we have two scenarios here:
>>>>>>>>>>
>>>>>>>>>> 1. You need full OTG compliance
>>>>>>>>>>
>>>>>>>>>>    For this, granted, you need the state machine if your HW doesn't
>>>>>>>>>>    track it. This is a given. With only one user, however, perhaps
>>>>>>>>>>    we don't need a generic layer. There are not enough different
>>>>>>>>>>    setups to design a good enough generic layer. We will end up
>>>>>>>>>>    with a pseudo-generic framework which is coupled with its only
>>>>>>>>>>    user.
>>>>>>>>>>
>>>>>>>>>> 2. Dual-role support, without OTG compliance
>>>>>>>>>>
>>>>>>>>>>    In this case, you don't need a stack. All you need is a signal
>>>>>>>>>>    to tell you state of ID pin and another to tell you state of
>>>>>>>>>>    VBUS level. If you have those, you don't need to walk an OTG
>>>>>>>>>>    state machine at all. You don't need any of those quirky OTG
>>>>>>>>>>    timers, agreed?
>>>>>>>>>>
>>>>>>>>>>    Given the above, why would you even want to use a subset of OTG
>>>>>>>>>>    state machine to implement something that's _usually_ as simple
>>>>>>>>>>    as:
>>>>>>>>>>
>>>>>>>>>> 8<----------------------------------------------------------------------
>>>>>>>>>>    vbus = read(VBUS_STATE); /* could be a gpio_get_value() */
>>>>>>>>>>          id = read(ID_STATE); /* could be a gpio_get_value() */
>>>>>>>>>>
>>>>>>>>>>          set_role(id);
>>>>>>>>>>          set_vbus(vbus);
>>>>>>>>>> ------------------------------------------------------------------------
>>>>>>>>>>
>>>>>>>>> In fact, the individual driver can do it by itself. The chipidea driver
>>>>>>>>> handles OTG and dual-role well currently. By considering this OTG/DRD
>>>>>>>>> framework is worthwhile or not, we would like to see if it can
>>>>>>>>> simplify DRD design for each driver, and can benefit the platforms which
>>>>>>>>> has different drivers for host and peripheral to finish the role switch
>>>>>>>>> well.
>>>>>>>> simplify how?  By adding unnecessary workqueues and a level indirection
>>>>>>>> that just goes back to the same driver?
>>>>>>> What do you mean by same driver?
>>>>>> dwc3 registers to OTG layer. dwc3 also registers as UDC to UDC
>>>>>> layer. When dwc3 OTG IRQ fires, dwc3 tells OTG layer about it and OTG
>>>>>> layer jumps to a callback that goes back to dwc3 to e.g. start
>>>>>> peripheral side.
>>>>>>
>>>>>> See ?!? Starts on dwc3, goes to OTG layer, goes back to DWC3.
>>>>>>
>>>>>>> Gadget driver, host driver and PHY (or MUX) driver (for ID/VBUS) can
>>>>>>> be 3 totally independent drivers unlike dwc3 where you have a single
>>>>>>> driver in control of both host and gadget.
>>>>>> That's a totally different issue and one not being tackled by OTG
>>>>>> layer, because there are no such users yet. We can't design anything
>>>>>> based solely on speculation of what might happen.
>>>>>>
>>>>>> If there aren't enough users, there is no way to design a good generic
>>>>>> layer.
>>>>>>
>>>>>>> Questions not clear to me are:
>>>>>>>
>>>>>>> 1) Which driver handles ID/VBUS events and makes a decision to do the
>>>>>>> role swap?  Probably the PHY/MUX driver?
>>>>>> This is implementation dependent. For TI's USB subsystem, we have PMIC
>>>>>> sampling VBUS/ID that and using EXTCON to tell dwc3-omap to program UTMI
>>>>>> mailbox. The same mailbox can be used in HW-mode (see AM437x) where SW
>>>>>> has no intervention.
>>>>>>
>>>>>> For Intel's USB subsystem, we have PMIC sampling VBUS/ID with an
>>>>>> internal mux (much like TI's UTMI mailbox, but slightly different) to
>>>>>> switch between a separate XHCI or a separate dwc3. The same mux can be
>>>>>> put in HW-mode where SW has no intervention.
>>>>>>
>>>>>> In any case, for Intel's stuff most of the magic happens in ASL. Our PHY
>>>>>> driver just detects role (at least for Type-C based plats) and executes
>>>>>> _DSM with correct arguments [1]. _DSM will program internal MUX, toggle
>>>>>> VBUS and, for type-C, toggle VCONN when needed.
>>>>>>
>>>>>>> 2) How does it perform the role swap? Probably a register write to the
>>>>>>> PHY/MUX without needing to stop/start controllers? Easy case is both
>>>>>>> controllers can run in co-existence without interference. Is there any
>>>>>>> platform other than dwc3 where this is not the case?
>>>>>> Again speculation. But to answer your question, only dwc3 is in such a
>>>>>> case today. But even for dwc3 we can have DRD with a much, much simpler
>>>>>> setup as I have already explained.
>>>>>>
>>>>>>> 3) Even if host and gadget controllers can operate in coexistence,
>>>>>>> there is no need for both to be running for embedded applications
>>>>>>> which are usually power conservative.  How can we achieve that?
>>>>>> Now you're also speculating that you're running on embedded applications
>>>>>> and that we _can_ power off parts of the IP. I happen to know that we
>>>>>> can't power off XHCI part of dwc3 in TI's SoC because that's fed by same
>>>>>> Clocks and power rails as the peripheral side.
>>>>>>
>>>>>> [1] https://lkml.org/lkml/2016/6/21/658
>>>>>>
>>>>> For TI's case it is dwc3 and you are implementing the role swap in the dwc3
>>>>> driver where you do intend to remove the XHCI platform device. So I'm not
>>>>> much concerned about that.
>>>>>
>>>>> I was concerned about other platforms. I guess I'll let the other platform
>>>>> people speak up as to what they need.
>>>> I will talk about the msm platforms using dwc3 hardware.
>>>> DWC3 controller on msm doesn't seem to have full otg functionality,
>>>> and the driver makes use of switching between host and device
>>>> using PRTCAPDIR register in of the core [1].
>>>> test
>>>> We plan to support this DRD role switching (swapping host and device
>>>> functionality based on id/vbus interrupts) in upstream.
>>>>
>>>> Do we see a valid case to have this framework?
>>> Felipe wanted to have a minimal dual-role logic inside dwc3 which is
>>> independent of any DRD/OTG framework.
>>>
>>> I have implemented this and will send out patches today for review.
>> Okay, good to know that. I will be happy to take a look at the
>> patches and test them for msm.
> At least for now, I'm relying on the OTG controller to know about the VBUS and ID
> line state and switch controller roles between host and peripheral.
> i.e. I'm keeping the PRTCAPDIR register as OTG always.
>
> Does the msm SoC have the dwc3 OTG controller IP?

No, on msm dwc3 makes use of only DRD host and DRD device modes.
So the PRTCAPDIR will toggle between 0x1 and 0x2.

I was thinking of using extcon to report us the status of Vbus and ID.
And then the notifier can trigger a switch between host and peripheral 
modes.

>
>> Thanks for sharing the info.
>>
>>>> Or, may be add a 'drd' layer for dwc3 that handles
>>>> role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.
>>>>
>>>>
>>>> [1] https://source.codeaurora.org/quic/la/kernel/msm-3.18/tree/drivers/usb/dwc3/dwc3-msm.c?h=msm-3.18
>>>>       "dwc3_otg_start_host()"
>>>>       "dwc3_otg_start_peripheral()"
>>>>
>>>>
> --
> cheers,
> -roger

-- 
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 11:02               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-10 11:02 UTC (permalink / raw)
  To: Roger Quadros, Sergei Shtylyov, peter.chen
  Cc: tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto, jun.li,
	grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar, b-liu,
	linux-usb, linux-omap, linux-kernel, devicetree

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]


Hi,

Roger Quadros <rogerq@ti.com> writes:
>>> What is wrong with calling it gadget controller?
>> 
>>    It's not a controller, it's a piece of software AFAIU. Or is my English just too weak? :-)
>
> Everything at this point is a piece of software :).
>
> struct usb_gadget, represents the gadget controller device not the
> driver (or software).
>
> struct usb_gadget_driver represents the gadget function driver.
> struct usb_gadget_ops represents the UDC driver ops.

right, and usb_udc was added just to have a way of linking usb_gadget
with usb_gadget_driver so we could have more than one peripheral port in
a system.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 11:02               ` Felipe Balbi
  0 siblings, 0 replies; 172+ messages in thread
From: Felipe Balbi @ 2016-06-10 11:02 UTC (permalink / raw)
  To: Roger Quadros, Sergei Shtylyov, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w, jun.li-KZfg59tc24xl57MIdRCFDg,
	grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 681 bytes --]


Hi,

Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> writes:
>>> What is wrong with calling it gadget controller?
>> 
>>    It's not a controller, it's a piece of software AFAIU. Or is my English just too weak? :-)
>
> Everything at this point is a piece of software :).
>
> struct usb_gadget, represents the gadget controller device not the
> driver (or software).
>
> struct usb_gadget_driver represents the gadget function driver.
> struct usb_gadget_ops represents the UDC driver ops.

right, and usb_udc was added just to have a way of linking usb_gadget
with usb_gadget_driver so we could have more than one peripheral port in
a system.

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-10 10:44           ` Sergei Shtylyov
@ 2016-06-10 10:54             ` Roger Quadros
  -1 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 10:54 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

On 10/06/16 13:44, Sergei Shtylyov wrote:
> On 6/10/2016 1:19 PM, Roger Quadros wrote:
> 
>>>> It provides APIs for the following tasks
>>>>
>>>> - Registering an OTG/dual-role capable controller
>>>> - Registering Host and Gadget controllers to OTG core
>>>> - Providing inputs to and kicking the OTG state machine
>>>>
>>>> Provide a dual-role device (DRD) state machine.
>>>> 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>
>>>
>>
>> <snip>
>>
>>> [...]
>>>> +/**
>>>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>>>> + * @gadget:    gadget controller
>>>
>>>    We call that USB device controller (UDC). I'm not sure what you meant here...
>>>    And what about the 2nd arg, 'ops'?
>>
>> There are 2 data structures representing the Device controller.
>>
>> struct usb_gadget - represents a usb slave device
>> struct usb_udc -struct usb_udc - describes one usb device controller
>>
>> usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
>> as argument.
>>
>> Do you want me to refer to struct usb_gadget as UDC?
> 
>    No.
> 
>> What is wrong with calling it gadget controller?
> 
>    It's not a controller, it's a piece of software AFAIU. Or is my English just too weak? :-)

Everything at this point is a piece of software :).

struct usb_gadget, represents the gadget controller device not the driver (or software).

struct usb_gadget_driver represents the gadget function driver.
struct usb_gadget_ops represents the UDC driver ops.

--
cheers,
-roger

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 10:54             ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 10:54 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

On 10/06/16 13:44, Sergei Shtylyov wrote:
> On 6/10/2016 1:19 PM, Roger Quadros wrote:
> 
>>>> It provides APIs for the following tasks
>>>>
>>>> - Registering an OTG/dual-role capable controller
>>>> - Registering Host and Gadget controllers to OTG core
>>>> - Providing inputs to and kicking the OTG state machine
>>>>
>>>> Provide a dual-role device (DRD) state machine.
>>>> 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>
>>>
>>
>> <snip>
>>
>>> [...]
>>>> +/**
>>>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>>>> + * @gadget:    gadget controller
>>>
>>>    We call that USB device controller (UDC). I'm not sure what you meant here...
>>>    And what about the 2nd arg, 'ops'?
>>
>> There are 2 data structures representing the Device controller.
>>
>> struct usb_gadget - represents a usb slave device
>> struct usb_udc -struct usb_udc - describes one usb device controller
>>
>> usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
>> as argument.
>>
>> Do you want me to refer to struct usb_gadget as UDC?
> 
>    No.
> 
>> What is wrong with calling it gadget controller?
> 
>    It's not a controller, it's a piece of software AFAIU. Or is my English just too weak? :-)

Everything at this point is a piece of software :).

struct usb_gadget, represents the gadget controller device not the driver (or software).

struct usb_gadget_driver represents the gadget function driver.
struct usb_gadget_ops represents the UDC driver ops.

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 10:44           ` Sergei Shtylyov
  0 siblings, 0 replies; 172+ messages in thread
From: Sergei Shtylyov @ 2016-06-10 10:44 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

On 6/10/2016 1:19 PM, Roger Quadros wrote:

>>> It provides APIs for the following tasks
>>>
>>> - Registering an OTG/dual-role capable controller
>>> - Registering Host and Gadget controllers to OTG core
>>> - Providing inputs to and kicking the OTG state machine
>>>
>>> Provide a dual-role device (DRD) state machine.
>>> 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>
>>
>
> <snip>
>
>> [...]
>>> +/**
>>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>>> + * @gadget:    gadget controller
>>
>>    We call that USB device controller (UDC). I'm not sure what you meant here...
>>    And what about the 2nd arg, 'ops'?
>
> There are 2 data structures representing the Device controller.
>
> struct usb_gadget - represents a usb slave device
> struct usb_udc -struct usb_udc - describes one usb device controller
>
> usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
> as argument.
>
> Do you want me to refer to struct usb_gadget as UDC?

    No.

> What is wrong with calling it gadget controller?

    It's not a controller, it's a piece of software AFAIU. Or is my English 
just too weak? :-)

> --
> cheers,
> -roger

MBR, Sergei

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 10:44           ` Sergei Shtylyov
  0 siblings, 0 replies; 172+ messages in thread
From: Sergei Shtylyov @ 2016-06-10 10:44 UTC (permalink / raw)
  To: Roger Quadros, peter.chen-KZfg59tc24xl57MIdRCFDg
  Cc: balbi-DgEjT+Ai2ygdnm+yROfE0A, tony-4v6yS6AI5VpBDgjK7y7TUQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	mathias.nyman-VuQAYsv1563Yd54FQh9/CA,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w, jun.li-KZfg59tc24xl57MIdRCFDg,
	grygorii.strashko-l0cyMroinI0,
	yoshihiro.shimoda.uh-zM6kxYcvzFBBDgjK7y7TUQ,
	robh-DgEjT+Ai2ygdnm+yROfE0A, nsekhar-l0cyMroinI0,
	b-liu-l0cyMroinI0, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 6/10/2016 1:19 PM, Roger Quadros wrote:

>>> It provides APIs for the following tasks
>>>
>>> - Registering an OTG/dual-role capable controller
>>> - Registering Host and Gadget controllers to OTG core
>>> - Providing inputs to and kicking the OTG state machine
>>>
>>> Provide a dual-role device (DRD) state machine.
>>> 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-l0cyMroinI0@public.gmane.org>
>>
>
> <snip>
>
>> [...]
>>> +/**
>>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>>> + * @gadget:    gadget controller
>>
>>    We call that USB device controller (UDC). I'm not sure what you meant here...
>>    And what about the 2nd arg, 'ops'?
>
> There are 2 data structures representing the Device controller.
>
> struct usb_gadget - represents a usb slave device
> struct usb_udc -struct usb_udc - describes one usb device controller
>
> usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
> as argument.
>
> Do you want me to refer to struct usb_gadget as UDC?

    No.

> What is wrong with calling it gadget controller?

    It's not a controller, it's a piece of software AFAIU. Or is my English 
just too weak? :-)

> --
> cheers,
> -roger

MBR, Sergei

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

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-09 12:34     ` Sergei Shtylyov
@ 2016-06-10 10:19         ` Roger Quadros
  2016-06-10 10:19         ` Roger Quadros
  1 sibling, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 10:19 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

Hi,

On 09/06/16 15:34, Sergei Shtylyov wrote:
> On 6/9/2016 10:53 AM, Roger Quadros wrote:
> 
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
>>
>> Provide a dual-role device (DRD) state machine.
>> 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>
> 

<snip>

> [...]
>> +/**
>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>> + * @gadget:    gadget controller
> 
>    We call that USB device controller (UDC). I'm not sure what you meant here...
>    And what about the 2nd arg, 'ops'?

There are 2 data structures representing the Device controller.

struct usb_gadget - represents a usb slave device
struct usb_udc -struct usb_udc - describes one usb device controller

usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
as argument.

Do you want me to refer to struct usb_gadget as UDC?

What is wrong with calling it gadget controller?

--
cheers,
-roger

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10 10:19         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10 10:19 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

Hi,

On 09/06/16 15:34, Sergei Shtylyov wrote:
> On 6/9/2016 10:53 AM, Roger Quadros wrote:
> 
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
>>
>> Provide a dual-role device (DRD) state machine.
>> 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>
> 

<snip>

> [...]
>> +/**
>> + * usb_otg_register_gadget - Register the gadget controller to OTG core
>> + * @gadget:    gadget controller
> 
>    We call that USB device controller (UDC). I'm not sure what you meant here...
>    And what about the 2nd arg, 'ops'?

There are 2 data structures representing the Device controller.

struct usb_gadget - represents a usb slave device
struct usb_udc -struct usb_udc - describes one usb device controller

usb_udc is for private use only. usb_otg_register_gadget() takes struct usb_gadget
as argument.

Do you want me to refer to struct usb_gadget as UDC?

What is wrong with calling it gadget controller?

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-09 12:34     ` Sergei Shtylyov
@ 2016-06-10  7:04         ` Roger Quadros
  2016-06-10 10:19         ` Roger Quadros
  1 sibling, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10  7:04 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

Hi Sergei,

On 09/06/16 15:34, Sergei Shtylyov wrote:
> On 6/9/2016 10:53 AM, Roger Quadros wrote:
> 
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
>>
>> Provide a dual-role device (DRD) state machine.
>> 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>
> 
> [...]
> 
>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>> new file mode 100644
>> index 0000000..baebe5c
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.c
>> @@ -0,0 +1,833 @@
> [...]
>> +/**
>> + * Change USB protocol when there is a protocol change.
>> + * fsm->lock must be held.
>> + */
> 
>    If you're using the kernel-doc comment, please follow the rules.
> 

All your comments are valid and I'll fix the issues.

<snip>

> [...]
> 
>    Phew, that was a long patch... normally I don't review the patches that are such big. :-)

Thanks for the patience and review :)

--
cheers,
-roger

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-10  7:04         ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-10  7:04 UTC (permalink / raw)
  To: Sergei Shtylyov, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

Hi Sergei,

On 09/06/16 15:34, Sergei Shtylyov wrote:
> On 6/9/2016 10:53 AM, Roger Quadros wrote:
> 
>> It provides APIs for the following tasks
>>
>> - Registering an OTG/dual-role capable controller
>> - Registering Host and Gadget controllers to OTG core
>> - Providing inputs to and kicking the OTG state machine
>>
>> Provide a dual-role device (DRD) state machine.
>> 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>
> 
> [...]
> 
>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>> new file mode 100644
>> index 0000000..baebe5c
>> --- /dev/null
>> +++ b/drivers/usb/common/usb-otg.c
>> @@ -0,0 +1,833 @@
> [...]
>> +/**
>> + * Change USB protocol when there is a protocol change.
>> + * fsm->lock must be held.
>> + */
> 
>    If you're using the kernel-doc comment, please follow the rules.
> 

All your comments are valid and I'll fix the issues.

<snip>

> [...]
> 
>    Phew, that was a long patch... normally I don't review the patches that are such big. :-)

Thanks for the patience and review :)

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

* Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-09  7:53     ` Roger Quadros
  (?)
@ 2016-06-09 12:34     ` Sergei Shtylyov
  2016-06-10  7:04         ` Roger Quadros
  2016-06-10 10:19         ` Roger Quadros
  -1 siblings, 2 replies; 172+ messages in thread
From: Sergei Shtylyov @ 2016-06-09 12:34 UTC (permalink / raw)
  To: Roger Quadros, peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	jun.li, grygorii.strashko, yoshihiro.shimoda.uh, robh, nsekhar,
	b-liu, linux-usb, linux-omap, linux-kernel, devicetree

On 6/9/2016 10:53 AM, Roger Quadros wrote:

> It provides APIs for the following tasks
>
> - Registering an OTG/dual-role capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine
>
> Provide a dual-role device (DRD) state machine.
> 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>

[...]

> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> new file mode 100644
> index 0000000..baebe5c
> --- /dev/null
> +++ b/drivers/usb/common/usb-otg.c
> @@ -0,0 +1,833 @@
[...]
> +/**
> + * Change USB protocol when there is a protocol change.
> + * fsm->lock must be held.
> + */

    If you're using the kernel-doc comment, please follow the rules.

> +static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
[...]
> +/**
> + * Called when entering a DRD state.
> + * fsm->lock must be held.
> + */

    Same here.

> +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
[...]
> +/**
> + * 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
> + */

    And here.

> +/**
> + * Dual-role device (DRD) work function
> + */

    And here.

> +static void usb_drd_work(struct work_struct *work)
> +{
> +	struct usb_otg *otg = container_of(work, struct usb_otg, work);
> +
> +	pm_runtime_get_sync(otg->dev);
> +	while (drd_statemachine(otg))
> +	;

    Indent it more please.

[...]
> +/**
> + * start/kick the OTG FSM if we can
> + * fsm->lock must be held
> + */

    Please follow the kernel-doc rules.

[...]
> +/**
> + * stop the OTG FSM. Stops Host & Gadget controllers as well.
> + * fsm->lock must be held
> + */

    Likewise.

[...]
> +/**
> + * usb_otg_sync_inputs - Sync OTG inputs with the OTG state machine
> + * @fsm:	OTG FSM instance

    Doesn't match the prototype.

> + *
> + * 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 usb_otg *otg)
[...]
> +/**
> + * usb_otg_register_gadget - Register the gadget controller to OTG core
> + * @gadget:	gadget controller

    We call that USB device controller (UDC). I'm not sure what you meant here...
    And what about the 2nd arg, 'ops'?

[...]
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index 85b8fb5..5d4850a 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -10,10 +10,68 @@
>  #define __LINUX_USB_OTG_H
>
>  #include <linux/phy/phy.h>
> -#include <linux/usb/phy.h>
> -#include <linux/usb/otg-fsm.h>
> +#include <linux/device.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

    IRQ?

> + * @ops: otg to host controller interface
> + * @ops: otg to host controller interface

    Once is enough. :-)

> + * @otg_dev: otg controller device

    OTG?

> +/**
> + * struct usb_otg - usb otg controller state
> + *
> + * @default_a: Indicates we are an A device. i.e. Host.
> + * @phy: USB phy interface

    PHY?

> + * @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

    OTG?

> + * @hcd_ops: host controller interface
> + * ------- internal use only -------
> + * @primary_hcd: primary host state and interface
> + * @shared_hcd: shared host state and interface
> + * @gadget_ops: gadget controller interface
> + * @list: list of otg controllers
> + * @work: otg state machine work
> + * @wq: otg state machine work queue
> + * @flags: to track if host/gadget is running
> + */
>  struct usb_otg {
>  	u8			default_a;
>
[...]
> @@ -42,26 +116,101 @@ struct usb_otg {
>
>  	/* start or continue HNP role switch */
>  	int	(*start_hnp)(struct usb_otg *otg);
> -
> +/*---------------------------------------------------------------*/
>  };
>
>  /**
> - * struct usb_otg_caps - describes the otg capabilities of the device
> - * @otg_rev: The OTG revision number the device is compliant with, it's
> - *		in binary-coded decimal (i.e. 2.0 is 0200H).
> - * @hnp_support: Indicates if the device supports HNP.
> - * @srp_support: Indicates if the device supports SRP.
> - * @adp_support: Indicates if the device supports ADP.
> + * struct usb_otg_config - otg controller configuration
> + * @caps: otg capabilities of the controller
> + * @ops: otg fsm operations

    OTG FSM?

> + * @otg_work: optional custom otg state machine work function

    OTG?

>   */

[...]

    Phew, that was a long patch... normally I don't review the patches that 
are such big. :-)

MBR, Sergei

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

* [PATCH v10 08/14] usb: otg: add OTG/dual-role core
  2016-06-08  9:03 ` [PATCH v9 08/14] usb: otg: add OTG/dual-role core Roger Quadros
@ 2016-06-09  7:53     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-09  7:53 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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>
---
v10:
- added missing mutex_unlock in in failure path in usb_otg_unregister()
- removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h

 drivers/usb/Kconfig          |  18 +
 drivers/usb/Makefile         |   1 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 833 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 181 +++++++++-
 10 files changed, 1034 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca7856..03f7204 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= common/
+obj-$(CONFIG_USB_OTG_CORE)	+= common/
 
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..baebe5c
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,833 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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 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 *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+
+		/* start host */
+		hcd_ops->add(otg->primary_hcd.hcd, otg->primary_hcd.irqnum,
+			     otg->primary_hcd.irqflags);
+		if (otg->shared_hcd.hcd) {
+			hcd_ops->add(otg->shared_hcd.hcd,
+				     otg->shared_hcd.irqnum,
+				     otg->shared_hcd.irqflags);
+		}
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->start(otg->gadget);
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->stop(otg->gadget);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * Change USB protocol when there is a protocol change.
+ * fsm->lock must be held.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Called when entering a DRD state.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * 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
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * Dual-role device (DRD) work function
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+	;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() if error.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	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 usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * stop the OTG FSM. Stops Host & Gadget controllers as well.
+ * fsm->lock must be held
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm - Kick the OTG state machine
+ * @otg_dev:	OTG 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 *otg_dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(otg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd - Register the host controller to OTG core
+ * @hcd:	host controller device
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget - Register the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget - Unregister the 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 halted
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->fsm.lock);
+
+	dev_info(otg_dev, "otg: gadget %s unregistered\n",
+		 dev_name(&gadget->dev));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
+
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 2057add..9d55384 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 51e3bde..1237f66 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -583,6 +583,7 @@ struct usb_gadget_ops {
  * @out_epnum: last used out ep number
  * @in_epnum: last used in ep number
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -639,6 +640,7 @@ struct usb_gadget {
 	unsigned			out_epnum;
 	unsigned			in_epnum;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..5d4850a 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,68 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @ops: otg to host controller interface
+ * @otg_dev: otg controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of otg controllers
+ * @work: otg state machine work
+ * @wq: otg state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +82,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +116,101 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - otg controller configuration
+ * @caps: otg capabilities of the controller
+ * @ops: otg fsm operations
+ * @otg_work: optional custom otg state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_kick_fsm(struct device *otg_dev);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +262,8 @@ 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);
 
@@ -237,4 +388,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

* [PATCH v10 08/14] usb: otg: add OTG/dual-role core
@ 2016-06-09  7:53     ` Roger Quadros
  0 siblings, 0 replies; 172+ messages in thread
From: Roger Quadros @ 2016-06-09  7:53 UTC (permalink / raw)
  To: peter.chen
  Cc: balbi, tony, gregkh, dan.j.williams, mathias.nyman, Joao.Pinto,
	sergei.shtylyov, jun.li, grygorii.strashko, yoshihiro.shimoda.uh,
	robh, nsekhar, b-liu, linux-usb, linux-omap, linux-kernel,
	devicetree, rogerq

It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
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>
---
v10:
- added missing mutex_unlock in in failure path in usb_otg_unregister()
- removed unnecessary hrtimer.h and ktime.h in linux/usb/otg.h

 drivers/usb/Kconfig          |  18 +
 drivers/usb/Makefile         |   1 +
 drivers/usb/common/Makefile  |   6 +-
 drivers/usb/common/usb-otg.c | 833 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/Kconfig     |  14 -
 drivers/usb/gadget/Kconfig   |   1 +
 include/linux/usb/gadget.h   |   2 +
 include/linux/usb/hcd.h      |   1 +
 include/linux/usb/otg-fsm.h  |   7 +
 include/linux/usb/otg.h      | 181 +++++++++-
 10 files changed, 1034 insertions(+), 30 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8689dcb..ed596ec 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
+config USB_OTG_CORE
+	tristate
+
+config USB_OTG
+	bool "OTG/Dual-role support"
+	depends on PM && USB && USB_GADGET
+	default n
+	---help---
+	  The most notable feature of USB OTG is support for a
+	  "Dual-Role" device, which can act as either a device
+	  or a host. The initial role is decided by the type of
+	  plug inserted and can be changed later when two dual
+	  role devices talk to each other.
+
+	  Select this only if your board has Mini-AB/Micro-AB
+	  connector.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
@@ -40,6 +57,7 @@ config USB
 	tristate "Support for Host-side USB"
 	depends on USB_ARCH_HAS_HCD
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS  # for UTF-8 strings
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca7856..03f7204 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= common/
+obj-$(CONFIG_USB_OTG_CORE)	+= common/
 
 obj-$(CONFIG_USBIP_CORE)	+= usbip/
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..5122b3f 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,7 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
-obj-$(CONFIG_USB_OTG)	+= usbotg.o
+ifeq ($(CONFIG_USB_OTG),y)
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
+obj-$(CONFIG_USB_OTG_CORE)	+= usbotg.o
+endif
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..baebe5c
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,833 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 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/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_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 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 *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+
+		/* start host */
+		hcd_ops->add(otg->primary_hcd.hcd, otg->primary_hcd.irqnum,
+			     otg->primary_hcd.irqflags);
+		if (otg->shared_hcd.hcd) {
+			hcd_ops->add(otg->shared_hcd.hcd,
+				     otg->shared_hcd.irqnum,
+				     otg->shared_hcd.irqflags);
+		}
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->start(otg->gadget);
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->stop(otg->gadget);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * Change USB protocol when there is a protocol change.
+ * fsm->lock must be held.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->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(otg, 0);
+		} else if (fsm->protocol == PROTO_GADGET) {
+			otg->gadget_ops->connect_control(otg->gadget, false);
+			ret = otg_start_gadget(otg, 0);
+		}
+
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST) {
+			ret = otg_start_host(otg, 1);
+		} else if (protocol == PROTO_GADGET) {
+			ret = otg_start_gadget(otg, 1);
+			otg->gadget_ops->connect_control(otg->gadget, true);
+		}
+
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Called when entering a DRD state.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->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);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * 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
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = 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;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * Dual-role device (DRD) work function
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	while (drd_statemachine(otg))
+	;
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() if error.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	/* otg->caps is controller caps + DT overrides */
+	otg->caps = *config->otg_caps;
+	ret = of_usb_update_otg_caps(dev->of_node, &otg->caps);
+	if (ret)
+		goto err_wq;
+
+	if ((otg->caps.hnp_support || otg->caps.srp_support ||
+	     otg->caps.adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_freezable_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	return otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role 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 *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		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 (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	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 usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget UDC registers\n");
+		return;
+	}
+
+	if (!otg->gadget_ready) {
+		dev_info(otg->dev,
+			 "otg: can't start till gadget function registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * stop the OTG FSM. Stops Host & Gadget controllers as well.
+ * fsm->lock must be held
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST) {
+		otg_start_host(otg, 0);
+	} else if (fsm->protocol == PROTO_GADGET) {
+		otg->gadget_ops->connect_control(otg->gadget, false);
+		otg_start_gadget(otg, 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 usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm - Kick the OTG state machine
+ * @otg_dev:	OTG 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 *otg_dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(otg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd - Register the host controller to OTG core
+ * @hcd:	host controller device
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with 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.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * 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 *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->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 == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->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;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->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 (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		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(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd - Unregister the 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 *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(hcd_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget - Register the 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 *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_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);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered, deferring.\n");
+		return -EPROBE_DEFER;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* FSM will be started in usb_otg_gadget_ready() */
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget - Unregister the 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 halted
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* FSM must be stopped in usb_otg_gadget_ready() */
+	if (otg->gadget_ready) {
+		dev_err(otg_dev,
+			"otg: gadget %s unregistered before being unready, forcing stop\n",
+			dev_name(&gadget->dev));
+		usb_otg_stop_fsm(otg);
+	}
+
+	otg->gadget = NULL;
+	mutex_unlock(&otg->fsm.lock);
+
+	dev_info(otg_dev, "otg: gadget %s unregistered\n",
+		 dev_name(&gadget->dev));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
+
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_err(gadget_dev,
+			"otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		mutex_unlock(&otg->fsm.lock);
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		return -EINVAL;
+	}
+
+	/* Start/stop FSM & gadget */
+	otg->gadget_ready = ready;
+	if (ready)
+		usb_otg_start_fsm(otg);
+	else
+		usb_otg_stop_fsm(otg);
+
+	dev_dbg(otg_dev, "otg: gadget %s %sready\n", dev_name(&gadget->dev),
+		ready ? "" : "not ");
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..37f8c54 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -41,20 +41,6 @@ config USB_DYNAMIC_MINORS
 
 	  If you are unsure about this, say N here.
 
-config USB_OTG
-	bool "OTG support"
-	depends on PM
-	default n
-	help
-	  The most notable feature of USB OTG is support for a
-	  "Dual-Role" device, which can act as either a device
-	  or a host. The initial role is decided by the type of
-	  plug inserted and can be changed later when two dual
-	  role devices talk to each other.
-
-	  Select this only if your board has Mini-AB/Micro-AB
-	  connector.
-
 config USB_OTG_WHITELIST
 	bool "Rely on OTG and EH Targeted Peripherals List"
 	depends on USB
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 2057add..9d55384 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -16,6 +16,7 @@
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
 	select USB_COMMON
+	select USB_OTG_CORE
 	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 51e3bde..1237f66 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -583,6 +583,7 @@ struct usb_gadget_ops {
  * @out_epnum: last used out ep number
  * @in_epnum: last used in ep number
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -639,6 +640,7 @@ struct usb_gadget {
 	unsigned			out_epnum;
 	unsigned			in_epnum;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 7729c1f..36bd54f 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -185,6 +185,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,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
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * 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
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..5d4850a 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,68 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.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
+ * @ops: otg to host controller interface
+ * @otg_dev: otg controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *		in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+	u16 otg_rev;
+	bool hnp_support;
+	bool srp_support;
+	bool adp_support;
+};
 
+/**
+ * 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
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of otg controllers
+ * @work: otg state machine work
+ * @wq: otg state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +82,25 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps	caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	bool gadget_ready;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* 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);
 
@@ -42,26 +116,101 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
- * struct usb_otg_caps - describes the otg capabilities of the device
- * @otg_rev: The OTG revision number the device is compliant with, it's
- *		in binary-coded decimal (i.e. 2.0 is 0200H).
- * @hnp_support: Indicates if the device supports HNP.
- * @srp_support: Indicates if the device supports SRP.
- * @adp_support: Indicates if the device supports ADP.
+ * struct usb_otg_config - otg controller configuration
+ * @caps: otg capabilities of the controller
+ * @ops: otg fsm operations
+ * @otg_work: optional custom otg state machine work function
  */
-struct usb_otg_caps {
-	u16 otg_rev;
-	bool hnp_support;
-	bool srp_support;
-	bool adp_support;
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
 };
 
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *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 usb_otg *otg);
+int usb_otg_kick_fsm(struct device *otg_dev);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *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 usb_otg *otg)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_gadget_ready(struct usb_gadget *gadget, bool ready)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +262,8 @@ 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);
 
@@ -237,4 +388,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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

end of thread, other threads:[~2017-01-20 11:40 UTC | newest]

Thread overview: 172+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-10 13:07 [PATCH v10 00/14] USB OTG/dual-role framework Roger Quadros
2016-06-10 13:07 ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0 Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:16   ` Roger Quadros
2016-06-14  8:16     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 02/14] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:17   ` Roger Quadros
2016-06-14  8:17     ` Roger Quadros
2016-06-14 14:21     ` Alan Stern
2016-06-14 14:21       ` Alan Stern
2016-06-15  7:14       ` Roger Quadros
2016-06-15  7:14         ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 04/14] usb: otg-fsm: use usb_otg wherever possible Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12  9:13   ` Peter Chen
2016-06-20  7:21   ` Felipe Balbi
2016-06-20  7:21     ` Felipe Balbi
2016-06-20  7:28     ` Roger Quadros
2016-06-20  7:28       ` Roger Quadros
2016-06-20  8:13       ` Felipe Balbi
2016-06-20  8:13         ` Felipe Balbi
2016-06-20  8:25         ` Roger Quadros
2016-06-20  8:25           ` Roger Quadros
2016-06-20  9:24           ` Felipe Balbi
2016-06-20  9:24             ` Felipe Balbi
2016-06-20  9:43             ` Roger Quadros
2016-06-20  9:43               ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 08/14] usb: otg: add OTG/dual-role core Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12 11:21   ` Peter Chen
2016-06-12 11:21     ` Peter Chen
2016-06-13  7:42     ` Roger Quadros
2016-06-13  7:42       ` Roger Quadros
2016-06-13  7:56   ` [PATCH v11 " Roger Quadros
2016-06-13  7:56     ` Roger Quadros
2016-06-13  7:58     ` Peter Chen
2016-06-20  7:45     ` Felipe Balbi
2016-06-20  7:45       ` Felipe Balbi
2016-06-20 10:13       ` Roger Quadros
2016-06-20 10:13         ` Roger Quadros
2016-06-20 12:03         ` Felipe Balbi
2016-06-20 12:26           ` Roger Quadros
2016-06-20 12:26             ` Roger Quadros
2016-06-20 12:46             ` Felipe Balbi
2016-06-21  6:39           ` Peter Chen
2016-06-21  7:19             ` Felipe Balbi
2016-06-21  7:19               ` Felipe Balbi
2016-06-21  8:02               ` Peter Chen
2016-06-21  8:18                 ` Felipe Balbi
2016-06-21  8:18                   ` Felipe Balbi
2016-06-21  9:14                   ` Peter Chen
2016-06-21  9:14                     ` Peter Chen
2016-06-21 12:35                     ` Felipe Balbi
2016-06-21 12:35                       ` Felipe Balbi
2016-06-21 13:12                       ` Peter Chen
2016-06-21 14:47                         ` Felipe Balbi
2016-06-22  3:33                           ` Peter Chen
2016-06-22  3:33                             ` Peter Chen
2016-06-22  6:51                             ` Felipe Balbi
2016-06-22  6:51                               ` Felipe Balbi
2016-06-22  7:30                               ` Peter Chen
2016-06-22  7:30                                 ` Peter Chen
2016-06-22  8:00                                 ` Felipe Balbi
2016-06-22  8:00                                   ` Felipe Balbi
2016-06-23  7:41                             ` Yoshihiro Shimoda
2016-06-23  7:41                               ` Yoshihiro Shimoda
2016-06-21  2:30         ` Yoshihiro Shimoda
2016-06-21  2:30           ` Yoshihiro Shimoda
2016-06-21  7:21           ` Felipe Balbi
2016-06-21  7:21             ` Felipe Balbi
2016-06-20 11:49       ` Peter Chen
2016-06-20 11:49         ` Peter Chen
2016-06-20 12:08         ` Felipe Balbi
2016-06-20 12:08           ` Felipe Balbi
2016-06-21  6:05           ` Peter Chen
2016-06-21  7:26             ` Felipe Balbi
2016-06-21  7:26               ` Felipe Balbi
2016-06-21  9:07               ` Peter Chen
2016-06-21  9:07                 ` Peter Chen
2016-06-21 10:02                 ` Felipe Balbi
2016-06-21 10:43                   ` Tony Lindgren
2016-06-21 10:43                     ` Tony Lindgren
2016-06-21 10:56                     ` Felipe Balbi
2016-06-21 13:05                   ` Peter Chen
2016-06-21 13:05                     ` Peter Chen
2016-06-22  6:56                     ` Felipe Balbi
2016-06-22  6:56                       ` Felipe Balbi
2016-06-22  7:33                       ` Peter Chen
2016-06-22  8:03                         ` Felipe Balbi
2016-06-22  7:49                       ` Roger Quadros
2016-06-22  7:49                         ` Roger Quadros
2016-06-22  8:14                         ` Felipe Balbi
2016-06-22  8:30                           ` Roger Quadros
2016-06-22  8:30                             ` Roger Quadros
2017-01-19 11:56                             ` Vivek Gautam
2017-01-19 12:15                               ` Roger Quadros
2017-01-19 12:15                                 ` Roger Quadros
2017-01-19 15:15                                 ` vivek.gautam
2017-01-20  8:30                                   ` Roger Quadros
2017-01-20  8:30                                     ` Roger Quadros
2017-01-20 11:39                                     ` Vivek Gautam
2016-06-23  7:42                         ` Yoshihiro Shimoda
2016-06-23  7:42                           ` Yoshihiro Shimoda
2016-06-10 13:07 ` [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-13  8:13   ` Jun Li
2016-06-13  8:13     ` Jun Li
2016-06-13  8:16     ` Roger Quadros
2016-06-13  8:16       ` Roger Quadros
2016-06-13  8:23   ` [PATCH v11 " Roger Quadros
2016-06-13  8:23     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 10/14] usb: otg: add hcd companion support Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 11/14] usb: otg: use dev_vdbg() instead of VDBG() Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 12/14] usb: hcd: Adapt to OTG core Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:17   ` Roger Quadros
2016-06-14  8:17     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 13/14] usb: gadget: udc: adapt " Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12 11:36   ` Peter Chen
2016-06-12 11:36     ` Peter Chen
2016-06-13  7:14     ` Roger Quadros
2016-06-13  7:14       ` Roger Quadros
2016-06-13  7:20       ` Peter Chen
2016-06-13  7:20         ` Peter Chen
2016-06-13  7:37         ` Roger Quadros
2016-06-13  7:37           ` Roger Quadros
2016-06-13  7:40           ` Peter Chen
2016-06-13  7:40             ` Peter Chen
2016-06-13  7:55   ` [PATCH v11 " Roger Quadros
2016-06-13  7:55     ` Roger Quadros
2016-06-13  7:56     ` Peter Chen
2016-06-13  8:06       ` Roger Quadros
2016-06-13  8:06         ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:18   ` Roger Quadros
2016-06-14  8:18     ` Roger Quadros
2016-06-14  2:17 ` [PATCH v10 00/14] USB OTG/dual-role framework Peter Chen
2016-06-14  8:12   ` Roger Quadros
2016-06-14  8:12     ` Roger Quadros
2016-06-16 11:07 ` Roger Quadros
2016-06-16 11:07   ` Roger Quadros
2016-06-17  7:17   ` Felipe Balbi
2016-06-17  7:17     ` Felipe Balbi
2016-06-17  7:31     ` Roger Quadros
2016-06-17  7:31       ` Roger Quadros
  -- strict thread matches above, loose matches on Subject: below --
2016-06-08  9:03 [PATCH v9 " Roger Quadros
2016-06-08  9:03 ` [PATCH v9 08/14] usb: otg: add OTG/dual-role core Roger Quadros
2016-06-09  7:53   ` [PATCH v10 " Roger Quadros
2016-06-09  7:53     ` Roger Quadros
2016-06-09 12:34     ` Sergei Shtylyov
2016-06-10  7:04       ` Roger Quadros
2016-06-10  7:04         ` Roger Quadros
2016-06-10 10:19       ` Roger Quadros
2016-06-10 10:19         ` Roger Quadros
2016-06-10 10:44         ` Sergei Shtylyov
2016-06-10 10:44           ` Sergei Shtylyov
2016-06-10 10:54           ` Roger Quadros
2016-06-10 10:54             ` Roger Quadros
2016-06-10 11:02             ` Felipe Balbi
2016-06-10 11:02               ` Felipe Balbi

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