Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1400666 > unrolled thread
| Started by | Roger Quadros <rogerq@ti.com> |
|---|---|
| First post | 2016-05-13 12:10 +0200 |
| Last post | 2016-05-30 16:10 +0200 |
| Articles | 20 on this page of 52 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH v8 00/14] USB OTG/dual-role framework Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-16 09:20 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-16 10:30 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-16 11:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-16 12:00 +0200
RE: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Jun Li <jun.li@nxp.com> - 2016-05-17 09:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-17 10:10 +0200
RE: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Jun Li <jun.li@nxp.com> - 2016-05-17 10:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-18 14:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-18 15:50 +0200
RE: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Jun Li <jun.li@nxp.com> - 2016-05-18 16:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-19 09:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-21 04:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-23 05:30 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-23 12:20 +0200
RE: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Jun Li <jun.li@nxp.com> - 2016-05-23 12:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-23 12:40 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-24 05:00 +0200
RE: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Jun Li <jun.li@nxp.com> - 2016-05-18 15:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-18 05:30 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-18 14:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-20 03:50 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-20 09:30 +0200
Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core Peter Chen <hzpeterchen@gmail.com> - 2016-05-21 05:00 +0200
[PATCH v8 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
Re: [PATCH v8 10/14] usb: otg: add hcd companion support Rob Herring <robh@kernel.org> - 2016-05-13 20:20 +0200
Re: [PATCH v8 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-16 10:20 +0200
[PATCH v9 10/14] usb: otg: add hcd companion support Roger Quadros <rogerq@ti.com> - 2016-05-20 11:40 +0200
Re: [PATCH v9 10/14] usb: otg: add hcd companion support Rob Herring <robh@kernel.org> - 2016-05-23 23:10 +0200
[PATCH v8 11/14] usb: otg: use dev_dbg() instead of VDBG() Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 12/14] usb: hcd: Adapt to OTG core Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 14/14] usb: host: xhci-plat: Add otg device to platform data Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-16 11:10 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-18 15:10 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-20 10:40 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-20 11:20 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Peter Chen <hzpeterchen@gmail.com> - 2016-05-20 12:00 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-23 12:10 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-24 11:50 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Peter Chen <hzpeterchen@gmail.com> - 2016-05-25 04:50 +0200
RE: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Jun Li <jun.li@nxp.com> - 2016-05-25 06:00 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-25 14:30 +0200
Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Roger Quadros <rogerq@ti.com> - 2016-05-25 14:30 +0200
RE: [PATCH v8 08/14] usb: otg: add OTG/dual-role core Jun Li <jun.li@nxp.com> - 2016-05-25 16:50 +0200
[PATCH v8 01/14] usb: hcd: Initialize hcd->flags to 0 Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
[PATCH v8 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops Roger Quadros <rogerq@ti.com> - 2016-05-13 12:10 +0200
Re: [PATCH v8 00/14] USB OTG/dual-role framework Peter Chen <hzpeterchen@gmail.com> - 2016-05-30 11:40 +0200
Re: [PATCH v8 00/14] USB OTG/dual-role framework Roger Quadros <rogerq@ti.com> - 2016-05-30 16:10 +0200
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Peter Chen <hzpeterchen@gmail.com> |
|---|---|
| Date | 2016-05-18 05:30 +0200 |
| Subject | Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core |
| Message-ID | <rA0lj-4Ys-3@gated-at.bofh.it> |
| In reply to | #1401409 |
On Mon, May 16, 2016 at 12:51:53PM +0300, Roger Quadros wrote:
> On 16/05/16 12:23, Peter Chen wrote:
> > On Mon, May 16, 2016 at 11:26:57AM +0300, Roger Quadros wrote:
> >> Hi,
> >>
> >> On 16/05/16 10:02, Peter Chen wrote:
> >>> On Fri, May 13, 2016 at 01:03:27PM +0300, Roger Quadros wrote:
> >>>> +
> >>>> +static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
> >>>> +{
> >>>> + struct usb_udc *udc;
> >>>> +
> >>>> + mutex_lock(&udc_lock);
> >>>> + udc = usb_gadget_to_udc(gadget);
> >>>> + if (!udc) {
> >>>> + dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
> >>>> + __func__);
> >>>> + mutex_unlock(&udc_lock);
> >>>> + return -EINVAL;
> >>>> + }
> >>>> +
> >>>> + if (connect) {
> >>>> + if (!gadget->connected)
> >>>> + usb_gadget_connect(udc->gadget);
> >>>> + } else {
> >>>> + if (gadget->connected) {
> >>>> + usb_gadget_disconnect(udc->gadget);
> >>>> + udc->driver->disconnect(udc->gadget);
> >>>> + }
> >>>> + }
> >>>> +
> >>>> + mutex_unlock(&udc_lock);
> >>>> +
> >>>> + return 0;
> >>>> +}
> >>>> +
> >>>
> >>> Since this is called for vbus interrupt, why not using
> >>> usb_udc_vbus_handler directly, and call udc->driver->disconnect
> >>> at usb_gadget_stop.
> >>
> >> We can't assume that this is always called for vbus interrupt so
> >> I decided not to call usb_udc_vbus_handler.
> >>
> >> udc->vbus is really pointless for us. We keep vbus states in our
> >> state machine and leave udc->vbus as ture always.
> >>
> >> Why do you want to move udc->driver->disconnect() to stop?
> >> If USB controller disconnected from bus then the gadget driver
> >> must be notified about the disconnect immediately. The controller
> >> may or may not be stopped by the core.
> >>
> >
> > Then, would you give some comments when this API will be used?
> > I was assumed it is only used for drd state machine.
>
> drd_state machine didn't even need this API in the first place :).
> You guys wanted me to separate out start/stop and connect/disconnect for full OTG case.
> Won't full OTG state machine want to use this API? If not what would it use?
>
Oh, I meant only drd and fully otg state machine needs it. I am
wondering if we need have a new API to do it. Two questions:
- Except for vbus interrupt, any chances this API will be used at
current logic?
- When this API is called but without a coming gadget->stop?
--
Best Regards,
Peter Chen
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-18 14:50 +0200 |
| Subject | Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core |
| Message-ID | <rA95g-2dr-21@gated-at.bofh.it> |
| In reply to | #1402706 |
On 18/05/16 06:18, Peter Chen wrote:
> On Mon, May 16, 2016 at 12:51:53PM +0300, Roger Quadros wrote:
>> On 16/05/16 12:23, Peter Chen wrote:
>>> On Mon, May 16, 2016 at 11:26:57AM +0300, Roger Quadros wrote:
>>>> Hi,
>>>>
>>>> On 16/05/16 10:02, Peter Chen wrote:
>>>>> On Fri, May 13, 2016 at 01:03:27PM +0300, Roger Quadros wrote:
>>>>>> +
>>>>>> +static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
>>>>>> +{
>>>>>> + struct usb_udc *udc;
>>>>>> +
>>>>>> + mutex_lock(&udc_lock);
>>>>>> + udc = usb_gadget_to_udc(gadget);
>>>>>> + if (!udc) {
>>>>>> + dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
>>>>>> + __func__);
>>>>>> + mutex_unlock(&udc_lock);
>>>>>> + return -EINVAL;
>>>>>> + }
>>>>>> +
>>>>>> + if (connect) {
>>>>>> + if (!gadget->connected)
>>>>>> + usb_gadget_connect(udc->gadget);
>>>>>> + } else {
>>>>>> + if (gadget->connected) {
>>>>>> + usb_gadget_disconnect(udc->gadget);
>>>>>> + udc->driver->disconnect(udc->gadget);
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + mutex_unlock(&udc_lock);
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>
>>>>> Since this is called for vbus interrupt, why not using
>>>>> usb_udc_vbus_handler directly, and call udc->driver->disconnect
>>>>> at usb_gadget_stop.
>>>>
>>>> We can't assume that this is always called for vbus interrupt so
>>>> I decided not to call usb_udc_vbus_handler.
>>>>
>>>> udc->vbus is really pointless for us. We keep vbus states in our
>>>> state machine and leave udc->vbus as ture always.
>>>>
>>>> Why do you want to move udc->driver->disconnect() to stop?
>>>> If USB controller disconnected from bus then the gadget driver
>>>> must be notified about the disconnect immediately. The controller
>>>> may or may not be stopped by the core.
>>>>
>>>
>>> Then, would you give some comments when this API will be used?
>>> I was assumed it is only used for drd state machine.
>>
>> drd_state machine didn't even need this API in the first place :).
>> You guys wanted me to separate out start/stop and connect/disconnect for full OTG case.
>> Won't full OTG state machine want to use this API? If not what would it use?
>>
>
> Oh, I meant only drd and fully otg state machine needs it. I am
> wondering if we need have a new API to do it. Two questions:
OK.
>
> - Except for vbus interrupt, any chances this API will be used at
> current logic?
I don't think so. But we can't assume caller behaviour for any API.
> - When this API is called but without a coming gadget->stop?
>
Never for DRD case. But we want to catch wrong users.
cheers,
-roger
[toc] | [prev] | [next] | [standalone]
| From | Peter Chen <hzpeterchen@gmail.com> |
|---|---|
| Date | 2016-05-20 03:50 +0200 |
| Subject | Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core |
| Message-ID | <rAHJE-7zo-7@gated-at.bofh.it> |
| In reply to | #1402955 |
On Wed, May 18, 2016 at 03:45:11PM +0300, Roger Quadros wrote:
> On 18/05/16 06:18, Peter Chen wrote:
> > On Mon, May 16, 2016 at 12:51:53PM +0300, Roger Quadros wrote:
> >> On 16/05/16 12:23, Peter Chen wrote:
> >>> On Mon, May 16, 2016 at 11:26:57AM +0300, Roger Quadros wrote:
> >>>> Hi,
> >>>>
> >>>> On 16/05/16 10:02, Peter Chen wrote:
> >>>>> On Fri, May 13, 2016 at 01:03:27PM +0300, Roger Quadros wrote:
> >>>>>> +
> >>>>>> +static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
> >>>>>> +{
> >>>>>> + struct usb_udc *udc;
> >>>>>> +
> >>>>>> + mutex_lock(&udc_lock);
> >>>>>> + udc = usb_gadget_to_udc(gadget);
> >>>>>> + if (!udc) {
> >>>>>> + dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
> >>>>>> + __func__);
> >>>>>> + mutex_unlock(&udc_lock);
> >>>>>> + return -EINVAL;
> >>>>>> + }
> >>>>>> +
> >>>>>> + if (connect) {
> >>>>>> + if (!gadget->connected)
> >>>>>> + usb_gadget_connect(udc->gadget);
> >>>>>> + } else {
> >>>>>> + if (gadget->connected) {
> >>>>>> + usb_gadget_disconnect(udc->gadget);
> >>>>>> + udc->driver->disconnect(udc->gadget);
> >>>>>> + }
> >>>>>> + }
> >>>>>> +
> >>>>>> + mutex_unlock(&udc_lock);
> >>>>>> +
> >>>>>> + return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>
> >>>>> Since this is called for vbus interrupt, why not using
> >>>>> usb_udc_vbus_handler directly, and call udc->driver->disconnect
> >>>>> at usb_gadget_stop.
> >>>>
> >>>> We can't assume that this is always called for vbus interrupt so
> >>>> I decided not to call usb_udc_vbus_handler.
> >>>>
> >>>> udc->vbus is really pointless for us. We keep vbus states in our
> >>>> state machine and leave udc->vbus as ture always.
> >>>>
> >>>> Why do you want to move udc->driver->disconnect() to stop?
> >>>> If USB controller disconnected from bus then the gadget driver
> >>>> must be notified about the disconnect immediately. The controller
> >>>> may or may not be stopped by the core.
> >>>>
> >>>
> >>> Then, would you give some comments when this API will be used?
> >>> I was assumed it is only used for drd state machine.
> >>
> >> drd_state machine didn't even need this API in the first place :).
> >> You guys wanted me to separate out start/stop and connect/disconnect for full OTG case.
> >> Won't full OTG state machine want to use this API? If not what would it use?
> >>
> >
> > Oh, I meant only drd and fully otg state machine needs it. I am
> > wondering if we need have a new API to do it. Two questions:
>
> OK.
> >
> > - Except for vbus interrupt, any chances this API will be used at
> > current logic?
>
> I don't think so. But we can't assume caller behaviour for any API.
>
> > - When this API is called but without a coming gadget->stop?
> >
> Never for DRD case. But we want to catch wrong users.
>
In future, otg_start_gadget will be used for both DRD and fully OTG FSM.
There is no otg_loc_conn at current DRD FSM, but there is
otg_loc_conn at current OTG FSM, see below.
DRD FSM:
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;
OTG FSM:
case OTG_STATE_B_IDLE:
otg_drv_vbus(otg, 0);
otg_chrg_vbus(otg, 0);
otg_loc_conn(otg, 0);
otg_loc_sof(otg, 0);
/*
* Driver is responsible for starting ADP probing
* if ADP sensing times out.
*/
otg_start_adp_sns(otg);
otg_set_protocol(fsm, PROTO_UNDEF);
otg_add_timer(otg, B_SE0_SRP);
break;
case OTG_STATE_B_PERIPHERAL:
otg_chrg_vbus(otg, 0);
otg_loc_sof(otg, 0);
otg_set_protocol(fsm, PROTO_GADGET);
otg_loc_conn(otg, 1);
break;
My original suggestion is to have an API to do pull dp and this API
will be used at both DRD and OTG FSM, and called at otg_loc_conn.
The (de)initialize is the same for both two FSMs, it both includes
init peripheral mode and pull up dp, and can be done by drd_set_protocol(fsm, PROTO_GADGET)
otg_loc_conn(otg, 1);
What do you think?
--
Best Regards,
Peter Chen
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-20 09:30 +0200 |
| Subject | Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core |
| Message-ID | <rAN2G-2yz-5@gated-at.bofh.it> |
| In reply to | #1404066 |
Peter,
On 20/05/16 04:39, Peter Chen wrote:
> On Wed, May 18, 2016 at 03:45:11PM +0300, Roger Quadros wrote:
>> On 18/05/16 06:18, Peter Chen wrote:
>>> On Mon, May 16, 2016 at 12:51:53PM +0300, Roger Quadros wrote:
>>>> On 16/05/16 12:23, Peter Chen wrote:
>>>>> On Mon, May 16, 2016 at 11:26:57AM +0300, Roger Quadros wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 16/05/16 10:02, Peter Chen wrote:
>>>>>>> On Fri, May 13, 2016 at 01:03:27PM +0300, Roger Quadros wrote:
>>>>>>>> +
>>>>>>>> +static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
>>>>>>>> +{
>>>>>>>> + struct usb_udc *udc;
>>>>>>>> +
>>>>>>>> + mutex_lock(&udc_lock);
>>>>>>>> + udc = usb_gadget_to_udc(gadget);
>>>>>>>> + if (!udc) {
>>>>>>>> + dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
>>>>>>>> + __func__);
>>>>>>>> + mutex_unlock(&udc_lock);
>>>>>>>> + return -EINVAL;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (connect) {
>>>>>>>> + if (!gadget->connected)
>>>>>>>> + usb_gadget_connect(udc->gadget);
>>>>>>>> + } else {
>>>>>>>> + if (gadget->connected) {
>>>>>>>> + usb_gadget_disconnect(udc->gadget);
>>>>>>>> + udc->driver->disconnect(udc->gadget);
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + mutex_unlock(&udc_lock);
>>>>>>>> +
>>>>>>>> + return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>
>>>>>>> Since this is called for vbus interrupt, why not using
>>>>>>> usb_udc_vbus_handler directly, and call udc->driver->disconnect
>>>>>>> at usb_gadget_stop.
>>>>>>
>>>>>> We can't assume that this is always called for vbus interrupt so
>>>>>> I decided not to call usb_udc_vbus_handler.
>>>>>>
>>>>>> udc->vbus is really pointless for us. We keep vbus states in our
>>>>>> state machine and leave udc->vbus as ture always.
>>>>>>
>>>>>> Why do you want to move udc->driver->disconnect() to stop?
>>>>>> If USB controller disconnected from bus then the gadget driver
>>>>>> must be notified about the disconnect immediately. The controller
>>>>>> may or may not be stopped by the core.
>>>>>>
>>>>>
>>>>> Then, would you give some comments when this API will be used?
>>>>> I was assumed it is only used for drd state machine.
>>>>
>>>> drd_state machine didn't even need this API in the first place :).
>>>> You guys wanted me to separate out start/stop and connect/disconnect for full OTG case.
>>>> Won't full OTG state machine want to use this API? If not what would it use?
>>>>
>>>
>>> Oh, I meant only drd and fully otg state machine needs it. I am
>>> wondering if we need have a new API to do it. Two questions:
>>
>> OK.
>>>
>>> - Except for vbus interrupt, any chances this API will be used at
>>> current logic?
>>
>> I don't think so. But we can't assume caller behaviour for any API.
>>
>>> - When this API is called but without a coming gadget->stop?
>>>
>> Never for DRD case. But we want to catch wrong users.
>>
>
> In future, otg_start_gadget will be used for both DRD and fully OTG FSM.
> There is no otg_loc_conn at current DRD FSM, but there is
> otg_loc_conn at current OTG FSM, see below.
>
> DRD FSM:
> 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;
>
> OTG FSM:
> case OTG_STATE_B_IDLE:
> otg_drv_vbus(otg, 0);
> otg_chrg_vbus(otg, 0);
> otg_loc_conn(otg, 0);
> otg_loc_sof(otg, 0);
> /*
> * Driver is responsible for starting ADP probing
> * if ADP sensing times out.
> */
> otg_start_adp_sns(otg);
> otg_set_protocol(fsm, PROTO_UNDEF);
> otg_add_timer(otg, B_SE0_SRP);
> break;
> case OTG_STATE_B_PERIPHERAL:
> otg_chrg_vbus(otg, 0);
> otg_loc_sof(otg, 0);
> otg_set_protocol(fsm, PROTO_GADGET);
> otg_loc_conn(otg, 1);
> break;
>
> My original suggestion is to have an API to do pull dp and this API
> will be used at both DRD and OTG FSM, and called at otg_loc_conn.
The API is usb_gadget_connect_control();
> The (de)initialize is the same for both two FSMs, it both includes
> init peripheral mode and pull up dp, and can be done by drd_set_protocol(fsm, PROTO_GADGET)
> otg_loc_conn(otg, 1);
>
> What do you think?
>
I think loc_conn is a bit confusing to drd users. Another issue I see is that
DRD controller drivers will need to explicitly pass .loc_conn ops via the otg_fsm_ops.
This is an additional step and totally unnecessary as it can be automatically done
via direct DRD -> UDC-core call.
cheers,
-roger
[toc] | [prev] | [next] | [standalone]
| From | Peter Chen <hzpeterchen@gmail.com> |
|---|---|
| Date | 2016-05-21 05:00 +0200 |
| Subject | Re: [PATCH v8 13/14] usb: gadget: udc: adapt to OTG core |
| Message-ID | <rB5iV-6gK-9@gated-at.bofh.it> |
| In reply to | #1404193 |
On Fri, May 20, 2016 at 10:26:03AM +0300, Roger Quadros wrote:
> Peter,
>
> On 20/05/16 04:39, Peter Chen wrote:
> > On Wed, May 18, 2016 at 03:45:11PM +0300, Roger Quadros wrote:
> >> On 18/05/16 06:18, Peter Chen wrote:
> >>> On Mon, May 16, 2016 at 12:51:53PM +0300, Roger Quadros wrote:
> >>>> On 16/05/16 12:23, Peter Chen wrote:
> >>>>> On Mon, May 16, 2016 at 11:26:57AM +0300, Roger Quadros wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> On 16/05/16 10:02, Peter Chen wrote:
> >>>>>>> On Fri, May 13, 2016 at 01:03:27PM +0300, Roger Quadros wrote:
> >>>>>>>> +
> >>>>>>>> +static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
> >>>>>>>> +{
> >>>>>>>> + struct usb_udc *udc;
> >>>>>>>> +
> >>>>>>>> + mutex_lock(&udc_lock);
> >>>>>>>> + udc = usb_gadget_to_udc(gadget);
> >>>>>>>> + if (!udc) {
> >>>>>>>> + dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
> >>>>>>>> + __func__);
> >>>>>>>> + mutex_unlock(&udc_lock);
> >>>>>>>> + return -EINVAL;
> >>>>>>>> + }
> >>>>>>>> +
> >>>>>>>> + if (connect) {
> >>>>>>>> + if (!gadget->connected)
> >>>>>>>> + usb_gadget_connect(udc->gadget);
> >>>>>>>> + } else {
> >>>>>>>> + if (gadget->connected) {
> >>>>>>>> + usb_gadget_disconnect(udc->gadget);
> >>>>>>>> + udc->driver->disconnect(udc->gadget);
> >>>>>>>> + }
> >>>>>>>> + }
> >>>>>>>> +
> >>>>>>>> + mutex_unlock(&udc_lock);
> >>>>>>>> +
> >>>>>>>> + return 0;
> >>>>>>>> +}
> >>>>>>>> +
> >>>>>>>
> >>>>>>> Since this is called for vbus interrupt, why not using
> >>>>>>> usb_udc_vbus_handler directly, and call udc->driver->disconnect
> >>>>>>> at usb_gadget_stop.
> >>>>>>
> >>>>>> We can't assume that this is always called for vbus interrupt so
> >>>>>> I decided not to call usb_udc_vbus_handler.
> >>>>>>
> >>>>>> udc->vbus is really pointless for us. We keep vbus states in our
> >>>>>> state machine and leave udc->vbus as ture always.
> >>>>>>
> >>>>>> Why do you want to move udc->driver->disconnect() to stop?
> >>>>>> If USB controller disconnected from bus then the gadget driver
> >>>>>> must be notified about the disconnect immediately. The controller
> >>>>>> may or may not be stopped by the core.
> >>>>>>
> >>>>>
> >>>>> Then, would you give some comments when this API will be used?
> >>>>> I was assumed it is only used for drd state machine.
> >>>>
> >>>> drd_state machine didn't even need this API in the first place :).
> >>>> You guys wanted me to separate out start/stop and connect/disconnect for full OTG case.
> >>>> Won't full OTG state machine want to use this API? If not what would it use?
> >>>>
> >>>
> >>> Oh, I meant only drd and fully otg state machine needs it. I am
> >>> wondering if we need have a new API to do it. Two questions:
> >>
> >> OK.
> >>>
> >>> - Except for vbus interrupt, any chances this API will be used at
> >>> current logic?
> >>
> >> I don't think so. But we can't assume caller behaviour for any API.
> >>
> >>> - When this API is called but without a coming gadget->stop?
> >>>
> >> Never for DRD case. But we want to catch wrong users.
> >>
> >
> > In future, otg_start_gadget will be used for both DRD and fully OTG FSM.
> > There is no otg_loc_conn at current DRD FSM, but there is
> > otg_loc_conn at current OTG FSM, see below.
> >
> > DRD FSM:
> > 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;
> >
> > OTG FSM:
> > case OTG_STATE_B_IDLE:
> > otg_drv_vbus(otg, 0);
> > otg_chrg_vbus(otg, 0);
> > otg_loc_conn(otg, 0);
> > otg_loc_sof(otg, 0);
> > /*
> > * Driver is responsible for starting ADP probing
> > * if ADP sensing times out.
> > */
> > otg_start_adp_sns(otg);
> > otg_set_protocol(fsm, PROTO_UNDEF);
> > otg_add_timer(otg, B_SE0_SRP);
> > break;
> > case OTG_STATE_B_PERIPHERAL:
> > otg_chrg_vbus(otg, 0);
> > otg_loc_sof(otg, 0);
> > otg_set_protocol(fsm, PROTO_GADGET);
> > otg_loc_conn(otg, 1);
> > break;
> >
> > My original suggestion is to have an API to do pull dp and this API
> > will be used at both DRD and OTG FSM, and called at otg_loc_conn.
>
> The API is usb_gadget_connect_control();
>
> > The (de)initialize is the same for both two FSMs, it both includes
> > init peripheral mode and pull up dp, and can be done by drd_set_protocol(fsm, PROTO_GADGET)
> > otg_loc_conn(otg, 1);
> >
> > What do you think?
> >
>
> I think loc_conn is a bit confusing to drd users. Another issue I see is that
> DRD controller drivers will need to explicitly pass .loc_conn ops via the otg_fsm_ops.
> This is an additional step and totally unnecessary as it can be automatically done
> via direct DRD -> UDC-core call.
>
If you are stick to that, let's follow your way if Felipe agree with it
too, although it lets the DRD state machine look different with OTG's.
--
Best Regards,
Peter Chen
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 10/14] usb: otg: add hcd companion support |
| Message-ID | <ryicG-1fj-31@gated-at.bofh.it> |
| In reply to | #1400666 |
From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Since some host controller (e.g. EHCI) needs a companion host controller
(e.g. OHCI), this patch adds such a configuration to use it in the OTG
core.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
Documentation/devicetree/bindings/usb/generic.txt | 3 +++
drivers/usb/common/usb-otg.c | 32 ++++++++++++++++-------
include/linux/usb/otg.h | 7 ++++-
3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index f6866c1..1db1c33 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -27,6 +27,9 @@ Optional properties:
- otg-controller: phandle to otg controller. Host or gadget controllers can
contain this property to link it to a particular OTG
controller.
+ - hcd-needs-companion: must be present if otg controller is dealing with
+ EHCI host controller that needs a companion OHCI host
+ controller.
This is an attribute to a USB controller such as:
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 64be6df..8a2a0d4 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
@@ -584,6 +585,10 @@ struct usb_otg *usb_otg_register(struct device *dev,
else
INIT_WORK(&otg->work, usb_drd_work);
+ if (of_find_property(dev->of_node, "hcd-needs-companion", NULL) ||
+ config->hcd_needs_companion) /* needs companion ? */
+ otg->flags |= OTG_FLAG_HCD_NEEDS_COMPANION;
+
otg->wq = create_freezable_workqueue("usb_otg");
if (!otg->wq) {
dev_err(dev, "otg: %s: can't create workqueue\n",
@@ -807,15 +812,18 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
/* HCD will be started by OTG fsm when needed */
mutex_lock(&otg->fsm.lock);
if (otg->primary_hcd.hcd) {
- /* probably a shared HCD ? */
- if (usb_otg_hcd_is_primary_hcd(hcd)) {
+ /* probably a shared HCD or a companion OHCI HCD ? */
+ if (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+ usb_otg_hcd_is_primary_hcd(hcd)) {
dev_err(otg_dev, "otg: primary host already registered\n");
goto err;
}
- if (hcd->shared_hcd == otg->primary_hcd.hcd) {
+ if (otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION ||
+ (hcd->shared_hcd == otg->primary_hcd.hcd)) {
if (otg->shared_hcd.hcd) {
- dev_err(otg_dev, "otg: shared host already registered\n");
+ dev_err(otg_dev,
+ "otg: shared/companion host already registered\n");
goto err;
}
@@ -823,10 +831,12 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
otg->shared_hcd.irqnum = irqnum;
otg->shared_hcd.irqflags = irqflags;
otg->shared_hcd.ops = ops;
- dev_info(otg_dev, "otg: shared host %s registered\n",
+ dev_info(otg_dev,
+ "otg: shared/companion host %s registered\n",
dev_name(hcd->self.controller));
} else {
- dev_err(otg_dev, "otg: invalid shared host %s\n",
+ dev_err(otg_dev,
+ "otg: invalid shared/companion host %s\n",
dev_name(hcd->self.controller));
goto err;
}
@@ -849,14 +859,17 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
* we're ready only if we have shared HCD
* or we don't need shared HCD.
*/
- if (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+ if (otg->shared_hcd.hcd ||
+ (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+ !otg->primary_hcd.hcd->shared_hcd)) {
otg->host = hcd_to_bus(hcd);
/* FIXME: set bus->otg_port if this is true OTG port with HNP */
/* start FSM */
usb_otg_start_fsm(otg);
} else {
- dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+ dev_dbg(otg_dev,
+ "otg: can't start till shared/companion host registers\n");
}
mutex_unlock(&otg->fsm.lock);
@@ -907,7 +920,8 @@ int usb_otg_unregister_hcd(struct usb_hcd *hcd)
dev_name(hcd_dev));
} else if (hcd == otg->shared_hcd.hcd) {
otg->shared_hcd.hcd = NULL;
- dev_info(otg_dev, "otg: shared host %s unregistered\n",
+ dev_info(otg_dev,
+ "otg: shared/companion host %s unregistered\n",
dev_name(hcd_dev));
} else {
dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index b094352..6f4ca77 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -57,7 +57,8 @@ struct otg_hcd {
* @list: list of otg controllers
* @work: otg state machine work
* @wq: otg state machine work queue
- * @flags: to track if host/gadget is running
+ * @flags: to track if host/gadget is running, or to indicate if hcd needs
+ * companion
*/
struct usb_otg {
u8 default_a;
@@ -84,6 +85,7 @@ struct usb_otg {
u32 flags;
#define OTG_FLAG_GADGET_RUNNING (1 << 0)
#define OTG_FLAG_HOST_RUNNING (1 << 1)
+#define OTG_FLAG_HCD_NEEDS_COMPANION (1 << 2)
/* use otg->fsm.lock for serializing access */
/*------------- deprecated interface -----------------------------*/
@@ -125,11 +127,14 @@ struct usb_otg_caps {
* @caps: otg capabilities of the controller
* @ops: otg fsm operations
* @otg_work: optional custom otg state machine work function
+ * @hcd_needs_companion: Indicates if host controller needs a companion
+ * controller
*/
struct usb_otg_config {
struct usb_otg_caps *otg_caps;
struct otg_fsm_ops *fsm_ops;
void (*otg_work)(struct work_struct *work);
+ bool hcd_needs_companion;
};
extern const char *usb_otg_state_string(enum usb_otg_state state);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2016-05-13 20:20 +0200 |
| Subject | Re: [PATCH v8 10/14] usb: otg: add hcd companion support |
| Message-ID | <rypQS-td-5@gated-at.bofh.it> |
| In reply to | #1400669 |
On Fri, May 13, 2016 at 5:03 AM, Roger Quadros <rogerq@ti.com> wrote: > From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> > > Since some host controller (e.g. EHCI) needs a companion host controller > (e.g. OHCI), this patch adds such a configuration to use it in the OTG > core. > > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> > Signed-off-by: Roger Quadros <rogerq@ti.com> > Acked-by: Peter Chen <peter.chen@nxp.com> > --- > Documentation/devicetree/bindings/usb/generic.txt | 3 +++ > drivers/usb/common/usb-otg.c | 32 ++++++++++++++++------- > include/linux/usb/otg.h | 7 ++++- > 3 files changed, 32 insertions(+), 10 deletions(-) > > diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt > index f6866c1..1db1c33 100644 > --- a/Documentation/devicetree/bindings/usb/generic.txt > +++ b/Documentation/devicetree/bindings/usb/generic.txt > @@ -27,6 +27,9 @@ Optional properties: > - otg-controller: phandle to otg controller. Host or gadget controllers can > contain this property to link it to a particular OTG > controller. > + - hcd-needs-companion: must be present if otg controller is dealing with > + EHCI host controller that needs a companion OHCI host > + controller. I thought the conclusion was this is not needed? One thing that is not clear here is otg-controller is a host or device property while hcd-needs-companion is an OTG controller property. These lists should be separated. Rob
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-16 10:20 +0200 |
| Subject | Re: [PATCH v8 10/14] usb: otg: add hcd companion support |
| Message-ID | <rzlUS-4vw-13@gated-at.bofh.it> |
| In reply to | #1400929 |
On 13/05/16 21:13, Rob Herring wrote: > On Fri, May 13, 2016 at 5:03 AM, Roger Quadros <rogerq@ti.com> wrote: >> From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> >> >> Since some host controller (e.g. EHCI) needs a companion host controller >> (e.g. OHCI), this patch adds such a configuration to use it in the OTG >> core. >> >> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> >> Signed-off-by: Roger Quadros <rogerq@ti.com> >> Acked-by: Peter Chen <peter.chen@nxp.com> >> --- >> Documentation/devicetree/bindings/usb/generic.txt | 3 +++ >> drivers/usb/common/usb-otg.c | 32 ++++++++++++++++------- >> include/linux/usb/otg.h | 7 ++++- >> 3 files changed, 32 insertions(+), 10 deletions(-) >> >> diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt >> index f6866c1..1db1c33 100644 >> --- a/Documentation/devicetree/bindings/usb/generic.txt >> +++ b/Documentation/devicetree/bindings/usb/generic.txt >> @@ -27,6 +27,9 @@ Optional properties: >> - otg-controller: phandle to otg controller. Host or gadget controllers can >> contain this property to link it to a particular OTG >> controller. >> + - hcd-needs-companion: must be present if otg controller is dealing with >> + EHCI host controller that needs a companion OHCI host >> + controller. > > I thought the conclusion was this is not needed? This is still needed to differentiate between primary+shared HCD case vs primary + primary-companion HCD case. > > One thing that is not clear here is otg-controller is a host or device > property while hcd-needs-companion is an OTG controller property. > These lists should be separated. Agreed. I'll fix that up. cheers, -roger
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-20 11:40 +0200 |
| Subject | [PATCH v9 10/14] usb: otg: add hcd companion support |
| Message-ID | <rAP4u-3Mf-31@gated-at.bofh.it> |
| In reply to | #1400669 |
Since some host controller (e.g. EHCI) needs a companion host controller
(e.g. OHCI), this patch adds such a configuration to use it in the OTG
core.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
v9:
- add DT property documentation under OTG controllers.
Documentation/devicetree/bindings/usb/generic.txt | 3 +++
drivers/usb/common/usb-otg.c | 32 ++++++++++++++++-------
include/linux/usb/otg.h | 7 ++++-
3 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
index 0887d6e..6013296 100644
--- a/Documentation/devicetree/bindings/usb/generic.txt
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -26,6 +26,9 @@ Optional properties for OTG controllers:
optional for OTG device.
- adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is
optional for OTG device.
+ - hcd-needs-companion: must be present if otg controller is dealing with
+ EHCI host controller that needs a companion OHCI host
+ controller.
Optional properties for host/device controllers:
- otg-controller: phandle to otg controller. Host or gadget controllers can
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 64be6df..8a2a0d4 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
@@ -584,6 +585,10 @@ struct usb_otg *usb_otg_register(struct device *dev,
else
INIT_WORK(&otg->work, usb_drd_work);
+ if (of_find_property(dev->of_node, "hcd-needs-companion", NULL) ||
+ config->hcd_needs_companion) /* needs companion ? */
+ otg->flags |= OTG_FLAG_HCD_NEEDS_COMPANION;
+
otg->wq = create_freezable_workqueue("usb_otg");
if (!otg->wq) {
dev_err(dev, "otg: %s: can't create workqueue\n",
@@ -807,15 +812,18 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
/* HCD will be started by OTG fsm when needed */
mutex_lock(&otg->fsm.lock);
if (otg->primary_hcd.hcd) {
- /* probably a shared HCD ? */
- if (usb_otg_hcd_is_primary_hcd(hcd)) {
+ /* probably a shared HCD or a companion OHCI HCD ? */
+ if (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+ usb_otg_hcd_is_primary_hcd(hcd)) {
dev_err(otg_dev, "otg: primary host already registered\n");
goto err;
}
- if (hcd->shared_hcd == otg->primary_hcd.hcd) {
+ if (otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION ||
+ (hcd->shared_hcd == otg->primary_hcd.hcd)) {
if (otg->shared_hcd.hcd) {
- dev_err(otg_dev, "otg: shared host already registered\n");
+ dev_err(otg_dev,
+ "otg: shared/companion host already registered\n");
goto err;
}
@@ -823,10 +831,12 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
otg->shared_hcd.irqnum = irqnum;
otg->shared_hcd.irqflags = irqflags;
otg->shared_hcd.ops = ops;
- dev_info(otg_dev, "otg: shared host %s registered\n",
+ dev_info(otg_dev,
+ "otg: shared/companion host %s registered\n",
dev_name(hcd->self.controller));
} else {
- dev_err(otg_dev, "otg: invalid shared host %s\n",
+ dev_err(otg_dev,
+ "otg: invalid shared/companion host %s\n",
dev_name(hcd->self.controller));
goto err;
}
@@ -849,14 +859,17 @@ int usb_otg_register_hcd(struct usb_hcd *hcd, unsigned int irqnum,
* we're ready only if we have shared HCD
* or we don't need shared HCD.
*/
- if (otg->shared_hcd.hcd || !otg->primary_hcd.hcd->shared_hcd) {
+ if (otg->shared_hcd.hcd ||
+ (!(otg->flags & OTG_FLAG_HCD_NEEDS_COMPANION) &&
+ !otg->primary_hcd.hcd->shared_hcd)) {
otg->host = hcd_to_bus(hcd);
/* FIXME: set bus->otg_port if this is true OTG port with HNP */
/* start FSM */
usb_otg_start_fsm(otg);
} else {
- dev_dbg(otg_dev, "otg: can't start till shared host registers\n");
+ dev_dbg(otg_dev,
+ "otg: can't start till shared/companion host registers\n");
}
mutex_unlock(&otg->fsm.lock);
@@ -907,7 +920,8 @@ int usb_otg_unregister_hcd(struct usb_hcd *hcd)
dev_name(hcd_dev));
} else if (hcd == otg->shared_hcd.hcd) {
otg->shared_hcd.hcd = NULL;
- dev_info(otg_dev, "otg: shared host %s unregistered\n",
+ dev_info(otg_dev,
+ "otg: shared/companion host %s unregistered\n",
dev_name(hcd_dev));
} else {
dev_err(otg_dev, "otg: host %s wasn't registered with otg\n",
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index b094352..6f4ca77 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -57,7 +57,8 @@ struct otg_hcd {
* @list: list of otg controllers
* @work: otg state machine work
* @wq: otg state machine work queue
- * @flags: to track if host/gadget is running
+ * @flags: to track if host/gadget is running, or to indicate if hcd needs
+ * companion
*/
struct usb_otg {
u8 default_a;
@@ -84,6 +85,7 @@ struct usb_otg {
u32 flags;
#define OTG_FLAG_GADGET_RUNNING (1 << 0)
#define OTG_FLAG_HOST_RUNNING (1 << 1)
+#define OTG_FLAG_HCD_NEEDS_COMPANION (1 << 2)
/* use otg->fsm.lock for serializing access */
/*------------- deprecated interface -----------------------------*/
@@ -125,11 +127,14 @@ struct usb_otg_caps {
* @caps: otg capabilities of the controller
* @ops: otg fsm operations
* @otg_work: optional custom otg state machine work function
+ * @hcd_needs_companion: Indicates if host controller needs a companion
+ * controller
*/
struct usb_otg_config {
struct usb_otg_caps *otg_caps;
struct otg_fsm_ops *fsm_ops;
void (*otg_work)(struct work_struct *work);
+ bool hcd_needs_companion;
};
extern const char *usb_otg_state_string(enum usb_otg_state state);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2016-05-23 23:10 +0200 |
| Subject | Re: [PATCH v9 10/14] usb: otg: add hcd companion support |
| Message-ID | <rC5gS-2zt-35@gated-at.bofh.it> |
| In reply to | #1404285 |
On Fri, May 20, 2016 at 12:32:27PM +0300, Roger Quadros wrote: > Since some host controller (e.g. EHCI) needs a companion host controller > (e.g. OHCI), this patch adds such a configuration to use it in the OTG > core. > > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> > Signed-off-by: Roger Quadros <rogerq@ti.com> > Acked-by: Peter Chen <peter.chen@nxp.com> > --- > v9: > - add DT property documentation under OTG controllers. > > Documentation/devicetree/bindings/usb/generic.txt | 3 +++ Acked-by: Rob Herring <robh@kernel.org> > drivers/usb/common/usb-otg.c | 32 ++++++++++++++++------- > include/linux/usb/otg.h | 7 ++++- > 3 files changed, 32 insertions(+), 10 deletions(-)
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 11/14] usb: otg: use dev_dbg() instead of VDBG() |
| Message-ID | <ryicG-1fj-25@gated-at.bofh.it> |
| In reply to | #1400666 |
Now that we have a device reference in struct usb_otg
let's use dev_dbg() for debug messages.
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Peter Chen <peter.chen@nxp.com>
---
drivers/usb/common/usb-otg-fsm.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 2986b66..e6e58c2 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -30,13 +30,6 @@
#include <linux/usb/otg.h>
#include <linux/usb/otg-fsm.h>
-#ifdef VERBOSE
-#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \
- __func__, ## args)
-#else
-#define VDBG(stuff...) do {} while (0)
-#endif
-
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
{
@@ -44,8 +37,9 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
int ret = 0;
if (fsm->protocol != protocol) {
- VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
- fsm->protocol, protocol);
+ dev_vdbg(otg->dev,
+ "Changing role fsm->protocol= %d; new protocol= %d\n",
+ fsm->protocol, protocol);
/* stop old protocol */
if (fsm->protocol == PROTO_HOST)
ret = otg_start_host(otg, 0);
@@ -226,7 +220,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
if (otg->state == new_state)
return 0;
- VDBG("Set state: %s\n", usb_otg_state_string(new_state));
+ dev_vdbg(otg->dev, "Set state: %s\n", usb_otg_state_string(new_state));
otg_leave_state(fsm, otg->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
@@ -358,7 +352,7 @@ int otg_statemachine(struct usb_otg *otg)
switch (state) {
case OTG_STATE_UNDEFINED:
- VDBG("fsm->id = %d\n", fsm->id);
+ dev_vdbg(otg->dev, "fsm->id = %d\n", fsm->id);
if (fsm->id)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else
@@ -466,7 +460,8 @@ int otg_statemachine(struct usb_otg *otg)
}
mutex_unlock(&fsm->lock);
- VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
+ dev_vdbg(otg->dev, "quit statemachine, changed = %d\n",
+ fsm->state_changed);
return fsm->state_changed;
}
EXPORT_SYMBOL_GPL(otg_statemachine);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 12/14] usb: hcd: Adapt to OTG core |
| Message-ID | <ryicG-1fj-23@gated-at.bofh.it> |
| In reply to | #1400666 |
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
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 14/14] usb: host: xhci-plat: Add otg device to platform data |
| Message-ID | <ryicG-1fj-29@gated-at.bofh.it> |
| In reply to | #1400666 |
Host controllers that are part of an OTG/dual-role instance
need to somehow pass the OTG controller device information
to the HCD core.
We use platform data to pass the OTG controller device.
Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Peter Chen <peter.chen@nxp.com>
---
drivers/usb/host/xhci-plat.c | 35 ++++++++++++++++++++++++++++-------
include/linux/usb/xhci_pdriver.h | 3 +++
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 5c15e9b..84ebe18 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -230,11 +230,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_usb3_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (pdata && pdata->otg_dev)
+ ret = usb_otg_add_hcd(hcd, irq, IRQF_SHARED, pdata->otg_dev);
+ else
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+
if (ret)
goto disable_usb_phy;
- ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ if (pdata && pdata->otg_dev)
+ ret = usb_otg_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED,
+ pdata->otg_dev);
+ else
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+
if (ret)
goto dealloc_usb2_hcd;
@@ -242,7 +251,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
dealloc_usb2_hcd:
- usb_remove_hcd(hcd);
+ if (pdata && pdata->otg_dev)
+ usb_otg_remove_hcd(hcd);
+ else
+ usb_remove_hcd(hcd);
disable_usb_phy:
usb_phy_shutdown(hcd->usb_phy);
@@ -260,16 +272,25 @@ put_hcd:
return ret;
}
-static int xhci_plat_remove(struct platform_device *dev)
+static int xhci_plat_remove(struct platform_device *pdev)
{
- struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct clk *clk = xhci->clk;
+ struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+ if (pdata && pdata->otg_dev)
+ usb_otg_remove_hcd(xhci->shared_hcd);
+ else
+ usb_remove_hcd(xhci->shared_hcd);
- usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy);
- usb_remove_hcd(hcd);
+ if (pdata && pdata->otg_dev)
+ usb_otg_remove_hcd(hcd);
+ else
+ usb_remove_hcd(hcd);
+
usb_put_hcd(xhci->shared_hcd);
if (!IS_ERR(clk))
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
index 376654b..5c68b83 100644
--- a/include/linux/usb/xhci_pdriver.h
+++ b/include/linux/usb/xhci_pdriver.h
@@ -18,10 +18,13 @@
*
* @usb3_lpm_capable: determines if this xhci platform supports USB3
* LPM capability
+ * @otg_dev: OTG controller device. Only requied if part of
+ * OTG/dual-role.
*
*/
struct usb_xhci_pdata {
unsigned usb3_lpm_capable:1;
+ struct device *otg_dev;
};
#endif /* __USB_CORE_XHCI_PDRIVER_H */
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 03/14] usb: hcd.h: Add OTG to HCD interface |
| Message-ID | <ryicG-1fj-33@gated-at.bofh.it> |
| In reply to | #1400666 |
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>
---
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
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-13 12:10 +0200 |
| Subject | [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <ryicG-1fj-27@gated-at.bofh.it> |
| In reply to | #1400666 |
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 | 1042 ++++++++++++++++++++++++++++++++++++++++++
drivers/usb/core/Kconfig | 4 +-
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 ++++++-
7 files changed, 1206 insertions(+), 6 deletions(-)
create mode 100644 drivers/usb/common/usb-otg.c
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..64be6df
--- /dev/null
+++ b/drivers/usb/common/usb-otg.c
@@ -0,0 +1,1042 @@
+/**
+ * drivers/usb/common/usb-otg.c - USB OTG core
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.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) {
+ otg->gadget_ops->connect_control(otg->gadget, false);
+ ret = otg_start_gadget(otg, 0);
+ }
+
+ if (ret)
+ return ret;
+
+ /* start new protocol */
+ if (protocol == PROTO_HOST) {
+ ret = otg_start_host(otg, 1);
+ } else if (protocol == PROTO_GADGET) {
+ ret = otg_start_gadget(otg, 1);
+ otg->gadget_ops->connect_control(otg->gadget, true);
+ }
+
+ if (ret)
+ return ret;
+
+ fsm->protocol = protocol;
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * Called when entering a DRD state.
+ * fsm->lock must be held.
+ */
+static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+ struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm);
+
+ if (otg->state == new_state)
+ return;
+
+ fsm->state_changed = 1;
+ dev_dbg(otg->dev, "otg: set state: %s\n",
+ usb_otg_state_string(new_state));
+ switch (new_state) {
+ case OTG_STATE_B_IDLE:
+ drd_set_protocol(fsm, PROTO_UNDEF);
+ otg_drv_vbus(otg, 0);
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ drd_set_protocol(fsm, PROTO_GADGET);
+ otg_drv_vbus(otg, 0);
+ break;
+ case OTG_STATE_A_HOST:
+ drd_set_protocol(fsm, PROTO_HOST);
+ otg_drv_vbus(otg, 1);
+ break;
+ default:
+ dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
+ __func__, usb_otg_state_string(new_state));
+ break;
+ }
+
+ otg->state = new_state;
+}
+
+/**
+ * DRD state change judgement
+ *
+ * For DRD we're only interested in some of the OTG states
+ * i.e. OTG_STATE_B_IDLE: both peripheral and host are stopped
+ * OTG_STATE_B_PERIPHERAL: peripheral active
+ * OTG_STATE_A_HOST: host active
+ * we're only interested in the following inputs
+ * fsm->id, fsm->b_sess_vld
+ */
+int drd_statemachine(struct usb_otg *otg)
+{
+ struct otg_fsm *fsm = &otg->fsm;
+ enum usb_otg_state state;
+ int ret;
+
+ mutex_lock(&fsm->lock);
+
+ fsm->state_changed = 0;
+ state = otg->state;
+
+ switch (state) {
+ case OTG_STATE_UNDEFINED:
+ if (!fsm->id)
+ drd_set_state(fsm, OTG_STATE_A_HOST);
+ else if (fsm->id && fsm->b_sess_vld)
+ drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+ else
+ drd_set_state(fsm, OTG_STATE_B_IDLE);
+ break;
+ case OTG_STATE_B_IDLE:
+ if (!fsm->id)
+ drd_set_state(fsm, OTG_STATE_A_HOST);
+ else if (fsm->b_sess_vld)
+ drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ if (!fsm->id)
+ drd_set_state(fsm, OTG_STATE_A_HOST);
+ else if (!fsm->b_sess_vld)
+ drd_set_state(fsm, OTG_STATE_B_IDLE);
+ break;
+ case OTG_STATE_A_HOST:
+ if (fsm->id && fsm->b_sess_vld)
+ drd_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+ else if (fsm->id && !fsm->b_sess_vld)
+ drd_set_state(fsm, OTG_STATE_B_IDLE);
+ break;
+
+ default:
+ dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
+ __func__, usb_otg_state_string(state));
+ break;
+ }
+
+ ret = fsm->state_changed;
+ mutex_unlock(&fsm->lock);
+ dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n",
+ fsm->state_changed);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(drd_statemachine);
+
+/**
+ * Dual-role device (DRD) work function
+ */
+static void usb_drd_work(struct work_struct *work)
+{
+ struct usb_otg *otg = container_of(work, struct usb_otg, work);
+
+ pm_runtime_get_sync(otg->dev);
+ 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_freezable_workqueue("usb_otg");
+ if (!otg->wq) {
+ dev_err(dev, "otg: %s: can't create workqueue\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_wq;
+ }
+
+ /* set otg ops */
+ otg->fsm.ops = config->fsm_ops;
+
+ mutex_init(&otg->fsm.lock);
+
+ list_add_tail(&otg->list, &otg_list);
+ mutex_unlock(&otg_list_mutex);
+
+ /* 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/core/Kconfig b/drivers/usb/core/Kconfig
index ae228d0..de371e6 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -42,8 +42,8 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here.
config USB_OTG
- bool "OTG support"
- depends on PM
+ bool "OTG/Dual-role support"
+ depends on PM && USB_GADGET
default n
help
The most notable feature of USB OTG is support for a
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 20a2f8a..3ecfddd 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]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-16 11:10 +0200 |
| Subject | Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <rzmHg-52I-11@gated-at.bofh.it> |
| In reply to | #1400674 |
On 13/05/16 13:03, Roger Quadros wrote:
> It provides APIs for the following tasks
>
> - Registering an OTG/dual-role capable controller
> - Registering Host and Gadget controllers to OTG core
> - Providing inputs to and kicking the OTG state machine
>
> Provide a dual-role device (DRD) state machine.
> DRD mode is a reduced functionality OTG mode. In this mode
> we don't support SRP, HNP and dynamic role-swap.
>
> In DRD operation, the controller mode (Host or Peripheral)
> is decided based on the ID pin status. Once a cable plug (Type-A
> or Type-B) is attached the controller selects the state
> and doesn't change till the cable in unplugged and a different
> cable type is inserted.
>
> As we don't need most of the complex OTG states and OTG timers
> we implement a lean DRD state machine in usb-otg.c.
> The DRD state machine is only interested in 2 hardware inputs
> 'id' and 'b_sess_vld'.
>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> drivers/usb/common/Makefile | 2 +-
> drivers/usb/common/usb-otg.c | 1042 ++++++++++++++++++++++++++++++++++++++++++
> drivers/usb/core/Kconfig | 4 +-
> 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 ++++++-
> 7 files changed, 1206 insertions(+), 6 deletions(-)
> create mode 100644 drivers/usb/common/usb-otg.c
This patch causes the following build issues when CONFIG_USB_GADGET=m, CONFIG_USB=m,
CONFIG_USB_COMMON=m and CONFIG_USB_OTG=y
ERROR: "usb_otg_register_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
ERROR: "usb_otg_unregister_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
ERROR: "usb_otg_register_hcd" [drivers/usb/core/usbcore.ko] undefined!
ERROR: "usb_otg_unregister_hcd" [drivers/usb/core/usbcore.ko] undefined!
ERROR: "otg_statemachine" [drivers/usb/chipidea/ci_hdrc.ko] undefined!
scripts/Makefile.modpost:91: recipe for target '__modpost' failed
make[1]: *** [__modpost] Error 1
Makefile:1141: recipe for target 'modules' failed
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....
drivers/built-in.o: In function `drd_set_state':
usb-otg.c:(.text+0x2b4242): undefined reference to `usb_otg_state_string'
drivers/built-in.o: In function `drd_statemachine':
(.text+0x2b4b4c): undefined reference to `usb_otg_state_string'
Makefile:937: recipe for target 'vmlinux' failed
I'll fix it up with the following diff.
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca7856..16a5b55 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_GADGET) += gadget/
obj-$(CONFIG_USB_COMMON) += common/
+obj-$(CONFIG_USB_OTG) += common/
obj-$(CONFIG_USBIP_CORE) += usbip/
diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
index 77048aa..17e449e 100644
--- a/drivers/usb/common/usb-otg.c
+++ b/drivers/usb/common/usb-otg.c
@@ -56,6 +56,30 @@ static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
return hcd == hcd->primary_hcd;
}
+static const char *otg_state_string(enum usb_otg_state state)
+{
+ static const char *const names[] = {
+ [OTG_STATE_A_IDLE] = "a_idle",
+ [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
+ [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
+ [OTG_STATE_A_HOST] = "a_host",
+ [OTG_STATE_A_SUSPEND] = "a_suspend",
+ [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
+ [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
+ [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
+ [OTG_STATE_B_IDLE] = "b_idle",
+ [OTG_STATE_B_SRP_INIT] = "b_srp_init",
+ [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
+ [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
+ [OTG_STATE_B_HOST] = "b_host",
+ };
+
+ if (state < 0 || state >= ARRAY_SIZE(names))
+ return "UNDEFINED";
+
+ return names[state];
+}
+
/**
* Check if the OTG device is in our wait list and return
* otg_wait_data, else NULL.
@@ -433,7 +457,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
fsm->state_changed = 1;
dev_dbg(otg->dev, "otg: set state: %s\n",
- usb_otg_state_string(new_state));
+ otg_state_string(new_state));
switch (new_state) {
case OTG_STATE_B_IDLE:
drd_set_protocol(fsm, PROTO_UNDEF);
@@ -449,7 +473,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
break;
default:
dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
- __func__, usb_otg_state_string(new_state));
+ __func__, otg_state_string(new_state));
break;
}
@@ -507,7 +531,7 @@ int drd_statemachine(struct usb_otg *otg)
default:
dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
- __func__, usb_otg_state_string(state));
+ __func__, otg_state_string(state));
break;
}
--
cheers,
-roger
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-18 15:10 +0200 |
| Subject | Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <rA9oB-2yO-1@gated-at.bofh.it> |
| In reply to | #1401381 |
Hi Peter,
On 18/05/16 10:45, Peter Chen wrote:
>
>
> On Mon, May 16, 2016 at 5:00 PM, Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>> wrote:
>
> On 13/05/16 13:03, Roger Quadros wrote:
> > It provides APIs for the following tasks
> >
> > - Registering an OTG/dual-role capable controller
> > - Registering Host and Gadget controllers to OTG core
> > - Providing inputs to and kicking the OTG state machine
> >
> > Provide a dual-role device (DRD) state machine.
> > DRD mode is a reduced functionality OTG mode. In this mode
> > we don't support SRP, HNP and dynamic role-swap.
> >
> > In DRD operation, the controller mode (Host or Peripheral)
> > is decided based on the ID pin status. Once a cable plug (Type-A
> > or Type-B) is attached the controller selects the state
> > and doesn't change till the cable in unplugged and a different
> > cable type is inserted.
> >
> > As we don't need most of the complex OTG states and OTG timers
> > we implement a lean DRD state machine in usb-otg.c.
> > The DRD state machine is only interested in 2 hardware inputs
> > 'id' and 'b_sess_vld'.
> >
> > Signed-off-by: Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>>
> > ---
> > drivers/usb/common/Makefile | 2 +-
> > drivers/usb/common/usb-otg.c | 1042 ++++++++++++++++++++++++++++++++++++++++++
> > drivers/usb/core/Kconfig | 4 +-
> > 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 ++++++-
> > 7 files changed, 1206 insertions(+), 6 deletions(-)
> > create mode 100644 drivers/usb/common/usb-otg.c
>
>
> This patch causes the following build issues when CONFIG_USB_GADGET=m, CONFIG_USB=m,
> CONFIG_USB_COMMON=m and CONFIG_USB_OTG=y
>
> ERROR: "usb_otg_register_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
> ERROR: "usb_otg_unregister_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
> ERROR: "usb_otg_register_hcd" [drivers/usb/core/usbcore.ko] undefined!
> ERROR: "usb_otg_unregister_hcd" [drivers/usb/core/usbcore.ko] undefined!
> ERROR: "otg_statemachine" [drivers/usb/chipidea/ci_hdrc.ko] undefined!
> scripts/Makefile.modpost:91: recipe for target '__modpost' failed
> make[1]: *** [__modpost] Error 1
> Makefile:1141: recipe for target 'modules' failed
> make: *** [modules] Error 2
> make: *** Waiting for unfinished jobs....
>
> drivers/built-in.o: In function `drd_set_state':
> usb-otg.c:(.text+0x2b4242): undefined reference to `usb_otg_state_string'
> drivers/built-in.o: In function `drd_statemachine':
> (.text+0x2b4b4c): undefined reference to `usb_otg_state_string'
> Makefile:937: recipe for target 'vmlinux' failed
>
> I'll fix it up with the following diff.
>
> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
> index dca7856..16a5b55 100644
> --- a/drivers/usb/Makefile
> +++ b/drivers/usb/Makefile
> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
> obj-$(CONFIG_USB_GADGET) += gadget/
>
> obj-$(CONFIG_USB_COMMON) += common/
> +obj-$(CONFIG_USB_OTG) += common/
>
> obj-$(CONFIG_USBIP_CORE) += usbip/
> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> index 77048aa..17e449e 100644
> --- a/drivers/usb/common/usb-otg.c
> +++ b/drivers/usb/common/usb-otg.c
> @@ -56,6 +56,30 @@ static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
> return hcd == hcd->primary_hcd;
> }
>
> +static const char *otg_state_string(enum usb_otg_state state)
> +{
> + static const char *const names[] = {
> + [OTG_STATE_A_IDLE] = "a_idle",
> + [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
> + [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
> + [OTG_STATE_A_HOST] = "a_host",
> + [OTG_STATE_A_SUSPEND] = "a_suspend",
> + [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
> + [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
> + [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
> + [OTG_STATE_B_IDLE] = "b_idle",
> + [OTG_STATE_B_SRP_INIT] = "b_srp_init",
> + [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
> + [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
> + [OTG_STATE_B_HOST] = "b_host",
> + };
> +
> + if (state < 0 || state >= ARRAY_SIZE(names))
> + return "UNDEFINED";
> +
> + return names[state];
> +}
> +
>
>
>
> From my point, make another copy for otg stuff is not a good way,
> could we make folder under usb/ named otg for dedicated otg stuffs,
> in that case, build otg stuffs can not depend on USB_COMMON.
OK. I can try that. I'll delete otg_state_string from usb-common.c and
move it into usb/otg/usb-otg.c
I'll also move usb-otg-fsm.c to usb/otg/.
cheers,
-roger
>
> Peter
>
>
> /**
> * Check if the OTG device is in our wait list and return
> * otg_wait_data, else NULL.
> @@ -433,7 +457,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>
> fsm->state_changed = 1;
> dev_dbg(otg->dev, "otg: set state: %s\n",
> - usb_otg_state_string(new_state));
> + otg_state_string(new_state));
> switch (new_state) {
> case OTG_STATE_B_IDLE:
> drd_set_protocol(fsm, PROTO_UNDEF);
> @@ -449,7 +473,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
> break;
> default:
> dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
> - __func__, usb_otg_state_string(new_state));
> + __func__, otg_state_string(new_state));
> break;
> }
>
> @@ -507,7 +531,7 @@ int drd_statemachine(struct usb_otg *otg)
>
> default:
> dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
> - __func__, usb_otg_state_string(state));
> + __func__, otg_state_string(state));
> break;
> }
>
> --
> cheers,
> -roger
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org <mailto:majordomo@vger.kernel.org>
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
>
>
> --
> BR,
> Peter Chen
[toc] | [prev] | [next] | [standalone]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-20 10:40 +0200 |
| Subject | Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <rAO8q-3ca-29@gated-at.bofh.it> |
| In reply to | #1402963 |
On 18/05/16 15:59, Roger Quadros wrote:
> Hi Peter,
>
> On 18/05/16 10:45, Peter Chen wrote:
>>
>>
>> On Mon, May 16, 2016 at 5:00 PM, Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>> wrote:
>>
>> On 13/05/16 13:03, Roger Quadros wrote:
>> > It provides APIs for the following tasks
>> >
>> > - Registering an OTG/dual-role capable controller
>> > - Registering Host and Gadget controllers to OTG core
>> > - Providing inputs to and kicking the OTG state machine
>> >
>> > Provide a dual-role device (DRD) state machine.
>> > DRD mode is a reduced functionality OTG mode. In this mode
>> > we don't support SRP, HNP and dynamic role-swap.
>> >
>> > In DRD operation, the controller mode (Host or Peripheral)
>> > is decided based on the ID pin status. Once a cable plug (Type-A
>> > or Type-B) is attached the controller selects the state
>> > and doesn't change till the cable in unplugged and a different
>> > cable type is inserted.
>> >
>> > As we don't need most of the complex OTG states and OTG timers
>> > we implement a lean DRD state machine in usb-otg.c.
>> > The DRD state machine is only interested in 2 hardware inputs
>> > 'id' and 'b_sess_vld'.
>> >
>> > Signed-off-by: Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>>
>> > ---
>> > drivers/usb/common/Makefile | 2 +-
>> > drivers/usb/common/usb-otg.c | 1042 ++++++++++++++++++++++++++++++++++++++++++
>> > drivers/usb/core/Kconfig | 4 +-
>> > 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 ++++++-
>> > 7 files changed, 1206 insertions(+), 6 deletions(-)
>> > create mode 100644 drivers/usb/common/usb-otg.c
>>
>>
>> This patch causes the following build issues when CONFIG_USB_GADGET=m, CONFIG_USB=m,
>> CONFIG_USB_COMMON=m and CONFIG_USB_OTG=y
>>
>> ERROR: "usb_otg_register_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
>> ERROR: "usb_otg_unregister_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
>> ERROR: "usb_otg_register_hcd" [drivers/usb/core/usbcore.ko] undefined!
>> ERROR: "usb_otg_unregister_hcd" [drivers/usb/core/usbcore.ko] undefined!
>> ERROR: "otg_statemachine" [drivers/usb/chipidea/ci_hdrc.ko] undefined!
>> scripts/Makefile.modpost:91: recipe for target '__modpost' failed
>> make[1]: *** [__modpost] Error 1
>> Makefile:1141: recipe for target 'modules' failed
>> make: *** [modules] Error 2
>> make: *** Waiting for unfinished jobs....
>>
>> drivers/built-in.o: In function `drd_set_state':
>> usb-otg.c:(.text+0x2b4242): undefined reference to `usb_otg_state_string'
>> drivers/built-in.o: In function `drd_statemachine':
>> (.text+0x2b4b4c): undefined reference to `usb_otg_state_string'
>> Makefile:937: recipe for target 'vmlinux' failed
>>
>> I'll fix it up with the following diff.
>>
>> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
>> index dca7856..16a5b55 100644
>> --- a/drivers/usb/Makefile
>> +++ b/drivers/usb/Makefile
>> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
>> obj-$(CONFIG_USB_GADGET) += gadget/
>>
>> obj-$(CONFIG_USB_COMMON) += common/
>> +obj-$(CONFIG_USB_OTG) += common/
>>
>> obj-$(CONFIG_USBIP_CORE) += usbip/
>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>> index 77048aa..17e449e 100644
>> --- a/drivers/usb/common/usb-otg.c
>> +++ b/drivers/usb/common/usb-otg.c
>> @@ -56,6 +56,30 @@ static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>> return hcd == hcd->primary_hcd;
>> }
>>
>> +static const char *otg_state_string(enum usb_otg_state state)
>> +{
>> + static const char *const names[] = {
>> + [OTG_STATE_A_IDLE] = "a_idle",
>> + [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
>> + [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
>> + [OTG_STATE_A_HOST] = "a_host",
>> + [OTG_STATE_A_SUSPEND] = "a_suspend",
>> + [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
>> + [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
>> + [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
>> + [OTG_STATE_B_IDLE] = "b_idle",
>> + [OTG_STATE_B_SRP_INIT] = "b_srp_init",
>> + [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
>> + [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
>> + [OTG_STATE_B_HOST] = "b_host",
>> + };
>> +
>> + if (state < 0 || state >= ARRAY_SIZE(names))
>> + return "UNDEFINED";
>> +
>> + return names[state];
>> +}
>> +
>>
>>
>>
>> From my point, make another copy for otg stuff is not a good way,
>> could we make folder under usb/ named otg for dedicated otg stuffs,
>> in that case, build otg stuffs can not depend on USB_COMMON.
>
> OK. I can try that. I'll delete otg_state_string from usb-common.c and
> move it into usb/otg/usb-otg.c
>
> I'll also move usb-otg-fsm.c to usb/otg/.
But we can't delete usb_otg_state_string() from usb-common.c. That is used at a
number of places whether OTG is enabled or not.
One option is to make usb-common built in when otg is enabled. What do you say?
cheers,
-roger
>> /**
>> * Check if the OTG device is in our wait list and return
>> * otg_wait_data, else NULL.
>> @@ -433,7 +457,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>>
>> fsm->state_changed = 1;
>> dev_dbg(otg->dev, "otg: set state: %s\n",
>> - usb_otg_state_string(new_state));
>> + otg_state_string(new_state));
>> switch (new_state) {
>> case OTG_STATE_B_IDLE:
>> drd_set_protocol(fsm, PROTO_UNDEF);
>> @@ -449,7 +473,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>> break;
>> default:
>> dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
>> - __func__, usb_otg_state_string(new_state));
>> + __func__, otg_state_string(new_state));
>> break;
>> }
>>
>> @@ -507,7 +531,7 @@ int drd_statemachine(struct usb_otg *otg)
>>
>> default:
>> dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
>> - __func__, usb_otg_state_string(state));
>> + __func__, otg_state_string(state));
>> break;
>> }
>>
>> --
>> cheers,
>> -roger
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo@vger.kernel.org <mailto:majordomo@vger.kernel.org>
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>>
>>
>> --
>> BR,
>> Peter Chen
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" 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]
| From | Roger Quadros <rogerq@ti.com> |
|---|---|
| Date | 2016-05-20 11:20 +0200 |
| Subject | Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <rAOL8-3Eg-19@gated-at.bofh.it> |
| In reply to | #1404251 |
On 20/05/16 11:31, Roger Quadros wrote:
> On 18/05/16 15:59, Roger Quadros wrote:
>> Hi Peter,
>>
>> On 18/05/16 10:45, Peter Chen wrote:
>>>
>>>
>>> On Mon, May 16, 2016 at 5:00 PM, Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>> wrote:
>>>
>>> On 13/05/16 13:03, Roger Quadros wrote:
>>> > It provides APIs for the following tasks
>>> >
>>> > - Registering an OTG/dual-role capable controller
>>> > - Registering Host and Gadget controllers to OTG core
>>> > - Providing inputs to and kicking the OTG state machine
>>> >
>>> > Provide a dual-role device (DRD) state machine.
>>> > DRD mode is a reduced functionality OTG mode. In this mode
>>> > we don't support SRP, HNP and dynamic role-swap.
>>> >
>>> > In DRD operation, the controller mode (Host or Peripheral)
>>> > is decided based on the ID pin status. Once a cable plug (Type-A
>>> > or Type-B) is attached the controller selects the state
>>> > and doesn't change till the cable in unplugged and a different
>>> > cable type is inserted.
>>> >
>>> > As we don't need most of the complex OTG states and OTG timers
>>> > we implement a lean DRD state machine in usb-otg.c.
>>> > The DRD state machine is only interested in 2 hardware inputs
>>> > 'id' and 'b_sess_vld'.
>>> >
>>> > Signed-off-by: Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>>
>>> > ---
>>> > drivers/usb/common/Makefile | 2 +-
>>> > drivers/usb/common/usb-otg.c | 1042 ++++++++++++++++++++++++++++++++++++++++++
>>> > drivers/usb/core/Kconfig | 4 +-
>>> > 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 ++++++-
>>> > 7 files changed, 1206 insertions(+), 6 deletions(-)
>>> > create mode 100644 drivers/usb/common/usb-otg.c
>>>
>>>
>>> This patch causes the following build issues when CONFIG_USB_GADGET=m, CONFIG_USB=m,
>>> CONFIG_USB_COMMON=m and CONFIG_USB_OTG=y
>>>
>>> ERROR: "usb_otg_register_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
>>> ERROR: "usb_otg_unregister_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
>>> ERROR: "usb_otg_register_hcd" [drivers/usb/core/usbcore.ko] undefined!
>>> ERROR: "usb_otg_unregister_hcd" [drivers/usb/core/usbcore.ko] undefined!
>>> ERROR: "otg_statemachine" [drivers/usb/chipidea/ci_hdrc.ko] undefined!
>>> scripts/Makefile.modpost:91: recipe for target '__modpost' failed
>>> make[1]: *** [__modpost] Error 1
>>> Makefile:1141: recipe for target 'modules' failed
>>> make: *** [modules] Error 2
>>> make: *** Waiting for unfinished jobs....
>>>
>>> drivers/built-in.o: In function `drd_set_state':
>>> usb-otg.c:(.text+0x2b4242): undefined reference to `usb_otg_state_string'
>>> drivers/built-in.o: In function `drd_statemachine':
>>> (.text+0x2b4b4c): undefined reference to `usb_otg_state_string'
>>> Makefile:937: recipe for target 'vmlinux' failed
>>>
>>> I'll fix it up with the following diff.
>>>
>>> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
>>> index dca7856..16a5b55 100644
>>> --- a/drivers/usb/Makefile
>>> +++ b/drivers/usb/Makefile
>>> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
>>> obj-$(CONFIG_USB_GADGET) += gadget/
>>>
>>> obj-$(CONFIG_USB_COMMON) += common/
>>> +obj-$(CONFIG_USB_OTG) += common/
>>>
>>> obj-$(CONFIG_USBIP_CORE) += usbip/
>>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
>>> index 77048aa..17e449e 100644
>>> --- a/drivers/usb/common/usb-otg.c
>>> +++ b/drivers/usb/common/usb-otg.c
>>> @@ -56,6 +56,30 @@ static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
>>> return hcd == hcd->primary_hcd;
>>> }
>>>
>>> +static const char *otg_state_string(enum usb_otg_state state)
>>> +{
>>> + static const char *const names[] = {
>>> + [OTG_STATE_A_IDLE] = "a_idle",
>>> + [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
>>> + [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
>>> + [OTG_STATE_A_HOST] = "a_host",
>>> + [OTG_STATE_A_SUSPEND] = "a_suspend",
>>> + [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
>>> + [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
>>> + [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
>>> + [OTG_STATE_B_IDLE] = "b_idle",
>>> + [OTG_STATE_B_SRP_INIT] = "b_srp_init",
>>> + [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
>>> + [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
>>> + [OTG_STATE_B_HOST] = "b_host",
>>> + };
>>> +
>>> + if (state < 0 || state >= ARRAY_SIZE(names))
>>> + return "UNDEFINED";
>>> +
>>> + return names[state];
>>> +}
>>> +
>>>
>>>
>>>
>>> From my point, make another copy for otg stuff is not a good way,
>>> could we make folder under usb/ named otg for dedicated otg stuffs,
>>> in that case, build otg stuffs can not depend on USB_COMMON.
>>
>> OK. I can try that. I'll delete otg_state_string from usb-common.c and
>> move it into usb/otg/usb-otg.c
>>
>> I'll also move usb-otg-fsm.c to usb/otg/.
>
> But we can't delete usb_otg_state_string() from usb-common.c. That is used at a
> number of places whether OTG is enabled or not.
>
> One option is to make usb-common built in when otg is enabled. What do you say?
>
This should also get solved if we make USB_OTG tristate so that it is same as
USB_COMMON.
However I haven't had success in making Kconfig behave like this.
USB_OTG = y if USB == y && GADGET = m
USB_OTG = y if USB == m && GADGET = y
Is there any Kconfig trickery to get this behaviour?
cheers,
-roger
> cheers,
> -roger
>
>>> /**
>>> * Check if the OTG device is in our wait list and return
>>> * otg_wait_data, else NULL.
>>> @@ -433,7 +457,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>>>
>>> fsm->state_changed = 1;
>>> dev_dbg(otg->dev, "otg: set state: %s\n",
>>> - usb_otg_state_string(new_state));
>>> + otg_state_string(new_state));
>>> switch (new_state) {
>>> case OTG_STATE_B_IDLE:
>>> drd_set_protocol(fsm, PROTO_UNDEF);
>>> @@ -449,7 +473,7 @@ static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
>>> break;
>>> default:
>>> dev_warn(otg->dev, "%s: otg: invalid state: %s\n",
>>> - __func__, usb_otg_state_string(new_state));
>>> + __func__, otg_state_string(new_state));
>>> break;
>>> }
>>>
>>> @@ -507,7 +531,7 @@ int drd_statemachine(struct usb_otg *otg)
>>>
>>> default:
>>> dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n",
>>> - __func__, usb_otg_state_string(state));
>>> + __func__, otg_state_string(state));
>>> break;
>>> }
>>>
>>> --
>>> cheers,
>>> -roger
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>>> the body of a message to majordomo@vger.kernel.org <mailto:majordomo@vger.kernel.org>
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>>
>>>
>>>
>>> --
>>> BR,
>>> Peter Chen
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" 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]
| From | Peter Chen <hzpeterchen@gmail.com> |
|---|---|
| Date | 2016-05-20 12:00 +0200 |
| Subject | Re: [PATCH v8 08/14] usb: otg: add OTG/dual-role core |
| Message-ID | <rAPnQ-3SW-17@gated-at.bofh.it> |
| In reply to | #1404274 |
On Fri, May 20, 2016 at 12:19:07PM +0300, Roger Quadros wrote:
> On 20/05/16 11:31, Roger Quadros wrote:
> > On 18/05/16 15:59, Roger Quadros wrote:
> >> Hi Peter,
> >>
> >> On 18/05/16 10:45, Peter Chen wrote:
> >>>
> >>>
> >>> On Mon, May 16, 2016 at 5:00 PM, Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>> wrote:
> >>>
> >>> On 13/05/16 13:03, Roger Quadros wrote:
> >>> > It provides APIs for the following tasks
> >>> >
> >>> > - Registering an OTG/dual-role capable controller
> >>> > - Registering Host and Gadget controllers to OTG core
> >>> > - Providing inputs to and kicking the OTG state machine
> >>> >
> >>> > Provide a dual-role device (DRD) state machine.
> >>> > DRD mode is a reduced functionality OTG mode. In this mode
> >>> > we don't support SRP, HNP and dynamic role-swap.
> >>> >
> >>> > In DRD operation, the controller mode (Host or Peripheral)
> >>> > is decided based on the ID pin status. Once a cable plug (Type-A
> >>> > or Type-B) is attached the controller selects the state
> >>> > and doesn't change till the cable in unplugged and a different
> >>> > cable type is inserted.
> >>> >
> >>> > As we don't need most of the complex OTG states and OTG timers
> >>> > we implement a lean DRD state machine in usb-otg.c.
> >>> > The DRD state machine is only interested in 2 hardware inputs
> >>> > 'id' and 'b_sess_vld'.
> >>> >
> >>> > Signed-off-by: Roger Quadros <rogerq@ti.com <mailto:rogerq@ti.com>>
> >>> > ---
> >>> > drivers/usb/common/Makefile | 2 +-
> >>> > drivers/usb/common/usb-otg.c | 1042 ++++++++++++++++++++++++++++++++++++++++++
> >>> > drivers/usb/core/Kconfig | 4 +-
> >>> > 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 ++++++-
> >>> > 7 files changed, 1206 insertions(+), 6 deletions(-)
> >>> > create mode 100644 drivers/usb/common/usb-otg.c
> >>>
> >>>
> >>> This patch causes the following build issues when CONFIG_USB_GADGET=m, CONFIG_USB=m,
> >>> CONFIG_USB_COMMON=m and CONFIG_USB_OTG=y
> >>>
> >>> ERROR: "usb_otg_register_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
> >>> ERROR: "usb_otg_unregister_gadget" [drivers/usb/gadget/udc/udc-core.ko] undefined!
> >>> ERROR: "usb_otg_register_hcd" [drivers/usb/core/usbcore.ko] undefined!
> >>> ERROR: "usb_otg_unregister_hcd" [drivers/usb/core/usbcore.ko] undefined!
> >>> ERROR: "otg_statemachine" [drivers/usb/chipidea/ci_hdrc.ko] undefined!
> >>> scripts/Makefile.modpost:91: recipe for target '__modpost' failed
> >>> make[1]: *** [__modpost] Error 1
> >>> Makefile:1141: recipe for target 'modules' failed
> >>> make: *** [modules] Error 2
> >>> make: *** Waiting for unfinished jobs....
> >>>
> >>> drivers/built-in.o: In function `drd_set_state':
> >>> usb-otg.c:(.text+0x2b4242): undefined reference to `usb_otg_state_string'
> >>> drivers/built-in.o: In function `drd_statemachine':
> >>> (.text+0x2b4b4c): undefined reference to `usb_otg_state_string'
> >>> Makefile:937: recipe for target 'vmlinux' failed
> >>>
> >>> I'll fix it up with the following diff.
> >>>
> >>> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
> >>> index dca7856..16a5b55 100644
> >>> --- a/drivers/usb/Makefile
> >>> +++ b/drivers/usb/Makefile
> >>> @@ -59,5 +59,6 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
> >>> obj-$(CONFIG_USB_GADGET) += gadget/
> >>>
> >>> obj-$(CONFIG_USB_COMMON) += common/
> >>> +obj-$(CONFIG_USB_OTG) += common/
> >>>
> >>> obj-$(CONFIG_USBIP_CORE) += usbip/
> >>> diff --git a/drivers/usb/common/usb-otg.c b/drivers/usb/common/usb-otg.c
> >>> index 77048aa..17e449e 100644
> >>> --- a/drivers/usb/common/usb-otg.c
> >>> +++ b/drivers/usb/common/usb-otg.c
> >>> @@ -56,6 +56,30 @@ static int usb_otg_hcd_is_primary_hcd(struct usb_hcd *hcd)
> >>> return hcd == hcd->primary_hcd;
> >>> }
> >>>
> >>> +static const char *otg_state_string(enum usb_otg_state state)
> >>> +{
> >>> + static const char *const names[] = {
> >>> + [OTG_STATE_A_IDLE] = "a_idle",
> >>> + [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
> >>> + [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
> >>> + [OTG_STATE_A_HOST] = "a_host",
> >>> + [OTG_STATE_A_SUSPEND] = "a_suspend",
> >>> + [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
> >>> + [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
> >>> + [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
> >>> + [OTG_STATE_B_IDLE] = "b_idle",
> >>> + [OTG_STATE_B_SRP_INIT] = "b_srp_init",
> >>> + [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
> >>> + [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
> >>> + [OTG_STATE_B_HOST] = "b_host",
> >>> + };
> >>> +
> >>> + if (state < 0 || state >= ARRAY_SIZE(names))
> >>> + return "UNDEFINED";
> >>> +
> >>> + return names[state];
> >>> +}
> >>> +
> >>>
> >>>
> >>>
> >>> From my point, make another copy for otg stuff is not a good way,
> >>> could we make folder under usb/ named otg for dedicated otg stuffs,
> >>> in that case, build otg stuffs can not depend on USB_COMMON.
> >>
> >> OK. I can try that. I'll delete otg_state_string from usb-common.c and
> >> move it into usb/otg/usb-otg.c
> >>
> >> I'll also move usb-otg-fsm.c to usb/otg/.
> >
> > But we can't delete usb_otg_state_string() from usb-common.c. That is used at a
> > number of places whether OTG is enabled or not.
> >
> > One option is to make usb-common built in when otg is enabled. What do you say?
> >
>
> This should also get solved if we make USB_OTG tristate so that it is same as
> USB_COMMON.
>
> However I haven't had success in making Kconfig behave like this.
>
> USB_OTG = y if USB == y && GADGET = m
> USB_OTG = y if USB == m && GADGET = y
>
> Is there any Kconfig trickery to get this behaviour?
>
Unless let the USB_OTG works like USB_COMMON which is selected by GADGET
or HCD. In fact, HCD and Gadget code uses USB OTG symbol directly in
this framework, it seems like HCD and Gadget depends on OTG, but not
otherwise.
If we want OTG to depend on HCD && GADGET, we need not to use OTG symbol
at HCD and GADGET, and the OTG can use HCD and GADGET symbol directly.
--
Best Regards,
Peter Chen
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | linux.kernel
csiph-web