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


Groups > linux.kernel > #1392163 > unrolled thread

[PATCH v7 00/14] USB OTG/dual-role framework

Started byRoger Quadros <rogerq@ti.com>
First post2016-05-02 14:20 +0200
Last post2016-05-11 13:10 +0200
Articles 20 on this page of 54 — 7 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v7 00/14] USB OTG/dual-role framework Roger Quadros <rogerq@ti.com> - 2016-05-02 14:20 +0200
    [PATCH v7 02/14] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros <rogerq@ti.com> - 2016-05-02 14:20 +0200
      Re: [PATCH v7 02/14] usb: otg-fsm: Prevent build warning "VDBG"  redefined Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 10:30 +0200
    [PATCH v7 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in  favour of CONFIG_USB_OTG Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 10:40 +0200
    [PATCH v7 09/14] usb: of: add an API to get OTG device from USB controller node Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 09/14] usb: of: add an API to get OTG device from USB  controller node Rob Herring <robh@kernel.org> - 2016-05-04 15:20 +0200
      Re: [PATCH v7 09/14] usb: of: add an API to get OTG device from USB  controller node Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 10:50 +0200
        Re: [PATCH v7 09/14] usb: of: add an API to get OTG device from USB  controller node Roger Quadros <rogerq@ti.com> - 2016-05-11 13:10 +0200
    [PATCH v7 11/14] usb: otg: use dev_dbg() instead of VDBG() Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 11/14] usb: otg: use dev_dbg() instead of VDBG() Peter Chen <hzpeterchen@gmail.com> - 2016-05-06 11:20 +0200
        Re: [PATCH v7 11/14] usb: otg: use dev_dbg() instead of VDBG() Roger Quadros <rogerq@ti.com> - 2016-05-09 11:50 +0200
          Re: [PATCH v7 11/14] usb: otg: use dev_dbg() instead of VDBG() Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 11:00 +0200
    [PATCH v7 14/14] usb: host: xhci-plat: Add otg device to platform data Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 14/14] usb: host: xhci-plat: Add otg device to  platform data Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 11:10 +0200
    [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Peter Chen <hzpeterchen@gmail.com> - 2016-05-06 11:50 +0200
        Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-09 11:50 +0200
          Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Peter Chen <hzpeterchen@gmail.com> - 2016-05-10 05:30 +0200
            Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-10 09:40 +0200
              Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Felipe Balbi <balbi@kernel.org> - 2016-05-10 10:20 +0200
                Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-10 11:20 +0200
              RE: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Jun Li <jun.li@nxp.com> - 2016-05-10 10:20 +0200
                Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-10 11:30 +0200
                  Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 08:30 +0200
    [PATCH v7 12/14] usb: hcd: Adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 12/14] usb: hcd: Adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 11:10 +0200
    [PATCH v7 01/14] usb: hcd: Initialize hcd->flags to 0 Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 01/14] usb: hcd: Initialize hcd->flags to 0 Peter Chen <hzpeterchen@gmail.com> - 2016-05-06 11:20 +0200
    [PATCH v7 06/14] usb: gadget.h: Add OTG to gadget interface Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
    [PATCH v7 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 08/14] usb: otg: add OTG/dual-role core Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 10:50 +0200
        Re: [PATCH v7 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-11 13:10 +0200
    [PATCH v7 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
    [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations  into usb_otg->hcd_ops Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 08:20 +0200
        Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations  into usb_otg->hcd_ops Roger Quadros <rogerq@ti.com> - 2016-05-11 13:10 +0200
          Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations  into usb_otg->hcd_ops Roger Quadros <rogerq@ti.com> - 2016-05-11 14:40 +0200
            Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations  into usb_otg->hcd_ops Peter Chen <hzpeterchen@gmail.com> - 2016-05-12 10:30 +0200
              Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations  into usb_otg->hcd_ops Roger Quadros <rogerq@ti.com> - 2016-05-12 10:40 +0200
    [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-02 14:30 +0200
      Re: [PATCH v7 10/14] usb: otg: add hcd companion support Rob Herring <robh@kernel.org> - 2016-05-04 15:20 +0200
        Re: [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-04 15:50 +0200
          Re: [PATCH v7 10/14] usb: otg: add hcd companion support Rob Herring <robh@kernel.org> - 2016-05-11 16:00 +0200
            Re: [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-11 16:20 +0200
              Re: [PATCH v7 10/14] usb: otg: add hcd companion support Alan Stern <stern@rowland.harvard.edu> - 2016-05-11 16:50 +0200
                RE: [PATCH v7 10/14] usb: otg: add hcd companion support Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> - 2016-05-12 06:10 +0200
                  Re: [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-12 10:40 +0200
                    Re: [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-12 11:40 +0200
                      RE: [PATCH v7 10/14] usb: otg: add hcd companion support Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> - 2016-05-12 12:40 +0200
                        Re: [PATCH v7 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-12 14:20 +0200
      Re: [PATCH v7 10/14] usb: otg: add hcd companion support Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 11:00 +0200
    Re: [PATCH v7 00/14] USB OTG/dual-role framework Peter Chen <hzpeterchen@gmail.com> - 2016-05-11 10:50 +0200
      Re: [PATCH v7 00/14] USB OTG/dual-role framework Roger Quadros <rogerq@ti.com> - 2016-05-11 13:10 +0200

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#1397826 — Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface

FromFelipe Balbi <balbi@kernel.org>
Date2016-05-10 10:20 +0200
SubjectRe: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
Message-ID<rxb3A-70Q-5@gated-at.bofh.it>
In reply to#1397774

[Multipart message — attachments visible in raw view] — view raw

Hi,

Roger Quadros <rogerq@ti.com> writes:
> On 10/05/16 06:14, Peter Chen wrote:
>> On Mon, May 09, 2016 at 12:45:38PM +0300, Roger Quadros wrote:
>>> On 06/05/16 12:41, Peter Chen wrote:
>>>> On Mon, May 02, 2016 at 03:18:46PM +0300, Roger Quadros wrote:
>>>>> The OTG core will use struct otg_hcd_ops to interface
>>>>> with the HCD controller.
>>>>>
>>>>> The main purpose of this interface is to avoid directly
>>>>> calling HCD APIs from the OTG core as they
>>>>> wouldn't be defined in the built-in symbol table if
>>>>> CONFIG_USB is m.
>>>>>
>>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>>> Acked-by: Peter Chen <peter.chen@nxp.com>
>>>>
>>>> Roger, after thinking more, I still think current dependency between
>>>> OTG, HCD and gadget are too complicated. Since the OTG can't work
>>>> if it is built as module, I suggest letting OTG depends on HCD &&
>>>> USB_GADGET, and it is a boolean, in that case, we don't need to
>>>> export any HCD and gadget ops, things will be much simpler.
>>>> What's your opinion?
>>>
>>> How will it work if HCD and USB_GADGET are modules and OTG is built-in?
>>>
>> 
>> The OTG will not be compiled at this situation, since it is boolean.
>> In fact, like I mentioned at above, OTG or USB function can't work if
>> it is built as module.
>
> Isn't this a limitation?

I agree, it should work built-in or module.

> As per the current implementation dual role works fine even with both
> USB_GADGET and HCD as module.
>
> In the real world it is unlikely that GADGET and HCD will be built-in.

we can't make this assumption, however :-)

-- 
balbi

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


#1397880 — Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface

FromRoger Quadros <rogerq@ti.com>
Date2016-05-10 11:20 +0200
SubjectRe: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
Message-ID<rxbZD-7Z2-11@gated-at.bofh.it>
In reply to#1397826
On 10/05/16 11:12, Felipe Balbi wrote:
> 
> Hi,
> 
> Roger Quadros <rogerq@ti.com> writes:
>> On 10/05/16 06:14, Peter Chen wrote:
>>> On Mon, May 09, 2016 at 12:45:38PM +0300, Roger Quadros wrote:
>>>> On 06/05/16 12:41, Peter Chen wrote:
>>>>> On Mon, May 02, 2016 at 03:18:46PM +0300, Roger Quadros wrote:
>>>>>> The OTG core will use struct otg_hcd_ops to interface
>>>>>> with the HCD controller.
>>>>>>
>>>>>> The main purpose of this interface is to avoid directly
>>>>>> calling HCD APIs from the OTG core as they
>>>>>> wouldn't be defined in the built-in symbol table if
>>>>>> CONFIG_USB is m.
>>>>>>
>>>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>>>> Acked-by: Peter Chen <peter.chen@nxp.com>
>>>>>
>>>>> Roger, after thinking more, I still think current dependency between
>>>>> OTG, HCD and gadget are too complicated. Since the OTG can't work
>>>>> if it is built as module, I suggest letting OTG depends on HCD &&
>>>>> USB_GADGET, and it is a boolean, in that case, we don't need to
>>>>> export any HCD and gadget ops, things will be much simpler.
>>>>> What's your opinion?
>>>>
>>>> How will it work if HCD and USB_GADGET are modules and OTG is built-in?
>>>>
>>>
>>> The OTG will not be compiled at this situation, since it is boolean.
>>> In fact, like I mentioned at above, OTG or USB function can't work if
>>> it is built as module.
>>
>> Isn't this a limitation?
> 
> I agree, it should work built-in or module.
> 
>> As per the current implementation dual role works fine even with both
>> USB_GADGET and HCD as module.
>>
>> In the real world it is unlikely that GADGET and HCD will be built-in.
> 
> we can't make this assumption, however :-)
> 
Agreed, we need to make sure it works with all combinations.

cheers,
-roger

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


#1397832 — RE: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface

FromJun Li <jun.li@nxp.com>
Date2016-05-10 10:20 +0200
SubjectRE: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
Message-ID<rxb3A-70Q-25@gated-at.bofh.it>
In reply to#1397774
Hi

> -----Original Message-----
> From: Roger Quadros [mailto:rogerq@ti.com]
> Sent: Tuesday, May 10, 2016 3:35 PM
> To: Peter Chen <hzpeterchen@gmail.com>
> Cc: peter.chen@freescale.com; stern@rowland.harvard.edu; balbi@kernel.org;
> gregkh@linuxfoundation.org; dan.j.williams@intel.com; jun.li@freescale.com;
> mathias.nyman@linux.intel.com; tony@atomide.com; Joao.Pinto@synopsys.com;
> abrestic@chromium.org; yoshihiro.shimoda.uh@renesas.com; linux-
> usb@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> omap@vger.kernel.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
> 
> On 10/05/16 06:14, Peter Chen wrote:
> > On Mon, May 09, 2016 at 12:45:38PM +0300, Roger Quadros wrote:
> >> On 06/05/16 12:41, Peter Chen wrote:
> >>> On Mon, May 02, 2016 at 03:18:46PM +0300, Roger Quadros wrote:
> >>>> The OTG core will use struct otg_hcd_ops to interface with the HCD
> >>>> controller.
> >>>>
> >>>> The main purpose of this interface is to avoid directly calling HCD
> >>>> APIs from the OTG core as they wouldn't be defined in the built-in
> >>>> symbol table if CONFIG_USB is m.
> >>>>
> >>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
> >>>> Acked-by: Peter Chen <peter.chen@nxp.com>
> >>>
> >>> Roger, after thinking more, I still think current dependency between
> >>> OTG, HCD and gadget are too complicated. Since the OTG can't work if
> >>> it is built as module, I suggest letting OTG depends on HCD &&
> >>> USB_GADGET, and it is a boolean, in that case, we don't need to
> >>> export any HCD and gadget ops, things will be much simpler.
> >>> What's your opinion?
> >>
> >> How will it work if HCD and USB_GADGET are modules and OTG is built-in?
> >>
> >
> > The OTG will not be compiled at this situation, since it is boolean.
> > In fact, like I mentioned at above, OTG or USB function can't work if
> > it is built as module.
> 
> Isn't this a limitation?
> As per the current implementation dual role works fine even with both
> USB_GADGET and HCD as module.

My understand: only make sense for pass build, host can't work before
gadget modules loaded; gadget can't work before hcd loaded, nothing
can work before all drivers are loaded.

> 
> In the real world it is unlikely that GADGET and HCD will be built-in.

Why? User enable USB_OTG means both drivers should be enabled anyway.
Even in non-OTG case, both may be built-in for machine with 2 ports
(one port is host only, the other one is peripheral only).

A general question, 2 drivers depends on each other, allowable?

> 
> cheers,
> -roger
> 
> >
> > Peter
> >> cheers,
> >> -roger
> >>
> >>>
> >>> Peter
> >>>
> >>>> ---
> >>>>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
> >>>>  1 file changed, 24 insertions(+)
> >>>>
> >>>> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> >>>> index b98f831..861ccaa 100644
> >>>> --- a/include/linux/usb/hcd.h
> >>>> +++ b/include/linux/usb/hcd.h
> >>>> @@ -399,6 +399,30 @@ struct hc_driver {
> >>>>
> >>>>  };
> >>>>
> >>>> +/**
> >>>> + * struct otg_hcd_ops - Interface between OTG core and HCD
> >>>> + *
> >>>> + * Provided by the HCD core to allow the OTG core to interface
> >>>> +with the HCD
> >>>> + *
> >>>> + * @add: function to add the HCD
> >>>> + * @remove: function to remove the HCD
> >>>> + * @usb_bus_start_enum: function to immediately start bus
> >>>> +enumeration
> >>>> + * @usb_control_msg: function to build and send of a control urb
> >>>> + * @usb_hub_find_child: function to get pointer to the child
> >>>> +device  */ struct otg_hcd_ops {
> >>>> +	int (*add)(struct usb_hcd *hcd,
> >>>> +		   unsigned int irqnum, unsigned long irqflags);
> >>>> +	void (*remove)(struct usb_hcd *hcd);
> >>>> +	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int
> port_num);
> >>>> +	int (*usb_control_msg)(struct usb_device *dev, unsigned int
> pipe,
> >>>> +			       __u8 request, __u8 requesttype, __u16 value,
> >>>> +			       __u16 index, void *data, __u16 size,
> >>>> +			       int timeout);
> >>>> +	struct usb_device * (*usb_hub_find_child)(struct usb_device
> *hdev,
> >>>> +						  int port1);
> >>>> +};
> >>>> +
> >>>>  static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)  {
> >>>>  	return hcd->driver->flags & HCD_BH;
> >>>> --
> >>>> 2.7.4
> >>>>
> >>>> --
> >>>> To unsubscribe from this list: send the line "unsubscribe
> >>>> linux-usb" in the body of a message to majordomo@vger.kernel.org
> >>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>>
> >

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


#1397889 — Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface

FromRoger Quadros <rogerq@ti.com>
Date2016-05-10 11:30 +0200
SubjectRe: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
Message-ID<rxc9j-84z-5@gated-at.bofh.it>
In reply to#1397832
On 10/05/16 11:03, Jun Li wrote:
> Hi
> 
>> -----Original Message-----
>> From: Roger Quadros [mailto:rogerq@ti.com]
>> Sent: Tuesday, May 10, 2016 3:35 PM
>> To: Peter Chen <hzpeterchen@gmail.com>
>> Cc: peter.chen@freescale.com; stern@rowland.harvard.edu; balbi@kernel.org;
>> gregkh@linuxfoundation.org; dan.j.williams@intel.com; jun.li@freescale.com;
>> mathias.nyman@linux.intel.com; tony@atomide.com; Joao.Pinto@synopsys.com;
>> abrestic@chromium.org; yoshihiro.shimoda.uh@renesas.com; linux-
>> usb@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
>> omap@vger.kernel.org; devicetree@vger.kernel.org
>> Subject: Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
>>
>> On 10/05/16 06:14, Peter Chen wrote:
>>> On Mon, May 09, 2016 at 12:45:38PM +0300, Roger Quadros wrote:
>>>> On 06/05/16 12:41, Peter Chen wrote:
>>>>> On Mon, May 02, 2016 at 03:18:46PM +0300, Roger Quadros wrote:
>>>>>> The OTG core will use struct otg_hcd_ops to interface with the HCD
>>>>>> controller.
>>>>>>
>>>>>> The main purpose of this interface is to avoid directly calling HCD
>>>>>> APIs from the OTG core as they wouldn't be defined in the built-in
>>>>>> symbol table if CONFIG_USB is m.
>>>>>>
>>>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>>>>>> Acked-by: Peter Chen <peter.chen@nxp.com>
>>>>>
>>>>> Roger, after thinking more, I still think current dependency between
>>>>> OTG, HCD and gadget are too complicated. Since the OTG can't work if
>>>>> it is built as module, I suggest letting OTG depends on HCD &&
>>>>> USB_GADGET, and it is a boolean, in that case, we don't need to
>>>>> export any HCD and gadget ops, things will be much simpler.
>>>>> What's your opinion?
>>>>
>>>> How will it work if HCD and USB_GADGET are modules and OTG is built-in?
>>>>
>>>
>>> The OTG will not be compiled at this situation, since it is boolean.
>>> In fact, like I mentioned at above, OTG or USB function can't work if
>>> it is built as module.
>>
>> Isn't this a limitation?
>> As per the current implementation dual role works fine even with both
>> USB_GADGET and HCD as module.
> 
> My understand: only make sense for pass build, host can't work before
> gadget modules loaded; gadget can't work before hcd loaded, nothing
> can work before all drivers are loaded.

I can make OTG depend on GADGET and HCD, no issue with that.
But we can't get rid of the OTG to HCD/Gadged interfaces as we want things
to work with GADGET and HCD as modules.

> 
>>
>> In the real world it is unlikely that GADGET and HCD will be built-in.
> 
> Why? User enable USB_OTG means both drivers should be enabled anyway.

Enabled, but not necessarily built-in. Most distributions don't have them
as built-in.

But let's not argue in that direction. Let's say that they can be either
built-in or modules.

> Even in non-OTG case, both may be built-in for machine with 2 ports
> (one port is host only, the other one is peripheral only).

Sure. Every system designer is free to select the configuration.

> 
> A general question, 2 drivers depends on each other, allowable?

I don't thing that's possible. Kconfig will complain.
http://lxr.free-electrons.com/source/Documentation/kbuild/kconfig-language.txt#L397

cheers,
-roger

>>>>>
>>>>>> ---
>>>>>>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
>>>>>>  1 file changed, 24 insertions(+)
>>>>>>
>>>>>> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
>>>>>> index b98f831..861ccaa 100644
>>>>>> --- a/include/linux/usb/hcd.h
>>>>>> +++ b/include/linux/usb/hcd.h
>>>>>> @@ -399,6 +399,30 @@ struct hc_driver {
>>>>>>
>>>>>>  };
>>>>>>
>>>>>> +/**
>>>>>> + * struct otg_hcd_ops - Interface between OTG core and HCD
>>>>>> + *
>>>>>> + * Provided by the HCD core to allow the OTG core to interface
>>>>>> +with the HCD
>>>>>> + *
>>>>>> + * @add: function to add the HCD
>>>>>> + * @remove: function to remove the HCD
>>>>>> + * @usb_bus_start_enum: function to immediately start bus
>>>>>> +enumeration
>>>>>> + * @usb_control_msg: function to build and send of a control urb
>>>>>> + * @usb_hub_find_child: function to get pointer to the child
>>>>>> +device  */ struct otg_hcd_ops {
>>>>>> +	int (*add)(struct usb_hcd *hcd,
>>>>>> +		   unsigned int irqnum, unsigned long irqflags);
>>>>>> +	void (*remove)(struct usb_hcd *hcd);
>>>>>> +	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int
>> port_num);
>>>>>> +	int (*usb_control_msg)(struct usb_device *dev, unsigned int
>> pipe,
>>>>>> +			       __u8 request, __u8 requesttype, __u16 value,
>>>>>> +			       __u16 index, void *data, __u16 size,
>>>>>> +			       int timeout);
>>>>>> +	struct usb_device * (*usb_hub_find_child)(struct usb_device
>> *hdev,
>>>>>> +						  int port1);
>>>>>> +};
>>>>>> +
>>>>>>  static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)  {
>>>>>>  	return hcd->driver->flags & HCD_BH;
>>>>>> --
>>>>>> 2.7.4
>>>>>>
>>>>>> --
>>>>>> To unsubscribe from this list: send the line "unsubscribe
>>>>>> linux-usb" in the body of a message to majordomo@vger.kernel.org
>>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>>
>>>

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


#1398709 — Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface

FromPeter Chen <hzpeterchen@gmail.com>
Date2016-05-11 08:30 +0200
SubjectRe: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
Message-ID<rxvOG-2AY-7@gated-at.bofh.it>
In reply to#1397889
On Tue, May 10, 2016 at 12:20:28PM +0300, Roger Quadros wrote:
> On 10/05/16 11:03, Jun Li wrote:
> > Hi
> > 
> >> -----Original Message-----
> >> From: Roger Quadros [mailto:rogerq@ti.com]
> >> Sent: Tuesday, May 10, 2016 3:35 PM
> >> To: Peter Chen <hzpeterchen@gmail.com>
> >> Cc: peter.chen@freescale.com; stern@rowland.harvard.edu; balbi@kernel.org;
> >> gregkh@linuxfoundation.org; dan.j.williams@intel.com; jun.li@freescale.com;
> >> mathias.nyman@linux.intel.com; tony@atomide.com; Joao.Pinto@synopsys.com;
> >> abrestic@chromium.org; yoshihiro.shimoda.uh@renesas.com; linux-
> >> usb@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> >> omap@vger.kernel.org; devicetree@vger.kernel.org
> >> Subject: Re: [PATCH v7 03/14] usb: hcd.h: Add OTG to HCD interface
> >>
> >> On 10/05/16 06:14, Peter Chen wrote:
> >>> On Mon, May 09, 2016 at 12:45:38PM +0300, Roger Quadros wrote:
> >>>> On 06/05/16 12:41, Peter Chen wrote:
> >>>>> On Mon, May 02, 2016 at 03:18:46PM +0300, Roger Quadros wrote:
> >>>>>> The OTG core will use struct otg_hcd_ops to interface with the HCD
> >>>>>> controller.
> >>>>>>
> >>>>>> The main purpose of this interface is to avoid directly calling HCD
> >>>>>> APIs from the OTG core as they wouldn't be defined in the built-in
> >>>>>> symbol table if CONFIG_USB is m.
> >>>>>>
> >>>>>> Signed-off-by: Roger Quadros <rogerq@ti.com>
> >>>>>> Acked-by: Peter Chen <peter.chen@nxp.com>
> >>>>>
> >>>>> Roger, after thinking more, I still think current dependency between
> >>>>> OTG, HCD and gadget are too complicated. Since the OTG can't work if
> >>>>> it is built as module, I suggest letting OTG depends on HCD &&
> >>>>> USB_GADGET, and it is a boolean, in that case, we don't need to
> >>>>> export any HCD and gadget ops, things will be much simpler.
> >>>>> What's your opinion?
> >>>>
> >>>> How will it work if HCD and USB_GADGET are modules and OTG is built-in?
> >>>>
> >>>
> >>> The OTG will not be compiled at this situation, since it is boolean.
> >>> In fact, like I mentioned at above, OTG or USB function can't work if
> >>> it is built as module.
> >>
> >> Isn't this a limitation?
> >> As per the current implementation dual role works fine even with both
> >> USB_GADGET and HCD as module.
> > 
> > My understand: only make sense for pass build, host can't work before
> > gadget modules loaded; gadget can't work before hcd loaded, nothing
> > can work before all drivers are loaded.
> 
> I can make OTG depend on GADGET and HCD, no issue with that.
> But we can't get rid of the OTG to HCD/Gadged interfaces as we want things
> to work with GADGET and HCD as modules.
> 

Let's make OTG depends on gadget and hcd at Kconfig, and keep others
unchanging, if no one objects it.

Peter
> > 
> >>
> >> In the real world it is unlikely that GADGET and HCD will be built-in.
> > 
> > Why? User enable USB_OTG means both drivers should be enabled anyway.
> 
> Enabled, but not necessarily built-in. Most distributions don't have them
> as built-in.
> 
> But let's not argue in that direction. Let's say that they can be either
> built-in or modules.
> 
> > Even in non-OTG case, both may be built-in for machine with 2 ports
> > (one port is host only, the other one is peripheral only).
> 
> Sure. Every system designer is free to select the configuration.
> 
> > 
> > A general question, 2 drivers depends on each other, allowable?
> 
> I don't thing that's possible. Kconfig will complain.
> http://lxr.free-electrons.com/source/Documentation/kbuild/kconfig-language.txt#L397
> 
> cheers,
> -roger
> 
> >>>>>
> >>>>>> ---
> >>>>>>  include/linux/usb/hcd.h | 24 ++++++++++++++++++++++++
> >>>>>>  1 file changed, 24 insertions(+)
> >>>>>>
> >>>>>> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> >>>>>> index b98f831..861ccaa 100644
> >>>>>> --- a/include/linux/usb/hcd.h
> >>>>>> +++ b/include/linux/usb/hcd.h
> >>>>>> @@ -399,6 +399,30 @@ struct hc_driver {
> >>>>>>
> >>>>>>  };
> >>>>>>
> >>>>>> +/**
> >>>>>> + * struct otg_hcd_ops - Interface between OTG core and HCD
> >>>>>> + *
> >>>>>> + * Provided by the HCD core to allow the OTG core to interface
> >>>>>> +with the HCD
> >>>>>> + *
> >>>>>> + * @add: function to add the HCD
> >>>>>> + * @remove: function to remove the HCD
> >>>>>> + * @usb_bus_start_enum: function to immediately start bus
> >>>>>> +enumeration
> >>>>>> + * @usb_control_msg: function to build and send of a control urb
> >>>>>> + * @usb_hub_find_child: function to get pointer to the child
> >>>>>> +device  */ struct otg_hcd_ops {
> >>>>>> +	int (*add)(struct usb_hcd *hcd,
> >>>>>> +		   unsigned int irqnum, unsigned long irqflags);
> >>>>>> +	void (*remove)(struct usb_hcd *hcd);
> >>>>>> +	int (*usb_bus_start_enum)(struct usb_bus *bus, unsigned int
> >> port_num);
> >>>>>> +	int (*usb_control_msg)(struct usb_device *dev, unsigned int
> >> pipe,
> >>>>>> +			       __u8 request, __u8 requesttype, __u16 value,
> >>>>>> +			       __u16 index, void *data, __u16 size,
> >>>>>> +			       int timeout);
> >>>>>> +	struct usb_device * (*usb_hub_find_child)(struct usb_device
> >> *hdev,
> >>>>>> +						  int port1);
> >>>>>> +};
> >>>>>> +
> >>>>>>  static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)  {
> >>>>>>  	return hcd->driver->flags & HCD_BH;
> >>>>>> --
> >>>>>> 2.7.4
> >>>>>>
> >>>>>> --
> >>>>>> To unsubscribe from this list: send the line "unsubscribe
> >>>>>> linux-usb" in the body of a message to majordomo@vger.kernel.org
> >>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>>>>
> >>>

-- 

Best Regards,
Peter Chen

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


#1392174 — [PATCH v7 12/14] usb: hcd: Adapt to OTG core

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 12/14] usb: hcd: Adapt to OTG core
Message-ID<rul98-3f2-23@gated-at.bofh.it>
In reply to#1392163
Introduce usb_otg_add/remove_hcd() for use by host
controllers that are part of OTG/dual-role port.

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

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

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

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


#1398807 — Re: [PATCH v7 12/14] usb: hcd: Adapt to OTG core

FromPeter Chen <hzpeterchen@gmail.com>
Date2016-05-11 11:10 +0200
SubjectRe: [PATCH v7 12/14] usb: hcd: Adapt to OTG core
Message-ID<rxyjw-58a-15@gated-at.bofh.it>
In reply to#1392174
On Mon, May 02, 2016 at 03:18:55PM +0300, Roger Quadros wrote:
> Introduce usb_otg_add/remove_hcd() for use by host
> controllers that are part of OTG/dual-role port.
> 
> Non Device tree platforms can use the otg_dev argument
> to specify the OTG controller device. If otg_dev is NULL
> then the device tree node's otg-controller property is used to
> get the otg_dev device.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>

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

> ---
>  drivers/usb/core/hcd.c  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/hcd.h |  4 ++++
>  2 files changed, 59 insertions(+)
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index 9484539..cfc8232 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -46,6 +46,11 @@
>  #include <linux/usb.h>
>  #include <linux/usb/hcd.h>
>  #include <linux/usb/phy.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/of.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
>  
>  #include "usb.h"
>  
> @@ -3013,6 +3018,56 @@ void usb_remove_hcd(struct usb_hcd *hcd)
>  }
>  EXPORT_SYMBOL_GPL(usb_remove_hcd);
>  
> +static struct otg_hcd_ops otg_hcd_intf = {
> +	.add = usb_add_hcd,
> +	.remove = usb_remove_hcd,
> +	.usb_bus_start_enum = usb_bus_start_enum,
> +	.usb_control_msg = usb_control_msg,
> +	.usb_hub_find_child = usb_hub_find_child,
> +};
> +
> +/**
> + * usb_otg_add_hcd - Register the HCD with OTG core.
> + * @hcd: the usb_hcd structure to initialize
> + * @irqnum: Interrupt line to allocate
> + * @irqflags: Interrupt type flags
> + * @otg_dev: OTG controller device managing this HCD
> + *
> + * Registers the HCD with OTG core. OTG core will call usb_add_hcd()
> + * or usb_remove_hcd() as necessary.
> + * If otg_dev is NULL then device tree node is checked for OTG
> + * controller device via the otg-controller property.
> + */
> +int usb_otg_add_hcd(struct usb_hcd *hcd,
> +		    unsigned int irqnum, unsigned long irqflags,
> +		    struct device *otg_dev)
> +{
> +	struct device *dev = hcd->self.controller;
> +
> +	if (!otg_dev) {
> +		hcd->otg_dev = of_usb_get_otg(dev->of_node);
> +		if (!hcd->otg_dev)
> +			return -ENODEV;
> +	} else {
> +		hcd->otg_dev = otg_dev;
> +	}
> +
> +	return usb_otg_register_hcd(hcd, irqnum, irqflags, &otg_hcd_intf);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_add_hcd);
> +
> +/**
> + * usb_otg_remove_hcd - Unregister the HCD with OTG core.
> + * @hcd: the usb_hcd structure to remove
> + *
> + * Unregisters the HCD from the OTG core.
> + */
> +void usb_otg_remove_hcd(struct usb_hcd *hcd)
> +{
> +	usb_otg_unregister_hcd(hcd);
> +}
> +EXPORT_SYMBOL_GPL(usb_otg_remove_hcd);
> +
>  void
>  usb_hcd_platform_shutdown(struct platform_device *dev)
>  {
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 2017cd4..adcf2e7 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -472,6 +472,10 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
>  extern int usb_add_hcd(struct usb_hcd *hcd,
>  		unsigned int irqnum, unsigned long irqflags);
>  extern void usb_remove_hcd(struct usb_hcd *hcd);
> +extern int usb_otg_add_hcd(struct usb_hcd *hcd,
> +			   unsigned int irqnum, unsigned long irqflags,
> +			   struct device *otg_dev);
> +extern void usb_otg_remove_hcd(struct usb_hcd *hcd);
>  extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
>  
>  struct platform_device;
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 

Best Regards,
Peter Chen

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


#1392175 — [PATCH v7 01/14] usb: hcd: Initialize hcd->flags to 0

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 01/14] usb: hcd: Initialize hcd->flags to 0
Message-ID<rul98-3f2-31@gated-at.bofh.it>
In reply to#1392163
When using the OTG/drd library we can call hcd_add/remove
consecutively without calling usb_put_hcd/usb_create_hcd in between
so hcd->flags can be stale.

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

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

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

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

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


#1395734 — Re: [PATCH v7 01/14] usb: hcd: Initialize hcd->flags to 0

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

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

-- 

Best Regards,
Peter Chen

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


#1392176 — [PATCH v7 06/14] usb: gadget.h: Add OTG to gadget interface

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 06/14] usb: gadget.h: Add OTG to gadget interface
Message-ID<rul99-3f2-37@gated-at.bofh.it>
In reply to#1392163
The OTG core will use struct otg_gadget_ops to
start/stop the gadget controller.

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

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

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

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


#1392177 — [PATCH v7 08/14] usb: otg: add OTG/dual-role core

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 08/14] usb: otg: add OTG/dual-role core
Message-ID<rul98-3f2-19@gated-at.bofh.it>
In reply to#1392163
It provides APIs for the following tasks

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

Provide a dual-role device (DRD) state machine.
DRD mode is a reduced functionality OTG mode. In this mode
we don't support SRP, HNP and dynamic role-swap.

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

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

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/usb/common/Makefile  |    2 +-
 drivers/usb/common/usb-otg.c | 1040 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/common/usb-otg.h |   71 +++
 drivers/usb/core/Kconfig     |    2 +-
 include/linux/usb/gadget.h   |    2 +
 include/linux/usb/hcd.h      |    1 +
 include/linux/usb/otg-fsm.h  |    7 +
 include/linux/usb/otg.h      |  154 ++++++-
 8 files changed, 1274 insertions(+), 5 deletions(-)
 create mode 100644 drivers/usb/common/usb-otg.c
 create mode 100644 drivers/usb/common/usb-otg.h

diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index f8f2c88..730d928 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,5 +7,5 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_ULPI_BUS)	+= ulpi.o
-usbotg-y		:= usb-otg-fsm.o
+usbotg-y		:= usb-otg.o usb-otg-fsm.o
 obj-$(CONFIG_USB_OTG)	+= usbotg.o
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
new file mode 100644
index 0000000..702bca8
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,1040 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+#include "usb-otg.h"
+
+struct otg_gcd {
+	struct usb_gadget *gadget;
+	struct otg_gadget_ops *ops;
+};
+
+/* OTG device list */
+LIST_HEAD(otg_list);
+static DEFINE_MUTEX(otg_list_mutex);
+
+/* Hosts and Gadgets waiting for OTG controller */
+struct otg_wait_data {
+	struct device *dev;		/* OTG controller device */
+
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gcd gcd;
+	struct list_head list;
+};
+
+LIST_HEAD(wait_list);
+static DEFINE_MUTEX(wait_list_mutex);
+
+static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
+{
+	if (!hcd->primary_hcd)
+		return 1;
+	return hcd == hcd->primary_hcd;
+}
+
+/**
+ * Check if the OTG device is in our wait list and return
+ * otg_wait_data, else NULL.
+ *
+ * wait_list_mutex must be held.
+ */
+static struct otg_wait_data *usb_otg_get_wait(struct device *otg_dev)
+{
+	struct otg_wait_data *wait;
+
+	if (!otg_dev)
+		return NULL;
+
+	/* is there an entry for this otg_dev ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->dev == otg_dev)
+			return wait;
+	}
+
+	return NULL;
+}
+
+/**
+ * Add the hcd to our wait list
+ */
+static int usb_otg_hcd_wait_add(struct device *otg_dev, struct usb_hcd *hcd,
+				unsigned int irqnum, unsigned long irqflags,
+				struct otg_hcd_ops *ops)
+{
+	struct otg_wait_data *wait;
+	int ret = -EINVAL;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait) {
+		/* Not yet in wait list? allocate and add */
+		wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+		if (!wait) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		wait->dev = otg_dev;
+		list_add_tail(&wait->list, &wait_list);
+	}
+
+	if (usb_otg_hcd_is_primary_hcd(hcd)) {
+		if (wait->primary_hcd.hcd)	/* already assigned? */
+			goto fail;
+
+		wait->primary_hcd.hcd = hcd;
+		wait->primary_hcd.irqnum = irqnum;
+		wait->primary_hcd.irqflags = irqflags;
+		wait->primary_hcd.ops = ops;
+		wait->primary_hcd.otg_dev = otg_dev;
+	} else {
+		if (wait->shared_hcd.hcd)	/* already assigned? */
+			goto fail;
+
+		wait->shared_hcd.hcd = hcd;
+		wait->shared_hcd.irqnum = irqnum;
+		wait->shared_hcd.irqflags = irqflags;
+		wait->shared_hcd.ops = ops;
+		wait->shared_hcd.otg_dev = otg_dev;
+	}
+
+	mutex_unlock(&wait_list_mutex);
+	return 0;
+
+fail:
+	mutex_unlock(&wait_list_mutex);
+	return ret;
+}
+
+/**
+ * Check and free wait list entry if empty
+ *
+ * wait_list_mutex must be held
+ */
+static void usb_otg_check_free_wait(struct otg_wait_data *wait)
+{
+	if (wait->primary_hcd.hcd || wait->shared_hcd.hcd || wait->gcd.gadget)
+		return;
+
+	list_del(&wait->list);
+	kfree(wait);
+}
+
+/**
+ * Remove the hcd from our wait list
+ */
+static int usb_otg_hcd_wait_remove(struct usb_hcd *hcd)
+{
+	struct otg_wait_data *wait;
+
+	mutex_lock(&wait_list_mutex);
+
+	/* is there an entry for this hcd ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->primary_hcd.hcd == hcd) {
+			wait->primary_hcd.hcd = 0;
+			goto found;
+		} else if (wait->shared_hcd.hcd == hcd) {
+			wait->shared_hcd.hcd = 0;
+			goto found;
+		}
+	}
+
+	mutex_unlock(&wait_list_mutex);
+	return -EINVAL;
+
+found:
+	usb_otg_check_free_wait(wait);
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+}
+
+/**
+ * Add the gadget to our wait list
+ */
+static int usb_otg_gadget_wait_add(struct device *otg_dev,
+				   struct usb_gadget *gadget,
+				   struct otg_gadget_ops *ops)
+{
+	struct otg_wait_data *wait;
+	int ret = -EINVAL;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait) {
+		/* Not yet in wait list? allocate and add */
+		wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+		if (!wait) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		wait->dev = otg_dev;
+		list_add_tail(&wait->list, &wait_list);
+	}
+
+	if (wait->gcd.gadget) /* already assigned? */
+		goto fail;
+
+	wait->gcd.gadget = gadget;
+	wait->gcd.ops = ops;
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+
+fail:
+	mutex_unlock(&wait_list_mutex);
+	return ret;
+}
+
+/**
+ * Remove the gadget from our wait list
+ */
+static int usb_otg_gadget_wait_remove(struct usb_gadget *gadget)
+{
+	struct otg_wait_data *wait;
+
+	mutex_lock(&wait_list_mutex);
+
+	/* is there an entry for this gadget ?*/
+	list_for_each_entry(wait, &wait_list, list) {
+		if (wait->gcd.gadget == gadget) {
+			wait->gcd.gadget = 0;
+			goto found;
+		}
+	}
+
+	mutex_unlock(&wait_list_mutex);
+
+	return -EINVAL;
+
+found:
+	usb_otg_check_free_wait(wait);
+	mutex_unlock(&wait_list_mutex);
+
+	return 0;
+}
+
+/**
+ * Register pending host/gadget and remove entry from wait list
+ */
+static void usb_otg_flush_wait(struct device *otg_dev)
+{
+	struct otg_wait_data *wait;
+	struct otg_hcd *whcd;
+	struct otg_gcd *wgcd;
+
+	mutex_lock(&wait_list_mutex);
+
+	wait = usb_otg_get_wait(otg_dev);
+	if (!wait)
+		goto done;
+
+	dev_dbg(otg_dev, "otg: registering pending host/gadget\n");
+	wgcd = &wait->gcd;
+	if (wgcd->gadget)
+		usb_otg_register_gadget(wgcd->gadget, wgcd->ops);
+
+	whcd = &wait->primary_hcd;
+	if (whcd->hcd)
+		usb_otg_register_hcd(whcd->hcd, whcd->irqnum, whcd->irqflags,
+				     whcd->ops);
+
+	whcd = &wait->shared_hcd;
+	if (whcd->hcd)
+		usb_otg_register_hcd(whcd->hcd, whcd->irqnum, whcd->irqflags,
+				     whcd->ops);
+
+	list_del(&wait->list);
+	kfree(wait);
+
+done:
+	mutex_unlock(&wait_list_mutex);
+}
+
+/**
+ * Check if the OTG device is in our OTG list and return
+ * usb_otg data, else NULL.
+ *
+ * otg_list_mutex must be held.
+ */
+static struct usb_otg *usb_otg_get_data(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	if (!otg_dev)
+		return NULL;
+
+	list_for_each_entry(otg, &otg_list, list) {
+		if (otg->dev == otg_dev)
+			return otg;
+	}
+
+	return NULL;
+}
+
+/**
+ * usb_otg_start_host - start/stop the host controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB host controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct otg_hcd_ops *hcd_ops = otg->hcd_ops;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!otg->host) {
+		WARN_ONCE(1, "otg: fsm running without host\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_HOST_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_HOST_RUNNING;
+
+		/* start host */
+		hcd_ops->add(otg->primary_hcd.hcd, otg->primary_hcd.irqnum,
+			     otg->primary_hcd.irqflags);
+		if (otg->shared_hcd.hcd) {
+			hcd_ops->add(otg->shared_hcd.hcd,
+				     otg->shared_hcd.irqnum,
+				     otg->shared_hcd.irqflags);
+		}
+	} else {
+		if (!(otg->flags & OTG_FLAG_HOST_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_HOST_RUNNING;
+
+		/* stop host */
+		if (otg->shared_hcd.hcd)
+			hcd_ops->remove(otg->shared_hcd.hcd);
+
+		hcd_ops->remove(otg->primary_hcd.hcd);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_host);
+
+/**
+ * usb_otg_start_gadget - start/stop the gadget controller
+ * @otg:	usb_otg instance
+ * @on:		true to start, false to stop
+ *
+ * Start/stop the USB gadget controller. This function is meant
+ * for use by the OTG controller driver.
+ */
+int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	struct usb_gadget *gadget = otg->gadget;
+
+	dev_dbg(otg->dev, "otg: %s %d\n", __func__, on);
+	if (!gadget) {
+		WARN_ONCE(1, "otg: fsm running without gadget\n");
+		return 0;
+	}
+
+	if (on) {
+		if (otg->flags & OTG_FLAG_GADGET_RUNNING)
+			return 0;
+
+		otg->flags |= OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->start(otg->gadget);
+	} else {
+		if (!(otg->flags & OTG_FLAG_GADGET_RUNNING))
+			return 0;
+
+		otg->flags &= ~OTG_FLAG_GADGET_RUNNING;
+		otg->gadget_ops->stop(otg->gadget);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_start_gadget);
+
+/**
+ * Change USB protocol when there is a protocol change.
+ * fsm->lock must be held.
+ */
+static int drd_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+	int ret = 0;
+
+	if (fsm->protocol != protocol) {
+		dev_dbg(otg->dev, "otg: changing role fsm->protocol= %d; new protocol= %d\n",
+			fsm->protocol, protocol);
+		/* stop old protocol */
+		if (fsm->protocol == PROTO_HOST)
+			ret = otg_start_host(otg, 0);
+		else if (fsm->protocol == PROTO_GADGET)
+			ret = otg_start_gadget(otg, 0);
+		if (ret)
+			return ret;
+
+		/* start new protocol */
+		if (protocol == PROTO_HOST)
+			ret = otg_start_host(otg, 1);
+		else if (protocol == PROTO_GADGET)
+			ret = otg_start_gadget(otg, 1);
+		if (ret)
+			return ret;
+
+		fsm->protocol = protocol;
+		return 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Called when entering a DRD state.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+	struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+	if (otg->state == new_state)
+		return;
+
+	fsm->state_changed = 1;
+	dev_dbg(otg->dev, "otg: set state: %s\n",
+		usb_otg_state_string(new_state));
+	switch (new_state) {
+	case OTG_STATE_B_IDLE:
+		drd_set_protocol(fsm, PROTO_UNDEF);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		drd_set_protocol(fsm, PROTO_GADGET);
+		otg_drv_vbus(otg, 0);
+		break;
+	case OTG_STATE_A_HOST:
+		drd_set_protocol(fsm, PROTO_HOST);
+		otg_drv_vbus(otg, 1);
+		break;
+	default:
+		dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+			 __func__, usb_otg_state_string(new_state));
+		break;
+	}
+
+	otg->state = new_state;
+}
+
+/**
+ * DRD state change judgement
+ *
+ * For DRD we're only interested in some of the OTG states
+ * i.e. OTG_STATE_B_IDLE: both peripheral and host are stopped
+ *	OTG_STATE_B_PERIPHERAL: peripheral active
+ *	OTG_STATE_A_HOST: host active
+ * we're only interested in the following inputs
+ *	fsm->id, fsm->b_sess_vld
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+	enum usb_otg_state state;
+	int ret;
+
+	mutex_lock(&fsm->lock);
+
+	fsm->state_changed = 0;
+	state = otg->state;
+
+	switch (state) {
+	case OTG_STATE_UNDEFINED:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (fsm->id && fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		else
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!fsm->id)
+			drd_set_state(fsm, OTG_STATE_A_HOST);
+		else if (!fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+	case OTG_STATE_A_HOST:
+		if (fsm->id && fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+		else if (fsm->id && !fsm->b_sess_vld)
+			drd_set_state(fsm, OTG_STATE_B_IDLE);
+		break;
+
+	default:
+		dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+			__func__, usb_otg_state_string(state));
+		break;
+	}
+
+	ret = fsm->state_changed;
+	mutex_unlock(&fsm->lock);
+	dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+		fsm->state_changed);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * Dual-role device (DRD) work function
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+	struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+	pm_runtime_get_sync(otg->dev);
+	drd_statemachine(otg);
+	pm_runtime_put_sync(otg->dev);
+}
+
+/**
+ * usb_otg_register() - Register the OTG/dual-role device to OTG core
+ * @dev: OTG/dual-role controller device.
+ * @config: OTG configuration.
+ *
+ * Registers the OTG/dual-role controller device with the USB OTG core.
+ *
+ * Return: struct usb_otg * if success, ERR_PTR() if error.
+ */
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config)
+{
+	struct usb_otg *otg;
+	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 */
+	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+	if (!otg) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	otg->dev = dev;
+	otg->caps = config->otg_caps;
+
+	if ((otg->caps->hnp_support || otg->caps->srp_support ||
+	     otg->caps->adp_support) && !config->otg_work) {
+		dev_err(dev,
+			"otg: otg_work must be provided for OTG support\n");
+		ret = -EINVAL;
+		goto err_wq;
+	}
+
+	if (config->otg_work)	/* custom otg_work ? */
+		INIT_WORK(&otg->work, config->otg_work);
+	else
+		INIT_WORK(&otg->work, usb_drd_work);
+
+	otg->wq = create_singlethread_workqueue("usb_otg");
+	if (!otg->wq) {
+		dev_err(dev, "otg: %s: can't create workqueue\n",
+			__func__);
+		ret = -ENOMEM;
+		goto err_wq;
+	}
+
+	/* set otg ops */
+	otg->fsm.ops = config->fsm_ops;
+
+	mutex_init(&otg->fsm.lock);
+
+	list_add_tail(&otg->list, &otg_list);
+	mutex_unlock(&otg_list_mutex);
+
+	/* 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 otg;
+
+err_wq:
+	kfree(otg);
+unlock:
+	mutex_unlock(&otg_list_mutex);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(usb_otg_register);
+
+/**
+ * usb_otg_unregister() - Unregister the OTG/dual-role device from USB OTG core
+ * @dev: OTG controller device.
+ *
+ * Unregisters the OTG/dual-role controller device from USB OTG core.
+ * Prevents unregistering till both the associated Host and Gadget controllers
+ * have unregistered from the OTG core.
+ *
+ * Return: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister(struct device *dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(dev);
+	if (!otg) {
+		dev_err(dev, "otg: %s: device not in otg list\n",
+			__func__);
+		mutex_unlock(&otg_list_mutex);
+		return -EINVAL;
+	}
+
+	/* prevent unregister till both host & gadget have unregistered */
+	if (otg->host || otg->gadget) {
+		dev_err(dev, "otg: %s: host/gadget still registered\n",
+			__func__);
+		return -EBUSY;
+	}
+
+	/* OTG FSM is halted when host/gadget unregistered */
+	destroy_workqueue(otg->wq);
+
+	/* remove from otg list */
+	list_del(&otg->list);
+	kfree(otg);
+	mutex_unlock(&otg_list_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister);
+
+/**
+ * start/kick the OTG FSM if we can
+ * fsm->lock must be held
+ */
+static void usb_otg_start_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (fsm->running)
+		goto kick_fsm;
+
+	if (!otg->host) {
+		dev_info(otg->dev, "otg: can't start till host registers\n");
+		return;
+	}
+
+	if (!otg->gadget) {
+		dev_info(otg->dev, "otg: can't start till gadget registers\n");
+		return;
+	}
+
+	fsm->running = true;
+kick_fsm:
+	queue_work(otg->wq, &otg->work);
+}
+
+/**
+ * stop the OTG FSM. Stops Host & Gadget controllers as well.
+ * fsm->lock must be held
+ */
+static void usb_otg_stop_fsm(struct usb_otg *otg)
+{
+	struct otg_fsm *fsm = &otg->fsm;
+
+	if (!fsm->running)
+		return;
+
+	/* no more new events queued */
+	fsm->running = false;
+
+	flush_workqueue(otg->wq);
+	otg->state = OTG_STATE_UNDEFINED;
+
+	/* stop host/gadget immediately */
+	if (fsm->protocol == PROTO_HOST)
+		otg_start_host(otg, 0);
+	else if (fsm->protocol == PROTO_GADGET)
+		otg_start_gadget(otg, 0);
+	fsm->protocol = PROTO_UNDEF;
+}
+
+/**
+ * usb_otg_sync_inputs - Sync OTG inputs with the OTG state machine
+ * @fsm:	OTG FSM instance
+ *
+ * Used by the OTG driver to update the inputs to the OTG
+ * state machine.
+ *
+ * Can be called in IRQ context.
+ */
+void usb_otg_sync_inputs(struct usb_otg *otg)
+{
+	/* Don't kick FSM till it has started */
+	if (!otg->fsm.running)
+		return;
+
+	/* Kick FSM */
+	queue_work(otg->wq, &otg->work);
+}
+EXPORT_SYMBOL_GPL(usb_otg_sync_inputs);
+
+/**
+ * usb_otg_kick_fsm - Kick the OTG state machine
+ * @otg_dev:	OTG controller device
+ *
+ * Used by USB host/device stack to sync OTG related
+ * events to the OTG state machine.
+ * e.g. change in host_bus->b_hnp_enable, gadget->b_hnp_enable
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	struct usb_otg *otg;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(otg_dev, "otg: %s: invalid otg device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	usb_otg_sync_inputs(otg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_kick_fsm);
+
+/**
+ * usb_otg_register_hcd - Register the host controller to OTG core
+ * @hcd:	host controller device
+ * @irqnum:	interrupt number
+ * @irqflags:	interrupt flags
+ * @ops:	HCD ops to interface with the HCD
+ *
+ * This is used by the USB Host stack to register the host controller
+ * to the OTG core. Host controller must not be started by the
+ * caller as it is left upto the OTG state machine to do so.
+ * hcd->otg_dev must contain the related otg controller device.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+			 unsigned long irqflags, struct otg_hcd_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *hcd_dev = hcd->self.controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(hcd_dev,
+			"otg: controller not yet registered. 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_err(hcd_dev, "otg: failed to add hcd to wait list\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	/* HCD will be started by OTG fsm when needed */
+	mutex_lock(&otg->fsm.lock);
+	if (otg->primary_hcd.hcd) {
+		/* probably a shared HCD ? */
+		if (usb_otg_hcd_is_primary_hcd(hcd)) {
+			dev_err(otg_dev, "otg: primary host already registered\n");
+			goto err;
+		}
+
+		if (hcd->shared_hcd == otg->primary_hcd.hcd) {
+			if (otg->shared_hcd.hcd) {
+				dev_err(otg_dev, "otg: shared host already registered\n");
+				goto err;
+			}
+
+			otg->shared_hcd.hcd = hcd;
+			otg->shared_hcd.irqnum = irqnum;
+			otg->shared_hcd.irqflags = irqflags;
+			otg->shared_hcd.ops = ops;
+			dev_info(otg_dev, "otg: shared host %s registered\n",
+				 dev_name(hcd->self.controller));
+		} else {
+			dev_err(otg_dev, "otg: invalid shared host %s\n",
+				dev_name(hcd->self.controller));
+			goto err;
+		}
+	} else {
+		if (!usb_otg_hcd_is_primary_hcd(hcd)) {
+			dev_err(otg_dev, "otg: primary host must be registered first\n");
+			goto err;
+		}
+
+		otg->primary_hcd.hcd = hcd;
+		otg->primary_hcd.irqnum = irqnum;
+		otg->primary_hcd.irqflags = irqflags;
+		otg->primary_hcd.ops = ops;
+		otg->hcd_ops = ops;
+		dev_info(otg_dev, "otg: primary host %s registered\n",
+			 dev_name(hcd->self.controller));
+	}
+
+	/*
+	 * we're ready only if we have shared HCD
+	 * or we don't need shared HCD.
+	 */
+	if (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+		otg->host = hcd_to_bus(hcd);
+		/* FIXME: set bus->otg_port if this is true OTG port with HNP */
+
+		/* start FSM */
+		usb_otg_start_fsm(otg);
+	} else {
+		dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+	}
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+
+err:
+	mutex_unlock(&otg->fsm.lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_hcd);
+
+/**
+ * usb_otg_unregister_hcd - Unregister the host controller from OTG core
+ * @hcd:	host controller device
+ *
+ * This is used by the USB Host stack to unregister the host controller
+ * from the OTG core. Ensures that host controller is not running
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_hcd(struct usb_hcd *hcd)
+{
+	struct usb_otg *otg;
+	struct device *hcd_dev = hcd_to_bus(hcd)->controller;
+	struct device *otg_dev = hcd->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		/* 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(&otg->fsm.lock);
+	if (hcd == otg->primary_hcd.hcd) {
+		otg->primary_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: primary host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else if (hcd == otg->shared_hcd.hcd) {
+		otg->shared_hcd.hcd = NULL;
+		dev_info(otg_dev, "otg: shared host %s unregistered\n",
+			 dev_name(hcd_dev));
+	} else {
+		dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
+			dev_name(hcd_dev));
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	/* stop FSM & Host */
+	usb_otg_stop_fsm(otg);
+	otg->host = NULL;
+
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_hcd);
+
+/**
+ * usb_otg_register_gadget - Register the gadget controller to OTG core
+ * @gadget:	gadget controller
+ *
+ * This is used by the USB gadget stack to register the gadget controller
+ * to the OTG core. Gadget controller must not be started by the
+ * caller as it is left upto the OTG state machine to do so.
+ *
+ * Gadget core must call this only when all resources required for
+ * gadget controller to run are available.
+ * i.e. gadget function driver is available.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;	/* we're definitely not OTG */
+
+	/* we're otg but otg controller might not yet be registered */
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		dev_dbg(gadget_dev,
+			"otg: controller not yet registered. 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_err(gadget_dev,
+				"otg: failed to add to gadget to wait list\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	mutex_lock(&otg->fsm.lock);
+	if (otg->gadget) {
+		dev_err(otg_dev, "otg: gadget already registered with otg\n");
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	otg->gadget = gadget;
+	otg->gadget_ops = ops;
+	dev_info(otg_dev, "otg: gadget %s registered\n",
+		 dev_name(&gadget->dev));
+
+	/* start FSM */
+	usb_otg_start_fsm(otg);
+	mutex_unlock(&otg->fsm.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_register_gadget);
+
+/**
+ * usb_otg_unregister_gadget - Unregister the gadget controller from OTG core
+ * @gadget:	gadget controller
+ *
+ * This is used by the USB gadget stack to unregister the gadget controller
+ * from the OTG core. Ensures that gadget controller is halted
+ * on successful return.
+ *
+ * Returns: 0 on success, error value otherwise.
+ */
+int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	struct usb_otg *otg;
+	struct device *gadget_dev = &gadget->dev;
+	struct device *otg_dev = gadget->otg_dev;
+
+	if (!otg_dev)
+		return -EINVAL;
+
+	mutex_lock(&otg_list_mutex);
+	otg = usb_otg_get_data(otg_dev);
+	mutex_unlock(&otg_list_mutex);
+	if (!otg) {
+		/* 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(&otg->fsm.lock);
+	if (otg->gadget != gadget) {
+		dev_err(otg_dev, "otg: gadget %s wasn't registered with otg\n",
+			dev_name(&gadget->dev));
+		mutex_unlock(&otg->fsm.lock);
+		return -EINVAL;
+	}
+
+	/* Stop FSM & gadget */
+	usb_otg_stop_fsm(otg);
+	otg->gadget = NULL;
+	mutex_unlock(&otg->fsm.lock);
+
+	dev_info(otg_dev, "otg: gadget %s unregistered\n",
+		 dev_name(&gadget->dev));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_unregister_gadget);
diff --git a/drivers/usb/common/usb-otg.h b/drivers/usb/common/usb-otg.h
new file mode 100644
index 0000000..2bf3fbf
--- /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) 2016 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#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 ae228d0..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
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 8c0ae64..1878ae1 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -583,6 +583,7 @@ struct usb_gadget_ops {
  * @out_epnum: last used out ep number
  * @in_epnum: last used in ep number
  * @otg_caps: OTG capabilities of this gadget.
+ * @otg_dev: OTG controller device, if needs to be used with OTG core.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
@@ -639,6 +640,7 @@ struct usb_gadget {
 	unsigned			out_epnum;
 	unsigned			in_epnum;
 	struct usb_otg_caps		*otg_caps;
+	struct device			*otg_dev;
 
 	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 861ccaa..2017cd4 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -184,6 +184,7 @@ struct usb_hcd {
 	struct mutex		*bandwidth_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
+	struct device		*otg_dev;	/* OTG controller device */
 
 
 #define HCD_BUFFER_POOLS	4
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index 26e6531..943714a 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -60,6 +60,11 @@ enum otg_fsm_timer {
 /**
  * struct otg_fsm - OTG state machine according to the OTG spec
  *
+ * DRD mode hardware Inputs
+ *
+ * @id:		TRUE for B-device, FALSE for A-device.
+ * @b_sess_vld:	VBUS voltage in regulation.
+ *
  * OTG hardware Inputs
  *
  *	Common inputs for A and B device
@@ -132,6 +137,7 @@ enum otg_fsm_timer {
  * a_clr_err:	Asserted (by application ?) to clear a_vbus_err due to an
  *		overcurrent condition and causes the A-device to transition
  *		to a_wait_vfall
+ * running:	state machine running/stopped indicator
  */
 struct otg_fsm {
 	/* Input */
@@ -187,6 +193,7 @@ struct otg_fsm {
 	int b_ase0_brst_tmout;
 	int a_bidl_adis_tmout;
 
+	bool running;
 	struct otg_fsm_ops *ops;
 
 	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 85b8fb5..b094352 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -10,10 +10,55 @@
 #define __LINUX_USB_OTG_H
 
 #include <linux/phy/phy.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/otg-fsm.h>
+#include <linux/device.h>
+#include <linux/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
+ * @ops: otg to host controller interface
+ * @otg_dev: otg controller device
+ */
+struct otg_hcd {
+	struct usb_hcd *hcd;
+	unsigned int irqnum;
+	unsigned long irqflags;
+	struct otg_hcd_ops *ops;
+	struct device *otg_dev;
+};
+
+/**
+ * struct usb_otg - usb otg controller state
+ *
+ * @default_a: Indicates we are an A device. i.e. Host.
+ * @phy: USB phy interface
+ * @usb_phy: old usb_phy interface
+ * @host: host controller bus
+ * @gadget: gadget device
+ * @state: current otg state
+ * @dev: otg controller device
+ * @caps: otg capabilities revision, hnp, srp, etc
+ * @fsm: otg finite state machine
+ * @hcd_ops: host controller interface
+ * ------- internal use only -------
+ * @primary_hcd: primary host state and interface
+ * @shared_hcd: shared host state and interface
+ * @gadget_ops: gadget controller interface
+ * @list: list of otg controllers
+ * @work: otg state machine work
+ * @wq: otg state machine work queue
+ * @flags: to track if host/gadget is running
+ */
 struct usb_otg {
 	u8			default_a;
 
@@ -24,9 +69,24 @@ struct usb_otg {
 	struct usb_gadget	*gadget;
 
 	enum usb_otg_state	state;
+	struct device *dev;
+	struct usb_otg_caps *caps;
 	struct otg_fsm fsm;
 	struct otg_hcd_ops	*hcd_ops;
 
+	/* internal use only */
+	struct otg_hcd primary_hcd;
+	struct otg_hcd shared_hcd;
+	struct otg_gadget_ops *gadget_ops;
+	struct list_head list;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	u32 flags;
+#define OTG_FLAG_GADGET_RUNNING (1 << 0)
+#define OTG_FLAG_HOST_RUNNING (1 << 1)
+	/* use otg->fsm.lock for serializing access */
+
+/*------------- deprecated interface -----------------------------*/
 	/* bind/unbind the host controller */
 	int	(*set_host)(struct usb_otg *otg, struct usb_bus *host);
 
@@ -42,7 +102,7 @@ struct usb_otg {
 
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct usb_otg *otg);
-
+/*---------------------------------------------------------------*/
 };
 
 /**
@@ -60,8 +120,92 @@ 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_work: optional custom otg state machine work function
+ */
+struct usb_otg_config {
+	struct usb_otg_caps *otg_caps;
+	struct otg_fsm_ops *fsm_ops;
+	void (*otg_work)(struct work_struct *work);
+};
+
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
+#if IS_ENABLED(CONFIG_USB_OTG)
+struct usb_otg *usb_otg_register(struct device *dev,
+				 struct usb_otg_config *config);
+int usb_otg_unregister(struct device *dev);
+int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+			 unsigned long irqflags, struct otg_hcd_ops *ops);
+int usb_otg_unregister_hcd(struct usb_hcd *hcd);
+int usb_otg_register_gadget(struct usb_gadget *gadget,
+			    struct otg_gadget_ops *ops);
+int usb_otg_unregister_gadget(struct usb_gadget *gadget);
+void usb_otg_sync_inputs(struct usb_otg *otg);
+int usb_otg_kick_fsm(struct device *otg_dev);
+int usb_otg_start_host(struct usb_otg *otg, int on);
+int usb_otg_start_gadget(struct usb_otg *otg, int on);
+
+#else /* CONFIG_USB_OTG */
+
+static inline struct usb_otg *usb_otg_register(struct device *dev,
+					       struct usb_otg_config *config)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
+static inline int usb_otg_unregister(struct device *dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
+				       unsigned long irqflags,
+				       struct otg_hcd_ops *ops)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_unregister_hcd(struct usb_hcd *hcd)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_register_gadget(struct usb_gadget *gadget,
+					  struct otg_gadget_ops *ops)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_unregister_gadget(struct usb_gadget *gadget)
+{
+	return -ENOTSUPP;
+}
+
+static inline void usb_otg_sync_inputs(struct usb_otg *otg)
+{
+}
+
+static inline int usb_otg_kick_fsm(struct device *otg_dev)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_host(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+
+static inline int usb_otg_start_gadget(struct usb_otg *otg, int on)
+{
+	return -ENOTSUPP;
+}
+#endif /* CONFIG_USB_OTG */
+
+/*------------- deprecated interface -----------------------------*/
 /* Context: can sleep */
 static inline int
 otg_start_hnp(struct usb_otg *otg)
@@ -113,6 +257,8 @@ otg_start_srp(struct usb_otg *otg)
 	return -ENOTSUPP;
 }
 
+/*---------------------------------------------------------------*/
+
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
 
@@ -237,4 +383,6 @@ static inline int otg_start_gadget(struct usb_otg *otg, int on)
 	return otg->fsm.ops->start_gadget(otg, on);
 }
 
+int drd_statemachine(struct usb_otg *otg);
+
 #endif /* __LINUX_USB_OTG_H */
-- 
2.7.4

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


#1398797 — Re: [PATCH v7 08/14] usb: otg: add OTG/dual-role core

FromPeter Chen <hzpeterchen@gmail.com>
Date2016-05-11 10:50 +0200
SubjectRe: [PATCH v7 08/14] usb: otg: add OTG/dual-role core
Message-ID<rxy0b-4vB-29@gated-at.bofh.it>
In reply to#1392177
On Mon, May 02, 2016 at 03:18:51PM +0300, Roger Quadros wrote:
> +
> +	if (config->otg_work)	/* custom otg_work ? */
> +		INIT_WORK(&otg->work, config->otg_work);
> +	else
> +		INIT_WORK(&otg->work, usb_drd_work);
> +
> +	otg->wq = create_singlethread_workqueue("usb_otg");

Using create_freezable_workqueue like I suggested before.

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

Seems you agree to remove above definitions.

>  
>  	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index 85b8fb5..b094352 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -10,10 +10,55 @@
>  #define __LINUX_USB_OTG_H
>  
>  #include <linux/phy/phy.h>
> -#include <linux/usb/phy.h>
> -#include <linux/usb/otg-fsm.h>
> +#include <linux/device.h>
> +#include <linux/hrtimer.h>
> +#include <linux/ktime.h>

Above two headers are not needed

-- 

Best Regards,
Peter Chen

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


#1398955 — Re: [PATCH v7 08/14] usb: otg: add OTG/dual-role core

FromRoger Quadros <rogerq@ti.com>
Date2016-05-11 13:10 +0200
SubjectRe: [PATCH v7 08/14] usb: otg: add OTG/dual-role core
Message-ID<rxAbE-77O-45@gated-at.bofh.it>
In reply to#1398797
On 11/05/16 11:34, Peter Chen wrote:
> On Mon, May 02, 2016 at 03:18:51PM +0300, Roger Quadros wrote:
>> +
>> +	if (config->otg_work)	/* custom otg_work ? */
>> +		INIT_WORK(&otg->work, config->otg_work);
>> +	else
>> +		INIT_WORK(&otg->work, usb_drd_work);
>> +
>> +	otg->wq = create_singlethread_workqueue("usb_otg");
> 
> Using create_freezable_workqueue like I suggested before.

Sorry that I missed this part. I'll fix it in v8.
> 
>> + */
>> +
>> +#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)
> 
> Seems you agree to remove above definitions.

My bad, sorry.
> 
>>  
>>  	/* Current usb protocol used: 0:undefine; 1:host; 2:client */
>> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
>> index 85b8fb5..b094352 100644
>> --- a/include/linux/usb/otg.h
>> +++ b/include/linux/usb/otg.h
>> @@ -10,10 +10,55 @@
>>  #define __LINUX_USB_OTG_H
>>  
>>  #include <linux/phy/phy.h>
>> -#include <linux/usb/phy.h>
>> -#include <linux/usb/otg-fsm.h>
>> +#include <linux/device.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/ktime.h>
> 
> Above two headers are not needed
> 
OK.

--
cheers
-roger

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


#1392178 — [PATCH v7 13/14] usb: gadget: udc: adapt to OTG core

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 13/14] usb: gadget: udc: adapt to OTG core
Message-ID<rul98-3f2-27@gated-at.bofh.it>
In reply to#1392163
The OTG state machine needs a mechanism to start and
stop the gadget controller. Add usb_gadget_start()
and usb_gadget_stop().

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

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

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

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

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

diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index 4151597..e384c7e 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 /**
  * struct usb_udc - describes one usb device controller
@@ -325,6 +330,87 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller and connect to bus
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller and connect to bus (enable pull).
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+	else
+		usb_udc_connect_control(udc);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - disconnect from bus and stop the usb gadget
+ * @gadget: The gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Disconnect from the bus (disable pull) and stop the
+ * gadget controller.
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	usb_gadget_disconnect(udc->gadget);
+	udc->driver->disconnect(udc->gadget);
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -486,6 +572,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
+
+/* udc_lock must be held */
 static void usb_gadget_remove_driver(struct usb_udc *udc)
 {
 	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
@@ -493,10 +606,18 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-	usb_gadget_disconnect(udc->gadget);
-	udc->driver->disconnect(udc->gadget);
+	/* If OTG, the otg core ensures UDC is stopped on unregister */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_unregister_gadget(udc->gadget);
+		mutex_lock(&udc_lock);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+		usb_gadget_udc_stop(udc);
+	}
+
 	udc->driver->unbind(udc->gadget);
-	usb_gadget_udc_stop(udc);
 
 	udc->driver = NULL;
 	udc->dev.driver = NULL;
@@ -530,6 +651,8 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	mutex_unlock(&udc_lock);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -539,6 +662,12 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+};
+
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -553,12 +682,20 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 	ret = driver->bind(udc->gadget, driver);
 	if (ret)
 		goto err1;
-	ret = usb_gadget_udc_start(udc);
-	if (ret) {
-		driver->unbind(udc->gadget);
-		goto err1;
+
+	/* If OTG, the otg core starts the UDC when needed */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_register_gadget(udc->gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_udc_connect_control(udc);
 	}
-	usb_udc_connect_control(udc);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 	return 0;
@@ -660,9 +797,15 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG mode we don't support softconnect, but b_bus_req */
+	if (udc->gadget->otg_dev) {
+		dev_err(dev, "soft-connect not supported in OTG mode\n");
+		return -EOPNOTSUPP;
+	}
+
 	if (sysfs_streq(buf, "connect")) {
 		usb_gadget_udc_start(udc);
-		usb_gadget_connect(udc->gadget);
+		usb_udc_connect_control(udc);
 	} else if (sysfs_streq(buf, "disconnect")) {
 		usb_gadget_disconnect(udc->gadget);
 		udc->driver->disconnect(udc->gadget);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1878ae1..c0c5617 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -1160,6 +1160,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

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


#1392179 — [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromRoger Quadros <rogerq@ti.com>
Date2016-05-02 14:30 +0200
Subject[PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rul99-3f2-33@gated-at.bofh.it>
In reply to#1392163
This is to prevent missing symbol build error if OTG is
enabled (built-in) and HCD core (CONFIG_USB) is module.

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

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

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


#1398708 — Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromPeter Chen <hzpeterchen@gmail.com>
Date2016-05-11 08:20 +0200
SubjectRe: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rxvEZ-2sl-7@gated-at.bofh.it>
In reply to#1392179
On Mon, May 02, 2016 at 03:18:48PM +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@nxp.com>
> ---
>  drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
>  drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
>  drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
>  include/linux/usb/otg.h          |  2 ++
>  4 files changed, 27 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
> index 1c0c750..2d8d659 100644
> --- a/drivers/usb/chipidea/otg_fsm.c
> +++ b/drivers/usb/chipidea/otg_fsm.c
> @@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
>  	.start_gadget = ci_otg_start_gadget,
>  };
>  
> +static struct otg_hcd_ops ci_hcd_ops = {
> +	.usb_bus_start_enum = usb_bus_start_enum,
> +	.usb_control_msg = usb_control_msg,
> +	.usb_hub_find_child = usb_hub_find_child,
> +};
> +

Is it possible have default otg_hcd_ops during OTG register to
avoid define it at every dual-role driver?

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

-- 

Best Regards,
Peter Chen

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


#1398950 — Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromRoger Quadros <rogerq@ti.com>
Date2016-05-11 13:10 +0200
SubjectRe: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rxAbE-77O-23@gated-at.bofh.it>
In reply to#1398708
On 11/05/16 09:10, Peter Chen wrote:
> On Mon, May 02, 2016 at 03:18:48PM +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@nxp.com>
>> ---
>>  drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
>>  drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
>>  drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
>>  include/linux/usb/otg.h          |  2 ++
>>  4 files changed, 27 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
>> index 1c0c750..2d8d659 100644
>> --- a/drivers/usb/chipidea/otg_fsm.c
>> +++ b/drivers/usb/chipidea/otg_fsm.c
>> @@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
>>  	.start_gadget = ci_otg_start_gadget,
>>  };
>>  
>> +static struct otg_hcd_ops ci_hcd_ops = {
>> +	.usb_bus_start_enum = usb_bus_start_enum,
>> +	.usb_control_msg = usb_control_msg,
>> +	.usb_hub_find_child = usb_hub_find_child,
>> +};
>> +
> 
> Is it possible have default otg_hcd_ops during OTG register to
> avoid define it at every dual-role driver?

Yes, I'll do that.

cheers,
-roger

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

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


#1399023 — Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromRoger Quadros <rogerq@ti.com>
Date2016-05-11 14:40 +0200
SubjectRe: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rxBAM-8ht-41@gated-at.bofh.it>
In reply to#1398950
Peter,

On 11/05/16 14:02, Roger Quadros wrote:
> On 11/05/16 09:10, Peter Chen wrote:
>> On Mon, May 02, 2016 at 03:18:48PM +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@nxp.com>
>>> ---
>>>  drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
>>>  drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
>>>  drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
>>>  include/linux/usb/otg.h          |  2 ++
>>>  4 files changed, 27 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
>>> index 1c0c750..2d8d659 100644
>>> --- a/drivers/usb/chipidea/otg_fsm.c
>>> +++ b/drivers/usb/chipidea/otg_fsm.c
>>> @@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
>>>  	.start_gadget = ci_otg_start_gadget,
>>>  };
>>>  
>>> +static struct otg_hcd_ops ci_hcd_ops = {
>>> +	.usb_bus_start_enum = usb_bus_start_enum,
>>> +	.usb_control_msg = usb_control_msg,
>>> +	.usb_hub_find_child = usb_hub_find_child,
>>> +};
>>> +
>>
>> Is it possible have default otg_hcd_ops during OTG register to
>> avoid define it at every dual-role driver?
> 
> Yes, I'll do that.

Every OTG driver doesn't need to do this as this is provided by
hcd.c during usb_otg_add_hcd().

So proper fix is that chipidea driver must use usb_otg_add_hcd().

cheers,
-roger

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

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


#1399746 — Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromPeter Chen <hzpeterchen@gmail.com>
Date2016-05-12 10:30 +0200
SubjectRe: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rxUam-1Mc-7@gated-at.bofh.it>
In reply to#1399023
On Wed, May 11, 2016 at 03:32:30PM +0300, Roger Quadros wrote:
> Peter,
> 
> On 11/05/16 14:02, Roger Quadros wrote:
> > On 11/05/16 09:10, Peter Chen wrote:
> >> On Mon, May 02, 2016 at 03:18:48PM +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@nxp.com>
> >>> ---
> >>>  drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
> >>>  drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
> >>>  drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
> >>>  include/linux/usb/otg.h          |  2 ++
> >>>  4 files changed, 27 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
> >>> index 1c0c750..2d8d659 100644
> >>> --- a/drivers/usb/chipidea/otg_fsm.c
> >>> +++ b/drivers/usb/chipidea/otg_fsm.c
> >>> @@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
> >>>  	.start_gadget = ci_otg_start_gadget,
> >>>  };
> >>>  
> >>> +static struct otg_hcd_ops ci_hcd_ops = {
> >>> +	.usb_bus_start_enum = usb_bus_start_enum,
> >>> +	.usb_control_msg = usb_control_msg,
> >>> +	.usb_hub_find_child = usb_hub_find_child,
> >>> +};
> >>> +
> >>
> >> Is it possible have default otg_hcd_ops during OTG register to
> >> avoid define it at every dual-role driver?
> > 
> > Yes, I'll do that.
> 
> Every OTG driver doesn't need to do this as this is provided by
> hcd.c during usb_otg_add_hcd().
> 
> So proper fix is that chipidea driver must use usb_otg_add_hcd().
> 

But the chipidea is not ready to merge with framework that this patch
set introduces. So, as a solution, we need this patch, and can remove
the redundant information after the OTG driver uses this framework?

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

-- 

Best Regards,
Peter Chen

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


#1399748 — Re: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops

FromRoger Quadros <rogerq@ti.com>
Date2016-05-12 10:40 +0200
SubjectRe: [PATCH v7 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops
Message-ID<rxUk2-1QS-7@gated-at.bofh.it>
In reply to#1399746
On 12/05/16 11:18, Peter Chen wrote:
> On Wed, May 11, 2016 at 03:32:30PM +0300, Roger Quadros wrote:
>> Peter,
>>
>> On 11/05/16 14:02, Roger Quadros wrote:
>>> On 11/05/16 09:10, Peter Chen wrote:
>>>> On Mon, May 02, 2016 at 03:18:48PM +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@nxp.com>
>>>>> ---
>>>>>  drivers/usb/chipidea/otg_fsm.c   |  7 +++++++
>>>>>  drivers/usb/common/usb-otg-fsm.c | 15 +++++++++++----
>>>>>  drivers/usb/phy/phy-fsl-usb.c    |  7 +++++++
>>>>>  include/linux/usb/otg.h          |  2 ++
>>>>>  4 files changed, 27 insertions(+), 4 deletions(-)
>>>>>
>>>>> diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
>>>>> index 1c0c750..2d8d659 100644
>>>>> --- a/drivers/usb/chipidea/otg_fsm.c
>>>>> +++ b/drivers/usb/chipidea/otg_fsm.c
>>>>> @@ -582,6 +582,12 @@ static struct otg_fsm_ops ci_otg_ops = {
>>>>>  	.start_gadget = ci_otg_start_gadget,
>>>>>  };
>>>>>  
>>>>> +static struct otg_hcd_ops ci_hcd_ops = {
>>>>> +	.usb_bus_start_enum = usb_bus_start_enum,
>>>>> +	.usb_control_msg = usb_control_msg,
>>>>> +	.usb_hub_find_child = usb_hub_find_child,
>>>>> +};
>>>>> +
>>>>
>>>> Is it possible have default otg_hcd_ops during OTG register to
>>>> avoid define it at every dual-role driver?
>>>
>>> Yes, I'll do that.
>>
>> Every OTG driver doesn't need to do this as this is provided by
>> hcd.c during usb_otg_add_hcd().
>>
>> So proper fix is that chipidea driver must use usb_otg_add_hcd().
>>
> 
> But the chipidea is not ready to merge with framework that this patch
> set introduces. So, as a solution, we need this patch, and can remove
> the redundant information after the OTG driver uses this framework?

That is fine, but I don't want to create a default otg_hcd_ops as we
don't want to encourage its use. Do you agree?

cheers,
-roger

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

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


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | linux.kernel


csiph-web