Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1212184 > unrolled thread

[PATCH v4 00/13] USB: OTG/DRD Core functionality

Started byRoger Quadros <rogerq@ti.com>
First post2015-08-24 15:30 +0200
Last post2015-09-07 13:50 +0200
Articles 18 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v4 00/13]  USB: OTG/DRD Core functionality Roger Quadros <rogerq@ti.com> - 2015-08-24 15:30 +0200
    [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops Roger Quadros <rogerq@ti.com> - 2015-08-24 15:30 +0200
      Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into  otg-fsm->ops Roger Quadros <rogerq@ti.com> - 2015-09-07 12:00 +0200
        Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into  otg-fsm->ops Roger Quadros <rogerq@ti.com> - 2015-09-08 10:30 +0200
    [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros <rogerq@ti.com> - 2015-08-24 15:30 +0200
      Re: [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support Roger Quadros <rogerq@ti.com> - 2015-09-07 12:00 +0200
    Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-07 12:30 +0200
      Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-08 14:30 +0200
        Re: [PATCH v4 07/13] usb: otg: add OTG core Alan Stern <stern@rowland.harvard.edu> - 2015-09-08 16:40 +0200
          Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-08 19:40 +0200
        Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-09 11:10 +0200
          Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-09 11:40 +0200
            Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-09 12:30 +0200
              Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-10 16:20 +0200
    Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-07 13:00 +0200
      Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-09 12:10 +0200
        Re: [PATCH v4 07/13] usb: otg: add OTG core Roger Quadros <rogerq@ti.com> - 2015-09-10 16:20 +0200
    Re: [PATCH v4 00/13] USB: OTG/DRD Core functionality Roger Quadros <rogerq@ti.com> - 2015-09-07 13:50 +0200

#1212184 — [PATCH v4 00/13] USB: OTG/DRD Core functionality

FromRoger Quadros <rogerq@ti.com>
Date2015-08-24 15:30 +0200
Subject[PATCH v4 00/13] USB: OTG/DRD Core functionality
Message-ID<q0ZZ0-vR-3@gated-at.bofh.it>
Hi,

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

DWC3 controller and platform related patches will be sent separately.

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

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

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

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

Why?:
----

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

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

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

What?:
-----

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

int usb_otg_unregister(struct device *dev);

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


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


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

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

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

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

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

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

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

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

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

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

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

--
cheers,
-roger

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

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

-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1212185 — [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops

FromRoger Quadros <rogerq@ti.com>
Date2015-08-24 15:30 +0200
Subject[PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops
Message-ID<q0ZZ2-vR-41@gated-at.bofh.it>
In reply to#1212184
This is to prevent missing symbol build error if OTG is
enabled (built-in) and HCD core (CONFIG_USB) is module.

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

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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220030 — Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops

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

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220599 — Re: [PATCH v4 04/13] otg-fsm: move usb_bus_start_enum into otg-fsm->ops

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

Yes, this is a better idea. Thanks.

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1212188 — [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support

FromRoger Quadros <rogerq@ti.com>
Date2015-08-24 15:30 +0200
Subject[PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support
Message-ID<q0ZZ2-vR-39@gated-at.bofh.it>
In reply to#1212184
DRD mode is a reduced functionality OTG mode. In this mode
we don't support SRP, HNP and dynamic role-swap.

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

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

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

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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220031 — Re: [PATCH v4 13/13] usb: otg: Add dual-role device (DRD) support

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

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

--
cheers,
-roger

>> +		drd_set_protocol(fsm, PROTO_HOST);
>> +		break;
>> +	case OTG_STATE_UNDEFINED:
>> +	case OTG_STATE_B_SRP_INIT:
>> +	case OTG_STATE_B_WAIT_ACON:
>> +	case OTG_STATE_B_HOST:
>> +	case OTG_STATE_A_IDLE:
>> +	case OTG_STATE_A_WAIT_VRISE:
>> +	case OTG_STATE_A_WAIT_BCON:
>> +	case OTG_STATE_A_SUSPEND:
>> +	case OTG_STATE_A_PERIPHERAL:
>> +	case OTG_STATE_A_WAIT_VFALL:
>> +	case OTG_STATE_A_VBUS_ERR:
>> +	default:
>> +		dev_warn(otgd->dev, "%s: otg: invalid state: %s\n",
>> +			 __func__, usb_otg_state_string(new_state));
>> +		break;
>> +	}
>> +
>> +	fsm->otg->state = new_state;
>> +}
>> +
> ... ...
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220040 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

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

Any better idea?

cheers,
-roger

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

[toc] | [prev] | [next] | [standalone]


#1220739 — Re: [PATCH v4 07/13] usb: otg: add OTG core

FromRoger Quadros <rogerq@ti.com>
Date2015-09-08 14:30 +0200
SubjectRe: [PATCH v4 07/13] usb: otg: add OTG core
Message-ID<q6qca-48n-35@gated-at.bofh.it>
In reply to#1220040

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

What if there is another architecture like so?

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

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

How about adding struct usb_otg parameter to usb_otg_register_hcd()?

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

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

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

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

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220865 — Re: [PATCH v4 07/13] usb: otg: add OTG core

FromAlan Stern <stern@rowland.harvard.edu>
Date2015-09-08 16:40 +0200
SubjectRe: [PATCH v4 07/13] usb: otg: add OTG core
Message-ID<q6sdZ-71F-31@gated-at.bofh.it>
In reply to#1220739
On Tue, 8 Sep 2015, Roger Quadros wrote:

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

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

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

and the following messages in that thread.

Alan Stern


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1221015 — Re: [PATCH v4 07/13] usb: otg: add OTG core

FromRoger Quadros <rogerq@ti.com>
Date2015-09-08 19:40 +0200
SubjectRe: [PATCH v4 07/13] usb: otg: add OTG core
Message-ID<q6v2a-2Em-7@gated-at.bofh.it>
In reply to#1220865
Alan,

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

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

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

cheers,
-roger

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1221319 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

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

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

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

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

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

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

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

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

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1221337 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

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

--
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1221360 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

Case A:

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

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

Case B:

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

code:

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

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

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

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

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

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

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

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

Yes, let's discuss more in that direction.

--
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1222224 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220052 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

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

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

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

Sorry missed this one. Will add.

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

OK. will add this too.

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

yes, returning usb_otg makes more sense now.

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

otgd->caps is a pointer.

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

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

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

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

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

yes.

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

yes.

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

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

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

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

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

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

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

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

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

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

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

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

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

Yes, can be moved there.

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

[toc] | [prev] | [next] | [standalone]


#1221352 — Re: [PATCH v4 07/13] usb: otg: add OTG core

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

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

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

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

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

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

Let's leave it around then.

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

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

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

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

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

--
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1222229 — Re: [PATCH v4 07/13] usb: otg: add OTG core

FromRoger Quadros <rogerq@ti.com>
Date2015-09-10 16:20 +0200
SubjectRe: [PATCH v4 07/13] usb: otg: add OTG core
Message-ID<q7aRI-3Sb-29@gated-at.bofh.it>
In reply to#1221352
On 10/09/15 12:28, Li Jun wrote:
> On Wed, Sep 09, 2015 at 01:01:14PM +0300, Roger Quadros wrote:
> ... ...
> 
>>>>>> +	return -EINVAL;
>>>>>
>>>>> Return non-zero, then if err, do we need call usb_otg_add_hcd() after
>>>>> usb_otg_register_hcd() fails?
>>>>
>>>> You should not call usb_otg_register_hcd() but usb_add_hcd().
>>>> If that fails then you fail as ususal.
>>>
>>> My point is if we use usb_add_hcd(), but failed in usb_otg_register_hcd(),
>>> then usb_otg_add_hcd() will be called in *all* error case, is this your
>>> expectation?
>>> 	if (usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf))
>>> 		return usb_otg_add_hcd(hcd, irqnum, irqflags);
>>>
>>
>> Yes, my intention was that if otg fails then it is a non otg HCD so register normally.
>> Let me correct my previous statement. If you are absolutely sure
>> that the HCD is for otg/dual-role usage then you should call usb_otg_register_hcd().
>>
> 
> I think this is not just about a statement, in your usb_otg_register_hcd()
> implementation, there are several places will return error, I think only
> the first two are for a non-otg HCD case, the following error cases seems
> mean this is for otg usage, but it fails in middle of registration, if that
> is the case, is it reasonable to call usb_otg_add_hcd()?

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

I will fix usb_add_hcd().

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

OK.

> 
>>>
>>>>>>  	struct usb_bus		*host;
>>>>>>  	struct usb_gadget	*gadget;
>>>>>>  
>>>>>>  	enum usb_otg_state	state;
>>>>>>  
>>>>>> +	struct device *dev;
>>>>>> +	struct usb_otg_caps *caps;
>>>>>> +	struct otg_fsm fsm;
>>>>>> +	struct otg_fsm_ops fsm_ops;
>>>>>> +
>>>>>> +	/* internal use only */
>>>>>> +	struct otg_hcd primary_hcd;
>>>>>> +	struct otg_hcd shared_hcd;
>>>>>> +	struct otg_gadget_ops *gadget_ops;
>>>>>> +	struct otg_timer timers[NUM_OTG_FSM_TIMERS];
>>>>>> +	struct list_head list;
>>>>>> +	struct work_struct work;
>>>>>> -- 
>>>>>> 2.1.4
>>>
--
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1220091 — Re: [PATCH v4 00/13] USB: OTG/DRD Core functionality

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

No problem and thanks for the tests.

cheers,
-roger

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

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web