Skip to contentSkip to conversation

USB OTG/dual-role framework

PATCH In review Roger Quadros 8 participants 89 messages Jun 10, 2016 – Jan 20, 2017

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

v10 cover USB OTG/dual-role framework

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
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#1 lore raw

PATCH v10 1/14 usb: hcd: Initialize hcd->flags to 0

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
---
 drivers/usb/core/hcd.c | 1 +
 1 file changed, 1 insertion(+)
drivers/usb/core/hcd.c +1 -0
index 34b837a..ae6c76d 100644
@@ -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);
 
Signature · 1 line
2.7.4
#2 lore raw

Re: [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0

+Alan,

Quoted 113 lines · 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
---
 drivers/usb/core/hcd.c | 1 +
 1 file changed, 1 insertion(+)
drivers/usb/core/hcd.c +0 -0
index 34b837a..ae6c76d 100644

drivers/usb/core/hcd.c void usb_remove_hcd(struct usb_hcd *hcd) · line 3027

Quoted 7 lines
drivers/usb/core/hcd.c +1 -0
@@ -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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

PATCH v10 2/14 usb: otg-fsm: Prevent build warning "VDBG" redefined

In reply to 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

---
 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(-)
drivers/usb/common/usb-otg-fsm.c +7 -0
index 9059b7d..199dee0 100644
@@ -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)
 {
drivers/usb/phy/phy-fsl-usb.c +7 -0
index 94eb292..a8784ec 100644
@@ -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"
include/linux/usb/otg-fsm.h +0 -15
index 7a03505..a0a8f87 100644
@@ -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)
Signature · 1 line
2.7.4
#4 lore raw

PATCH v10 3/14 usb: hcd.h: Add OTG to HCD interface

In reply to 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.

---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/usb/hcd.h +24 -0
index 66fc137..7729c1f 100644
@@ -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;
Signature · 1 line
2.7.4
#5 lore raw

Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface

+Alan

Quoted 50 lines · 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.

---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/usb/hcd.h +24 -0
index 66fc137..7729c1f 100644
@@ -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;
Acked-by
#6 lore raw

Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface

Quoted 23 lines · Roger Quadros

+Alan

Quoted 20 lines · 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.

---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/usb/hcd.h +0 -0
index 66fc137..7729c1f 100644
@@ -400,6 +400,30 @@ struct hc_driver {
 
Quoted 6 lines

include/linux/usb/hcd.h struct hc_driver { · line 406

Quoted 6 lines
include/linux/usb/hcd.h +4 -0
 };
 
+/**
+ * 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:

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#7 lore raw

Re: [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface

Quoted 25 lines · Alan Stern
Quoted 23 lines · Roger Quadros

+Alan

Quoted 20 lines · 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.

---
 include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/linux/usb/hcd.h +0 -0
index 66fc137..7729c1f 100644
@@ -400,6 +400,30 @@ struct hc_driver {
 
Quoted 8 lines
Quoted 6 lines

include/linux/usb/hcd.h struct hc_driver { · line 406

Quoted 6 lines
include/linux/usb/hcd.h +4 -0
 };
 
+/**
+ * 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.

Quoted 5 lines

Otherwise, for patches 1, 3, and 12:

Thanks.

cheers,
-roger

#8 lore raw

PATCH v10 4/14 usb: otg-fsm: use usb_otg wherever possible

In reply to Roger Quadros

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

---
 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(-)
drivers/usb/chipidea/ci.h +0 -1
index cd41455..c523975 100644
@@ -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;
drivers/usb/chipidea/core.c +7 -7
index 69426e6..56b6ac6 100644
@@ -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);
 	}
drivers/usb/chipidea/debug.c +1 -1
index 6d23eed..374cdaa 100644
@@ -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",
drivers/usb/chipidea/otg_fsm.c +84 -85

427 lines not on this page · raw message

drivers/usb/chipidea/udc.c +9 -8
index 065f5d9..7a6b0b5 100644
@@ -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);
 }
 
 /**
drivers/usb/common/usb-otg-fsm.c +93 -87

369 lines not on this page · raw message

drivers/usb/phy/phy-fsl-usb.c +67 -74

391 lines not on this page · raw message

drivers/usb/phy/phy-fsl-usb.h +1 -2
index 2314995..e207cfb 100644
@@ -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;
 
include/linux/usb/otg-fsm.h +14 -118

147 lines not on this page · raw message

include/linux/usb/otg.h +107 -0

123 lines not on this page · raw message

Signature · 1 line
2.7.4
#9 lore raw

PATCH v10 5/14 usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

In reply to Roger Quadros

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

---
 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(-)
drivers/usb/chipidea/otg_fsm.c +7 -0
index 1c0c750..2d8d659 100644
@@ -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)
drivers/usb/common/usb-otg-fsm.c +11 -4
index 610b5bd6..482d4c9 100644
@@ -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:
drivers/usb/phy/phy-fsl-usb.c +7 -0
index 3ffa4c6..011d36e 100644
@@ -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;
include/linux/usb/otg.h +2 -0
index e8a14dc..85b8fb5 100644
@@ -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);
Signature · 1 line
2.7.4
#10 lore raw

PATCH v10 6/14 usb: gadget.h: Add OTG to gadget interface

In reply to 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +16 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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);
+};
 
 /*-------------------------------------------------------------------------*/
 
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Acked-by on v10 6/14
#11 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Quoted 9 lines · 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.

Quoted 38 lines
---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +16 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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);
+};
 
 /*-------------------------------------------------------------------------*/
 
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best Regards,
Peter Chen
#12 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

In reply to Roger Quadros

Hi,

Quoted 27 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +6 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 10 lines
include/linux/usb/gadget.h +10 -0
+ *
+ * @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()

Signature · 1 line
balbi
#13 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Quoted 36 lines · Felipe Balbi

Hi,

Quoted 32 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +11 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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
+ */
Quoted 9 lines

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 5 lines
include/linux/usb/gadget.h +5 -0
+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

#14 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Hi,

Quoted 48 lines · Roger Quadros

[ Unknown signature status ]

Quoted 36 lines · Felipe Balbi

Hi,

Quoted 32 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +11 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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
+ */
Quoted 9 lines

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 5 lines
include/linux/usb/gadget.h +5 -0
+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()

Quoted 2 lines

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.

Signature · 1 line
balbi
#15 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Quoted 52 lines · Felipe Balbi

Hi,

Quoted 48 lines · Roger Quadros

[ Unknown signature status ]

Quoted 45 lines · Felipe Balbi

Hi,

Quoted 27 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +6 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 10 lines
include/linux/usb/gadget.h +10 -0
+ *
+ * @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()

Quoted 6 lines
Quoted 2 lines

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

#16 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Hi,

Quoted 50 lines · Roger Quadros
Quoted 43 lines
Quoted 43 lines
Quoted 42 lines
Quoted 27 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +6 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 10 lines
include/linux/usb/gadget.h +10 -0
+ *
+ * @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()

Quoted 6 lines
Quoted 2 lines

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.

Quoted 5 lines

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.

Signature · 1 line
balbi
#17 lore raw

Re: [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface

Quoted 57 lines · Felipe Balbi

Hi,

Quoted 53 lines · Roger Quadros
Quoted 43 lines
Quoted 43 lines
Quoted 42 lines
Quoted 27 lines · 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.

---
 include/linux/usb/gadget.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/linux/usb/gadget.h +6 -0
index 2dd9e6b..f4fc0aa 100644
@@ -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

include/linux/usb/gadget.h struct usb_gadget_driver { · line 657

Quoted 10 lines
include/linux/usb/gadget.h +10 -0
+ *
+ * @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()

Quoted 6 lines
Quoted 2 lines

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

Quoted 7 lines
Quoted 2 lines

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

#18 lore raw

PATCH v10 7/14 usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG

In reply to 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.

---
 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(-)
Documentation/usb/chipidea.txt +1 -1
index edf7cdf..580d157 100644
@@ -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:
drivers/usb/chipidea/Makefile +1 -1
index 518e445..45aa24d 100644
@@ -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
 
drivers/usb/chipidea/ci.h +1 -1
index c523975..1a32b8c 100644
@@ -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] &&
drivers/usb/chipidea/otg_fsm.h +1 -1
index 6366fe3..2d451bb 100644
@@ -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);
drivers/usb/common/Makefile +2 -1
index 6bbb3ec..f8f2c88 100644
@@ -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
drivers/usb/core/Kconfig +0 -8
index dd28010..ae228d0 100644
@@ -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
drivers/usb/phy/Kconfig +1 -1
index ca50944..66a79d3 100644
@@ -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.
Signature · 1 line
2.7.4
#19 lore raw

PATCH v10 8/14 usb: otg: add OTG/dual-role core

In reply to 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'.

---
 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
drivers/usb/Kconfig +18 -0
index 8689dcb..ed596ec 100644
@@ -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
drivers/usb/Makefile +1 -0
index dca7856..03f7204 100644
@@ -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/
drivers/usb/common/Makefile +4 -2
index f8f2c88..5122b3f 100644
@@ -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
drivers/usb/common/usb-otg.c new file +906 -0

906 lines not on this page · raw message

drivers/usb/core/Kconfig +0 -14
index ae228d0..37f8c54 100644
@@ -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
drivers/usb/gadget/Kconfig +1 -0
index 3c3f31c..5fc9095 100644
@@ -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
include/linux/usb/gadget.h +2 -0
index f4fc0aa..1d74fb8 100644
@@ -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;
include/linux/usb/hcd.h +1 -0
index 7729c1f..36bd54f 100644
@@ -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
include/linux/usb/otg-fsm.h +7 -0
index 26e6531..943714a 100644
@@ -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 */
include/linux/usb/otg.h +166 -14

221 lines not on this page · raw message

Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#20 lore raw

Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core

drivers/usb/Makefile obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ · line 62

Quoted 8 lines · Roger Quadros

index dca7856..03f7204 100644

drivers/usb/Makefile +1 -0
@@ -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?

drivers/usb/Makefile obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/

Quoted 3 lines
drivers/usb/Makefile +3 -0
+
+/**
+ * usb_otg_get_data() - get usb_otg data structa

%s/structa/structure

Quoted 19 lines
drivers/usb/Makefile +19 -0
+
+/**
+ * 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) {

drivers/usb/Makefile

Quoted 10 lines
drivers/usb/Makefile +10 -0
+		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.

drivers/usb/Makefile

Quoted 11 lines
drivers/usb/Makefile +11 -0
+
+/**
+ * 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

drivers/usb/Makefile

Quoted 10 lines
drivers/usb/Makefile +10 -0
+
+/**
+ * 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

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#21 lore raw

Re: [PATCH v10 08/14] usb: otg: add OTG/dual-role core

Quoted 11 lines · Peter Chen

drivers/usb/Makefile obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ · line 62

Quoted 8 lines · Roger Quadros

index dca7856..03f7204 100644

drivers/usb/Makefile +1 -0
@@ -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.

Quoted 6 lines

drivers/usb/Makefile obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/

Quoted 4 lines
drivers/usb/Makefile +3 -0
+
+/**
+ * usb_otg_get_data() - get usb_otg data structa

%s/structa/structure

OK.

Quoted 25 lines
Quoted 25 lines
drivers/usb/Makefile +24 -0
+
+/**
+ * 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;
+	}
+
Quoted 8 lines

drivers/usb/Makefile

Quoted 5 lines
drivers/usb/Makefile +5 -0
+	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.

Quoted 15 lines

drivers/usb/Makefile

Quoted 12 lines
drivers/usb/Makefile +11 -0
+
+/**
+ * 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

Quoted 13 lines

drivers/usb/Makefile

Quoted 10 lines
drivers/usb/Makefile +10 -0
+
+/**
+ * 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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#22 lore raw

PATCH v11 8/14 usb: otg: add OTG/dual-role core

In reply to 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'.

---
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
drivers/usb/Kconfig +18 -0
index 8689dcb..ed596ec 100644
@@ -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
drivers/usb/common/Makefile +4 -2
index f8f2c88..5122b3f 100644
@@ -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
drivers/usb/common/usb-otg.c new file +877 -0

877 lines not on this page · raw message

drivers/usb/core/Kconfig +0 -14
index ae228d0..37f8c54 100644
@@ -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
drivers/usb/gadget/Kconfig +1 -0
index 3c3f31c..5fc9095 100644
@@ -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
include/linux/usb/gadget.h +2 -0
index f4fc0aa..1d74fb8 100644
@@ -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;
include/linux/usb/hcd.h +1 -0
index 7729c1f..36bd54f 100644
@@ -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
include/linux/usb/otg-fsm.h +7 -0
index 26e6531..943714a 100644
@@ -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 */
include/linux/usb/otg.h +160 -14

215 lines not on this page · raw message

Signature · 7 lines
2.7.4


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Acked-by on v11 8/14
#23 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 21 lines · 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'.

Quoted 6 lines

---
v11:
- remove usb_otg_kick_fsm().
- typo fixes: structa/structure, upto/up to.
- remove "obj-$(CONFIG_USB_OTG_CORE) += common/" from Makefile.

Quoted 1,279 lines
 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
drivers/usb/Kconfig +18 -0
index 8689dcb..ed596ec 100644
@@ -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
drivers/usb/common/Makefile +4 -2
index f8f2c88..5122b3f 100644
@@ -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
drivers/usb/common/usb-otg.c new file +877 -0
new file mode 100644
index 0000000..a23ab1e
@@ -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 <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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");
drivers/usb/core/Kconfig +0 -14
index ae228d0..37f8c54 100644
@@ -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
drivers/usb/gadget/Kconfig +1 -0
index 3c3f31c..5fc9095 100644
@@ -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
include/linux/usb/gadget.h +2 -0
index f4fc0aa..1d74fb8 100644
@@ -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;
include/linux/usb/hcd.h +1 -0
index 7729c1f..36bd54f 100644
@@ -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
include/linux/usb/otg-fsm.h +7 -0
index 26e6531..943714a 100644
@@ -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 */
include/linux/usb/otg.h +160 -14
index 85b8fb5..9d72951 100644
@@ -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 */
Signature · 7 lines
2.7.4


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best Regards,
Peter Chen
#24 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Roger Quadros

Hi,

Quoted 5 lines · 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

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.

Quoted 1 line

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.

Quoted 38 lines

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

---
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
drivers/usb/Kconfig +0 -0
index 8689dcb..ed596ec 100644

drivers/usb/Kconfig if USB_SUPPORT · line 36

Quoted 5 lines
drivers/usb/Kconfig +2 -0
@@ -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'?

Quoted 24 lines
drivers/usb/common/usb-otg.c new file +18 -0
new file mode 100644
index 0000000..a23ab1e
@@ -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 <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>

drivers/usb/common/usb-otg.c line 28

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+#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?

drivers/usb/common/usb-otg.c line 34

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+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?

Quoted 37 lines
drivers/usb/common/usb-otg.c new file +37 -0
+	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.
+ *

drivers/usb/common/usb-otg.c line 81

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+ * 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.

drivers/usb/common/usb-otg.c line 92

Quoted 11 lines
drivers/usb/common/usb-otg.c new file +11 -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?

Quoted 16 lines
drivers/usb/common/usb-otg.c new file +16 -0
+		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;
+			}
+		}

drivers/usb/common/usb-otg.c line 118

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+		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()?

Quoted 17 lines
drivers/usb/common/usb-otg.c new file +17 -0
+		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.
+ */

drivers/usb/common/usb-otg.c line 146

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+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

Quoted 175 lines
drivers/usb/common/usb-otg.c new file +175 -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;

drivers/usb/common/usb-otg.c line 332

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+	}
+
+	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.

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+
+/**
+ * usb_drd_work() - Dual-role state machine work function
+ * @work: work_struct context
+ *
+ * Runs the DRD state machine. Scheduled whenever there is a change

drivers/usb/common/usb-otg.c line 348

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+ * 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.

Quoted 45 lines
drivers/usb/common/usb-otg.c new file +45 -0
+}
+
+/**
+ * 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) {

drivers/usb/common/usb-otg.c line 403

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+		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?

Quoted 46 lines
drivers/usb/common/usb-otg.c new file +46 -0
+	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);

drivers/usb/common/usb-otg.c line 460

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+		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.

Quoted 28 lines
drivers/usb/common/usb-otg.c new file +28 -0
+	/* 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;
+

drivers/usb/common/usb-otg.c line 499

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+	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.

Quoted 367 lines
drivers/usb/common/usb-otg.c new file +367 -0
+	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);
+

drivers/usb/common/usb-otg.c line 877

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+	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?

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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?

Signature · 1 line
balbi
#25 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 15 lines · Felipe Balbi

Hi,

Quoted 5 lines · 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

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.

Quoted 7 lines

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

Quoted 1 line

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

Quoted 42 lines
Quoted 42 lines

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

---
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
drivers/usb/Kconfig +0 -0
index 8689dcb..ed596ec 100644
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
Quoted 4 lines

drivers/usb/Kconfig if USB_SUPPORT · line 36

Quoted 2 lines
drivers/usb/Kconfig +2 -0
+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.

Quoted 29 lines
Quoted 29 lines
drivers/usb/common/usb-otg.c new file +22 -0
new file mode 100644
index 0000000..a23ab1e
@@ -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 <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
Quoted 8 lines

drivers/usb/common/usb-otg.c line 28

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+#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.

Quoted 11 lines

drivers/usb/common/usb-otg.c line 34

Quoted 7 lines
drivers/usb/common/usb-otg.c new file +6 -0
+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.

Quoted 50 lines
Quoted 38 lines
drivers/usb/common/usb-otg.c new file +37 -0
+	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.
+ *

drivers/usb/common/usb-otg.c line 81

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+ * 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"))

Quoted 4 lines
	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;
Quoted 14 lines

drivers/usb/common/usb-otg.c line 92

Quoted 12 lines
drivers/usb/common/usb-otg.c new file +11 -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.

Quoted 51 lines
Quoted 17 lines
drivers/usb/common/usb-otg.c new file +16 -0
+		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;
+			}
+		}

drivers/usb/common/usb-otg.c line 118

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+		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()?

Quoted 21 lines
drivers/usb/common/usb-otg.c new file +21 -0
+		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;
Quoted 8 lines

drivers/usb/common/usb-otg.c line 146

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+
+	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__)

Quoted 180 lines
Quoted 180 lines
drivers/usb/common/usb-otg.c new file +179 -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);
Quoted 8 lines

drivers/usb/common/usb-otg.c line 332

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+	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.

Quoted 1 line

below. BTW, that work_struct looks unnecessary.

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

Quoted 12 lines
Quoted 12 lines
drivers/usb/common/usb-otg.c new file +11 -0
+
+/**
+ * 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);
Quoted 8 lines

drivers/usb/common/usb-otg.c line 348

Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -0
+
+	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.

Quoted 50 lines
Quoted 50 lines
drivers/usb/common/usb-otg.c new file +49 -0
+}
+
+/**
+ * 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;
Quoted 8 lines

drivers/usb/common/usb-otg.c line 403

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+	}
+
+	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.

Quoted 54 lines
Quoted 54 lines
drivers/usb/common/usb-otg.c new file +53 -0
+	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__);
Quoted 8 lines

drivers/usb/common/usb-otg.c line 460

Quoted 3 lines
drivers/usb/common/usb-otg.c new file +3 -0
+		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.

Quoted 35 lines
Quoted 35 lines
drivers/usb/common/usb-otg.c new file +34 -0
+	/* 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) {
Quoted 8 lines

drivers/usb/common/usb-otg.c line 499

Quoted 4 lines
drivers/usb/common/usb-otg.c new file +4 -0
+		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.

Quoted 374 lines

You seem to guarantee that will never be the case.

Quoted 371 lines
drivers/usb/common/usb-otg.c new file +371 -0
+	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);
Quoted 8 lines

drivers/usb/common/usb-otg.c line 877

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_gadget_ready);
+
+MODULE_LICENSE("GPL");

GPL or GPL 2-only?

GPL v2.

Quoted 13 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 10 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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

#26 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 17 lines · Roger Quadros
Quoted 17 lines
Quoted 5 lines · 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

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.

Quoted 1 line

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

Quoted 7 lines
Quoted 2 lines

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

Quoted 46 lines
Quoted 41 lines
Quoted 41 lines

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

---
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
drivers/usb/Kconfig +0 -0
index 8689dcb..ed596ec 100644
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
Quoted 4 lines

drivers/usb/Kconfig if USB_SUPPORT · line 36

Quoted 2 lines
drivers/usb/Kconfig +2 -0
+config USB_OTG_CORE
+	tristate

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

Quoted 6 lines

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.

Quoted 51 lines
Quoted 28 lines
Quoted 28 lines
drivers/usb/common/usb-otg.c new file +22 -0
new file mode 100644
index 0000000..a23ab1e
@@ -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 <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
Quoted 8 lines

drivers/usb/common/usb-otg.c line 28

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+#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.

Quoted 11 lines

drivers/usb/common/usb-otg.c line 34

Quoted 7 lines
drivers/usb/common/usb-otg.c new file +6 -0
+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?

Quoted 2 lines

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 ?

Quoted 51 lines
Quoted 51 lines
Quoted 37 lines
drivers/usb/common/usb-otg.c new file +37 -0
+	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.
+ *

drivers/usb/common/usb-otg.c line 81

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+ * 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;
Quoted 5 lines
Quoted 2 lines

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.

Quoted 4 lines

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.

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -0
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
Quoted 8 lines

drivers/usb/common/usb-otg.c line 92

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+			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?

Quoted 4 lines

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.

Quoted 10 lines
Quoted 3 lines

drivers/usb/common/usb-otg.c line 332

Quoted 1 line
drivers/usb/common/usb-otg.c new file +1 -0
+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.

Quoted 1 line

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

Quoted 56 lines
Quoted 47 lines
Quoted 47 lines
drivers/usb/common/usb-otg.c new file +47 -0
+/**
+ * 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;
Quoted 8 lines

drivers/usb/common/usb-otg.c line 403

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+	}
+
+	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?

Quoted 2 lines

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.

Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
drivers/usb/common/usb-otg.c new file +13 -0
+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) {
Quoted 8 lines

drivers/usb/common/usb-otg.c line 499

Quoted 4 lines
drivers/usb/common/usb-otg.c new file +4 -0
+		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?

Quoted 2 lines

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.

Quoted 20 lines
Quoted 3 lines

drivers/usb/common/usb-otg.c line 877

Quoted 1 line
drivers/usb/common/usb-otg.c new file +1 -0
+MODULE_LICENSE("GPL");

GPL or GPL 2-only?

GPL v2.

Quoted 13 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 10 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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?

Quoted 4 lines

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.

Signature · 1 line
balbi
#27 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 81 lines · Felipe Balbi

Hi,

Quoted 17 lines · Roger Quadros
Quoted 17 lines
Quoted 5 lines · 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

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.

Quoted 1 line

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

Quoted 7 lines
Quoted 2 lines

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

Quoted 50 lines
Quoted 41 lines
Quoted 41 lines

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

---
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
drivers/usb/Kconfig +0 -0
index 8689dcb..ed596ec 100644
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
Quoted 4 lines

drivers/usb/Kconfig if USB_SUPPORT · line 36

Quoted 2 lines
drivers/usb/Kconfig +2 -0
+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

Quoted 5 lines
Quoted 2 lines

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.

Quoted 52 lines
Quoted 52 lines
Quoted 29 lines
Quoted 29 lines
drivers/usb/common/usb-otg.c new file +22 -0
new file mode 100644
index 0000000..a23ab1e
@@ -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 <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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>
Quoted 8 lines

drivers/usb/common/usb-otg.c line 28

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+#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.

Quoted 11 lines

drivers/usb/common/usb-otg.c line 34

Quoted 7 lines
drivers/usb/common/usb-otg.c new file +6 -0
+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?

Quoted 5 lines
Quoted 2 lines

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.

Quoted 52 lines
Quoted 52 lines
Quoted 52 lines
Quoted 38 lines
drivers/usb/common/usb-otg.c new file +37 -0
+	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.
+ *

drivers/usb/common/usb-otg.c line 81

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+ * 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;
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

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?

Quoted 32 lines
Quoted 5 lines

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.

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -0
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
Quoted 8 lines

drivers/usb/common/usb-otg.c line 92

Quoted 6 lines
drivers/usb/common/usb-otg.c new file +6 -0
+			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?

Quoted 4 lines

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.

Quoted 5 lines

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.

Quoted 7 lines

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.

Quoted 12 lines

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.

Quoted 6 lines
Quoted 3 lines

drivers/usb/common/usb-otg.c line 332

Quoted 1 line
drivers/usb/common/usb-otg.c new file +1 -0
+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.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

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.

Quoted 57 lines
Quoted 57 lines
Quoted 56 lines
Quoted 44 lines
drivers/usb/common/usb-otg.c new file +43 -0
+/**
+ * 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) {

drivers/usb/common/usb-otg.c line 403

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+		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?

Quoted 6 lines
Quoted 2 lines

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.

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 8 lines
drivers/usb/common/usb-otg.c new file +7 -0
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+

drivers/usb/common/usb-otg.c line 499

Quoted 10 lines
drivers/usb/common/usb-otg.c new file +10 -0
+	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?

Quoted 7 lines
Quoted 2 lines

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.

Quoted 24 lines
Quoted 24 lines
Quoted 4 lines

drivers/usb/common/usb-otg.c line 877

Quoted 2 lines
drivers/usb/common/usb-otg.c new file +1 -0
+MODULE_LICENSE("GPL");

GPL or GPL 2-only?

GPL v2.

Quoted 13 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 10 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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.

Quoted 9 lines
Quoted 1 line

[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

#28 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 17 lines · Roger Quadros
Quoted 17 lines
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
drivers/usb/Kconfig +0 -0
index 8689dcb..ed596ec 100644
@@ -32,6 +32,23 @@ if USB_SUPPORT
 config USB_COMMON
 	tristate
 
Quoted 4 lines

drivers/usb/Kconfig if USB_SUPPORT · line 36

Quoted 2 lines
drivers/usb/Kconfig +2 -0
+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

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

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'?

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 10 lines

drivers/usb/Kconfig if USB_SUPPORT · line 42

Quoted 6 lines
drivers/usb/Kconfig +6 -0
+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?

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

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?

Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

drivers/usb/Kconfig if USB_SUPPORT · line 50

Quoted 8 lines
drivers/usb/Kconfig +8 -0
+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.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

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.

Quoted 24 lines
Quoted 24 lines
Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
drivers/usb/Kconfig +5 -0
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
Quoted 8 lines

drivers/usb/Kconfig

Quoted 6 lines
drivers/usb/Kconfig +6 -0
+			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?

Quoted 4 lines

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.

Quoted 8 lines
Quoted 5 lines

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.

Quoted 8 lines
Quoted 6 lines

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.

Quoted 9 lines
Quoted 6 lines
Quoted 2 lines

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.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

drivers/usb/Kconfig

Quoted 4 lines
drivers/usb/Kconfig +4 -0
+	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?

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

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

Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
drivers/usb/Kconfig +13 -0
+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) {
Quoted 8 lines

drivers/usb/Kconfig

Quoted 4 lines
drivers/usb/Kconfig +4 -0
+		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.

Quoted 8 lines
Quoted 4 lines

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

Quoted 3 lines

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.

Quoted 2 lines

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

right

Quoted 2 lines

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?

Signature · 1 line
balbi
#29 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Felipe Balbi
Quoted 34 lines · Felipe Balbi

Hi,

Quoted 8 lines
Quoted 7 lines

drivers/usb/common/usb-otg.c line 92

Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -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?

Quoted 4 lines

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?

Quoted 4 lines

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.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 9 lines
Quoted 1 line

[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 :)

Signature · 2 lines
Best Regards,
Peter Chen
#30 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 31 lines · Peter Chen
Quoted 31 lines
Quoted 8 lines
Quoted 7 lines

drivers/usb/common/usb-otg.c line 92

Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -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?

Quoted 4 lines

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?

Quoted 6 lines
Quoted 4 lines

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.

Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 2 lines

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

Signature · 1 line
balbi
#31 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 62 lines · Felipe Balbi

Hi,

Quoted 31 lines · Peter Chen
Quoted 31 lines
Quoted 8 lines
Quoted 7 lines

drivers/usb/common/usb-otg.c line 92

Quoted 5 lines
drivers/usb/common/usb-otg.c new file +5 -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?

Quoted 4 lines

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?

Quoted 6 lines
Quoted 4 lines

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.

Quoted 18 lines
Quoted 17 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 6 lines
Quoted 2 lines

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?

Quoted 9 lines
Quoted 3 lines

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.

Signature · 2 lines
Best Regards,
Peter Chen
#32 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 62 lines · Peter Chen
Quoted 62 lines
Quoted 31 lines · Peter Chen
Quoted 31 lines
Quoted 8 lines
Quoted 7 lines

Review

Quoted 5 lines
(quoted diff) +5 -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?

Quoted 4 lines

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?

Quoted 6 lines
Quoted 4 lines

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.

Quoted 20 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 9 lines
Quoted 1 line

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

Quoted 6 lines
Quoted 3 lines

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.

Quoted 10 lines
Quoted 8 lines
Quoted 2 lines

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

Signature · 1 line
balbi
#33 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 70 lines · Felipe Balbi

Hi,

Quoted 66 lines · Peter Chen
Quoted 65 lines
Quoted 31 lines · Peter Chen
Quoted 31 lines
Quoted 8 lines
Quoted 7 lines

Review

Quoted 5 lines
(quoted diff) +5 -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?

Quoted 4 lines

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?

Quoted 6 lines
Quoted 4 lines

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.

Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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.

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#34 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 33 lines · Peter Chen
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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.

Quoted 6 lines

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

Signature · 1 line
balbi
#35 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 41 lines · Felipe Balbi

Hi,

Quoted 37 lines · Peter Chen
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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

Quoted 8 lines
Quoted 2 lines

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.

Signature · 2 lines
Best Regards,
Peter Chen
#36 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 40 lines · Peter Chen
Quoted 40 lines
Quoted 39 lines
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 1 line

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.

Signature · 1 line
balbi
#37 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 83 lines · Felipe Balbi

Hi,

Quoted 40 lines · Peter Chen
Quoted 40 lines
Quoted 39 lines
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 7 lines
Quoted 1 line

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

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#38 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 62 lines · Peter Chen
Quoted 54 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 7 lines
Quoted 1 line

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.

Quoted 7 lines

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)

Quoted 1 line

- A common workqueue to handle vbus and id event

I already have a threaded IRQ handler. Why do I need a workqueue?

Quoted 1 line

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

Signature · 1 line
balbi
#39 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 74 lines · Felipe Balbi

Hi,

Quoted 62 lines · Peter Chen
Quoted 54 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 7 lines
Quoted 1 line

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.

Quoted 7 lines

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.

Quoted 9 lines

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)

Quoted 1 line

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

Quoted 8 lines
Quoted 1 line

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

Signature · 1 line
balbi
Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#40 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 75 lines · Peter Chen
Quoted 75 lines
Quoted 62 lines
Quoted 54 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 7 lines
Quoted 1 line

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.

Quoted 7 lines

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)

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

- 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?

Quoted 11 lines

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

Signature · 1 line
balbi
#41 lore raw

RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Peter Chen

Hi,

Quoted 105 lines

From: Peter Chen
Sent: Wednesday, June 22, 2016 12:34 PM

Quoted 83 lines · Felipe Balbi

Hi,

Quoted 40 lines · Peter Chen
Quoted 40 lines
Quoted 39 lines
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+ * @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.

Quoted 7 lines
Quoted 4 lines

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.

Quoted 7 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 4 lines

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)

Quoted 7 lines
Quoted 1 line

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

Quoted 3 lines

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

Quoted 6 lines

[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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#42 lore raw

RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Roger Quadros

Hi Roger,

Quoted 6 lines

From: Roger Quadros
Sent: Monday, June 20, 2016 7:13 PM

Hi,

On 20/06/16 10:45, Felipe Balbi wrote:

< snip >

Quoted 13 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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?

Quoted 8 lines

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#43 lore raw

RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 29 lines · Yoshihiro Shimoda

Hi Roger,

Quoted 6 lines

From: Roger Quadros
Sent: Monday, June 20, 2016 7:13 PM

Hi,

On 20/06/16 10:45, Felipe Balbi wrote:

< snip >

Quoted 20 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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,

Quoted 7 lines
Quoted 1 line

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

Signature · 1 line
balbi
#44 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Felipe Balbi
Quoted 10 lines · Felipe Balbi

Hi,

Quoted 5 lines · 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

Quoted 7 lines

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.

Quoted 13 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 10 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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.

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#45 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 12 lines · Peter Chen
Quoted 12 lines
Quoted 5 lines · 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

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.

Quoted 5 lines
Quoted 2 lines

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

Quoted 1 line

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.

Quoted 13 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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?

Quoted 3 lines

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.

Signature · 1 line
balbi
#46 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 27 lines · Felipe Balbi

Hi,

Quoted 12 lines · Peter Chen
Quoted 12 lines
Quoted 5 lines · 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

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.

Quoted 5 lines
Quoted 2 lines

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.

Quoted 5 lines

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

Quoted 5 lines
Quoted 1 line

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.

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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?

Quoted 7 lines
Quoted 3 lines

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?

Signature · 2 lines
Best Regards,
Peter Chen
#47 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 28 lines · Peter Chen
Quoted 22 lines
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines

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.

Quoted 5 lines
Quoted 2 lines

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.

Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 1 line

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.

Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 2 lines

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"?

Signature · 1 line
balbi
#48 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 14 lines · Felipe Balbi

Hi,

Quoted 11 lines
Quoted 6 lines

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"?

Quoted 9 lines
Quoted 2 lines

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.

Quoted 10 lines
Quoted 8 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 7 lines
Quoted 2 lines

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.

Quoted 28 lines
Quoted 18 lines
Quoted 18 lines
Quoted 17 lines
Quoted 13 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 10 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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.

Quoted 5 lines
Quoted 3 lines

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"

Quoted 8 lines

You didn't include role swap in your original comment. Semantics aside...

Quoted 2 lines

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 <[email protected]>
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?

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#49 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 13 lines · Peter Chen
Quoted 13 lines
Quoted 12 lines
Quoted 5 lines

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

Quoted 8 lines
Quoted 6 lines

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.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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

------------------------------------------------------------------------

Quoted 7 lines
Quoted 6 lines
Quoted 1 line

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.

Quoted 6 lines

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?

Quoted 32 lines
Quoted 32 lines
Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
Quoted 12 lines

include/linux/usb/gadget.h struct usb_gadget_ops { · line 331

Quoted 9 lines
include/linux/usb/gadget.h +1 -0
index f4fc0aa..1d74fb8 100644
@@ -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.

Quoted 5 lines
Quoted 3 lines

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

Quoted 2 lines

Consider the use case the host driver is at host/ and udc driver is at gadget/udc, how to finish to role swap?

Quoted 7 lines
Quoted 3 lines

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

Quoted 4 lines

commit 11c011a5e777c83819078a18672543f04482b3ec

Author: Srinivas Kandagatla <[email protected]>
Date:   Thu May 19 11:12:56 2016 +0100
Quoted 8 lines

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.

Signature · 1 line
balbi
#50 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 6 lines · Felipe Balbi

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#51 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 11 lines · Tony Lindgren
Quoted 6 lines · Felipe Balbi

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.

Signature · 1 line
balbi
#52 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Felipe Balbi
Quoted 24 lines · Felipe Balbi

Hi,

Quoted 20 lines · Peter Chen
Quoted 19 lines
Quoted 6 lines
Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 4 lines
Quoted 1 line

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?

Quoted 37 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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

Quoted 11 lines
Quoted 11 lines
Quoted 6 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 2 lines

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.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines

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"?

Quoted 7 lines
Quoted 3 lines

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.

Quoted 15 lines

(already implemented as gadget_wakeup())

Quoted 4 lines

commit 11c011a5e777c83819078a18672543f04482b3ec

Author: Srinivas Kandagatla <[email protected]>
Date:   Thu May 19 11:12:56 2016 +0100
Quoted 8 lines

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?

Quoted 8 lines

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?

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#53 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 21 lines · Peter Chen
Quoted 21 lines
Quoted 20 lines · Peter Chen
Quoted 19 lines
Quoted 6 lines
Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

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.

Quoted 2 lines

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

Quoted 3 lines

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.

Quoted 45 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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

------------------------------------------------------------------------

Quoted 6 lines

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?

Quoted 22 lines
Quoted 13 lines
Quoted 4 lines

commit 11c011a5e777c83819078a18672543f04482b3ec

Author: Srinivas Kandagatla <[email protected]>
Date:   Thu May 19 11:12:56 2016 +0100
Quoted 8 lines

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?

Quoted 8 lines

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.

Quoted 3 lines

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.

Signature · 1 line
balbi
#54 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 40 lines · Felipe Balbi

Hi,

Quoted 21 lines · Peter Chen
Quoted 21 lines
Quoted 20 lines · Peter Chen
Quoted 19 lines
Quoted 6 lines
Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

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.

Quoted 2 lines

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

Quoted 7 lines
Quoted 3 lines

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"?

Signature · 2 lines
Best Regards,
Peter Chen
#55 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 39 lines · Peter Chen
Quoted 39 lines
Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
Quoted 19 lines
Quoted 6 lines
Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

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.

Quoted 2 lines

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

Quoted 3 lines

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?

Quoted 6 lines
Quoted 3 lines

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.

Signature · 1 line
balbi
#56 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Felipe Balbi

Hi Felipe,

Quoted 100 lines · Felipe Balbi

Hi,

Quoted 21 lines · Peter Chen
Quoted 21 lines
Quoted 20 lines · Peter Chen
Quoted 19 lines
Quoted 6 lines
Quoted 5 lines

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

Quoted 6 lines

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.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

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.

Quoted 2 lines

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

Quoted 3 lines

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.

Quoted 45 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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

------------------------------------------------------------------------

Quoted 6 lines

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.

Quoted 2 lines

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?

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 5 lines

commit 11c011a5e777c83819078a18672543f04482b3ec

Author: Srinivas Kandagatla <[email protected]>
Date:   Thu May 19 11:12:56 2016 +0100
Quoted 8 lines

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.

Quoted 8 lines
Quoted 3 lines

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

#57 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

Quoted 52 lines · Roger Quadros
Quoted 52 lines
Quoted 51 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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

Signature · 1 line
balbi
#58 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 112 lines · Felipe Balbi

Hi,

Quoted 52 lines · Roger Quadros
Quoted 52 lines
Quoted 51 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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?

Quoted 7 lines

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

#59 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi,

On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <[email protected]> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

Quoted 118 lines · Felipe Balbi
Quoted 117 lines

Hi,

Quoted 52 lines · Roger Quadros
Quoted 52 lines
Quoted 51 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

Quoted 8 lines
Quoted 2 lines

[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

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#60 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Vivek,

Quoted 139 lines · Vivek Gautam

Hi,

On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <[email protected]> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

Quoted 118 lines · Felipe Balbi
Quoted 117 lines

Hi,

Quoted 52 lines · Roger Quadros
Quoted 52 lines
Quoted 51 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

Quoted 8 lines
Quoted 2 lines

[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].

Quoted 4 lines

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.

Quoted 9 lines

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

#61 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Hi Roger,

Quoted 149 lines · Roger Quadros

Vivek,

Quoted 146 lines · Vivek Gautam

Hi,

On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <[email protected]> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

Quoted 122 lines · Felipe Balbi
Quoted 121 lines

Hi,

Quoted 56 lines · Roger Quadros
Quoted 56 lines
Quoted 55 lines
Quoted 40 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

Quoted 8 lines
Quoted 2 lines

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

Quoted 6 lines
Quoted 1 line

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.

Quoted 5 lines
Quoted 5 lines

Or, may be add a 'drd' layer for dwc3 that handles
role switching (using PRTCAPDIR) based on the id/vbus extcon notifications.

Quoted 8 lines
Quoted 5 lines

[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

#62 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Vivek,

Quoted 150 lines · On 19/01/17 17:15, [email protected] wrote:

Hi Roger,

Quoted 147 lines · Roger Quadros

Vivek,

Quoted 143 lines · Vivek Gautam

Hi,

On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <[email protected]> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

Quoted 118 lines · Felipe Balbi
Quoted 117 lines

Hi,

Quoted 52 lines · Roger Quadros
Quoted 52 lines
Quoted 51 lines
Quoted 36 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

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.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

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:

Quoted 8 lines

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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

Quoted 8 lines
Quoted 2 lines

[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?

Quoted 7 lines
Quoted 4 lines

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?

Quoted 14 lines

Thanks for sharing the info.

Quoted 11 lines
Quoted 10 lines

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#63 lore raw

Re: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

Quoted 140 lines · Roger Quadros

Vivek,

Quoted 137 lines · On 19/01/17 17:15, [email protected] wrote:

Hi Roger,

Quoted 134 lines · Roger Quadros

Vivek,

Quoted 127 lines · Vivek Gautam

Hi,

On Wed, Jun 22, 2016 at 2:00 PM, Roger Quadros <[email protected]> wrote:

Luckily hit this thread while checking about DRD role functionality for DWC3.

Quoted 104 lines · Felipe Balbi
Quoted 103 lines

Hi,

Quoted 45 lines · Roger Quadros
Quoted 45 lines
Quoted 45 lines
Quoted 31 lines
Quoted 8 lines
Quoted 7 lines
Quoted 6 lines

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:

Quoted 8 lines

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.

Quoted 3 lines
Quoted 2 lines

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.

Quoted 3 lines

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.

Quoted 4 lines

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.

Quoted 4 lines

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.

Quoted 3 lines

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.

Quoted 8 lines
Quoted 2 lines

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

Quoted 1 line

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.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

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.

Quoted 15 lines
Quoted 12 lines

Thanks for sharing the info.

Quoted 9 lines
Quoted 9 lines

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

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#64 lore raw

RE: [PATCH v11 08/14] usb: otg: add OTG/dual-role core

In reply to Roger Quadros

Hi Roger-san,

< snip >

Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
Quoted 21 lines
Quoted 4 lines

commit 11c011a5e777c83819078a18672543f04482b3ec

Author: Srinivas Kandagatla <[email protected]>
Date:   Thu May 19 11:12:56 2016 +0100
Quoted 8 lines

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.

Quoted 8 lines
Quoted 3 lines

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.

Quoted 4 lines

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

Quoted 2 lines

cheers,
-roger

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#65 lore raw

PATCH v10 9/14 usb: of: add an API to get OTG device from USB controller node

In reply to 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.

---
 Documentation/devicetree/bindings/usb/generic.txt |  3 +++
 drivers/usb/common/common.c                       | 27 +++++++++++++++++++++++
 include/linux/usb/of.h                            |  9 ++++++++
 3 files changed, 39 insertions(+)
Documentation/devicetree/bindings/usb/generic.txt +3 -0
index bba8257..f6866c1 100644
@@ -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:
 
drivers/usb/common/common.c +27 -0
index e3d0161..d7ec471 100644
@@ -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");
include/linux/usb/of.h +9 -0
index de3237f..499a4e8 100644
@@ -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
Signature · 1 line
2.7.4
#66 lore raw

RE: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node

Hi

drivers/usb/common/common.c int of_usb_update_otg_caps(struct device_node *np, } · line 244

Quoted 12 lines
drivers/usb/common/common.c +5 -0
index e3d0161..d7ec471 100644
@@ -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

Quoted 39 lines
drivers/usb/common/common.c +21 -0
+ *
+ * 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");
include/linux/usb/of.h index renamed from include/linux/usb/of.h +0 -0

de3237f..499a4e8 100644

include/linux/usb/of.h +7 -0
@@ -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
Quoted 3 lines

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#67 lore raw

Re: [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node

Quoted 9 lines · Jun Li

Hi

Quoted 7 lines
drivers/usb/common/common.c +0 -0
index e3d0161..d7ec471 100644
@@ -238,6 +238,33 @@ int of_usb_update_otg_caps(struct device_node *np,  }
 EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
 
Quoted 7 lines

drivers/usb/common/common.c int of_usb_update_otg_caps(struct device_node *np, · line 245

Quoted 5 lines
drivers/usb/common/common.c +5 -0
+#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.

Quoted 32 lines
Quoted 32 lines
drivers/usb/common/common.c +21 -0
+ *
+ * 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");
include/linux/usb/of.h index renamed from include/linux/usb/of.h +0 -0

de3237f..499a4e8 100644

include/linux/usb/of.h +0 -0
@@ -40,6 +40,15 @@ static inline struct device_node
 *usb_of_get_child_node  }  #endif
 
Quoted 12 lines
Quoted 11 lines
include/linux/usb/of.h +7 -0
+#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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#68 lore raw

PATCH v11 9/14 usb: of: add an API to get OTG device from USB controller node

In reply to 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.

---
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(+)
Documentation/devicetree/bindings/usb/generic.txt +3 -0
index bba8257..f6866c1 100644
@@ -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:
 
drivers/usb/common/common.c +26 -0
index e3d0161..d0c104c 100644
@@ -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");
include/linux/usb/of.h +9 -0
index de3237f..499a4e8 100644
@@ -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
Signature · 1 line
2.7.4
#69 lore raw

PATCH v10 10/14 usb: otg: add hcd companion support

In reply to Roger Quadros

From: Yoshihiro Shimoda <[email protected]>

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.

---
 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(-)
Documentation/devicetree/bindings/usb/generic.txt +3 -0
index f6866c1..1db1c33 100644
@@ -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:
 
drivers/usb/common/usb-otg.c +22 -9
index 4185954..c663f4a 100644
@@ -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);
include/linux/usb/otg.h +6 -1
index 2175fb7..61d524e 100644
@@ -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);
Signature · 1 line
2.7.4
#70 lore raw

PATCH v10 11/14 usb: otg: use dev_vdbg() instead of VDBG()

In reply to Roger Quadros

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

---
 drivers/usb/common/usb-otg-fsm.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)
drivers/usb/common/usb-otg-fsm.c +7 -12
index 482d4c9..e6e58c2 100644
@@ -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);
Signature · 1 line
2.7.4
#71 lore raw

PATCH v10 12/14 usb: hcd: Adapt to OTG core

In reply to 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.

---
 drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/hcd.h |  4 ++++
 2 files changed, 59 insertions(+)
drivers/usb/core/hcd.c +55 -0
index ae6c76d..c6f4155 100644
@@ -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)
 {
include/linux/usb/hcd.h +4 -0
index 36bd54f..0c70282 100644
@@ -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;
Signature · 1 line
2.7.4
#72 lore raw

Re: [PATCH v10 12/14] usb: hcd: Adapt to OTG core

+Alan

Quoted 104 lines · 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.

---
 drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/hcd.h |  4 ++++
 2 files changed, 59 insertions(+)
drivers/usb/core/hcd.c +55 -0
index ae6c76d..c6f4155 100644
@@ -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)
 {
include/linux/usb/hcd.h +4 -0
index 36bd54f..0c70282 100644
@@ -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;
#73 lore raw

PATCH v10 13/14 usb: gadget: udc: adapt to OTG core

In reply to 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.

---
 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)
drivers/usb/gadget/udc/core.c +192 -10
index 42756d7..9d8a1d0 100644
@@ -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);
include/linux/usb/gadget.h +4 -0
index 1d74fb8..8c6880d 100644
@@ -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 */
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#74 lore raw

Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core

Quoted 5 lines · Roger Quadros

+/**
+ * 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

Quoted 24 lines
drivers/usb/gadget/udc/core.c +13 -4
+/* 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;

drivers/usb/gadget/udc/core.c static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri · line 1471

Quoted 10 lines
drivers/usb/gadget/udc/core.c +3 -2
+		}
+		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

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#75 lore raw

Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core

Quoted 8 lines · Peter Chen
Quoted 5 lines · Roger Quadros

+/**
+ * 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.

Quoted 30 lines
Quoted 30 lines
drivers/usb/gadget/udc/core.c +15 -5
+/* 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);
 
Quoted 9 lines

drivers/usb/gadget/udc/core.c static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri · line 1471

Quoted 5 lines
drivers/usb/gadget/udc/core.c +1 -1
 	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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#76 lore raw

Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core

Quoted 11 lines · Roger Quadros
Quoted 8 lines · Peter Chen
Quoted 5 lines · Roger Quadros

+/**
+ * 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.

Quoted 4 lines

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

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#77 lore raw

Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core

Quoted 16 lines · Peter Chen
Quoted 11 lines · Roger Quadros
Quoted 8 lines · Peter Chen
Quoted 5 lines · Roger Quadros

+/**
+ * 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.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 25 lines

/**
* 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);
}
Quoted 2 lines

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#78 lore raw

Re: [PATCH v10 13/14] usb: gadget: udc: adapt to OTG core

Quoted 25 lines · Roger Quadros
Quoted 16 lines · Peter Chen
Quoted 11 lines · Roger Quadros
Quoted 8 lines · Peter Chen
Quoted 5 lines · Roger Quadros

+/**
+ * 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.

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

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.

Quoted 7 lines

@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

Quoted 32 lines
Quoted 26 lines

/**
* 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);
}
Quoted 2 lines

EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);

--
cheers,
-roger

Signature · 6 lines
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#79 lore raw

PATCH v11 13/14 usb: gadget: udc: adapt to OTG core

In reply to 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.

---
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(-)
drivers/usb/gadget/udc/core.c +192 -10
index 42756d7..1290f03 100644
@@ -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);
include/linux/usb/gadget.h +4 -0
index 1d74fb8..8c6880d 100644
@@ -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 */
Signature · 1 line
2.7.4
Acked-by on v11 13/14
#80 lore raw

Re: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core

drivers/usb/gadget/udc/core.c static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri · line 1471

Quoted 3 lines · Roger Quadros

err1:

drivers/usb/gadget/udc/core.c +1 -1
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))

Since you do not need above change.

Expect above, I am ok with this patch.

Quoted 39 lines
drivers/usb/gadget/udc/core.c +6 -0
 		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);
include/linux/usb/gadget.h +4 -0
index 1d74fb8..8c6880d 100644
@@ -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 */
Signature · 7 lines
2.7.4


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best Regards,
Peter Chen
#81 lore raw

Re: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core

Quoted 6 lines · Peter Chen

drivers/usb/gadget/udc/core.c static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri · line 1471

Quoted 3 lines · Roger Quadros

err1:

drivers/usb/gadget/udc/core.c +1 -1
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))

Since you do not need above change.

Ah :P, will fix it.

Quoted 4 lines

Expect above, I am ok with this patch.

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 [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#82 lore raw

PATCH v10 14/14 usb: host: xhci-plat: Add otg device to platform data

In reply to 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.

---
 drivers/usb/host/xhci-plat.c     | 35 ++++++++++++++++++++++++++++-------
 include/linux/usb/xhci_pdriver.h |  3 +++
 2 files changed, 31 insertions(+), 7 deletions(-)
drivers/usb/host/xhci-plat.c +28 -7
index 676ea45..24d030a 100644
@@ -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))
include/linux/usb/xhci_pdriver.h +3 -0
index 376654b..5c68b83 100644
@@ -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 */
Signature · 1 line
2.7.4
#83 lore raw

Re: [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data

Mathias,

Quoted 4 lines · 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.

Quoted 8 lines

We use platform data to pass the OTG controller device.

---
 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?

Quoted 89 lines
drivers/usb/host/xhci-plat.c +28 -7
index 676ea45..24d030a 100644
@@ -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))
include/linux/usb/xhci_pdriver.h +3 -0
index 376654b..5c68b83 100644
@@ -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 */
#84 lore raw
In reply to Roger Quadros
Quoted 11 lines · 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.

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

Quoted 256 lines

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
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best Regards,
Peter Chen
#85 lore raw

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

Hi,

Quoted 13 lines · Peter Chen
Quoted 11 lines · 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.

Quoted 5 lines

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

Quoted 260 lines

Peter

Quoted 256 lines

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
Signature · 6 lines
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#86 lore raw
In reply to Roger Quadros

Hi Felipe,

Quoted 5 lines · 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.

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

Quoted 255 lines

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
#87 lore raw

Hi Roger,

Quoted 6 lines · Roger Quadros
Quoted 3 lines

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.

Signature · 1 line
balbi
#88 lore raw
Quoted 11 lines · Felipe Balbi

Hi Roger,

Quoted 6 lines · Roger Quadros
Quoted 3 lines

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.

Quoted 8 lines

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