From: Hao Wu <hao.wu@xxxxxxxxx> This patch provided the support to common OTG data structure. Main changes: - Notify otg related events using notifier and remove direct access to otg data structure(state machine). - Provide start_peripheral/stop_peripheral function to transceiver. - Provide client register/unregister function. Signed-off-by: Hao Wu <hao.wu@xxxxxxxxx> Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx> --- drivers/usb/gadget/langwell_udc.c | 179 +++++++++++++++++++++++++++---------- drivers/usb/gadget/langwell_udc.h | 5 + 2 files changed, 132 insertions(+), 52 deletions(-) diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 6251c3c..5db2289 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -1899,6 +1899,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) dev->ep0_state = WAIT_FOR_SETUP; dev->ep0_dir = USB_DIR_OUT; + /* bind OTG transceiver */ + if (dev->transceiver) + (void)otg_set_peripheral(dev->transceiver, &dev->gadget); + /* enable interrupt and set controller to run state */ if (dev->got_irq) langwell_udc_start(dev); @@ -2368,26 +2372,22 @@ static void handle_setup_packet(struct langwell_udc *dev, dev->dev_status &= ~(1 << wValue); } break; - default: - rc = -EOPNOTSUPP; - break; - } - - if (!gadget_is_otg(&dev->gadget)) - break; - else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) { + case USB_DEVICE_B_HNP_ENABLE: dev->gadget.b_hnp_enable = 1; -#ifdef OTG_TRANSCEIVER - if (!dev->lotg->otg.default_a) - dev->lotg->hsm.b_hnp_enable = 1; -#endif - } else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) + dev->dev_status |= (1 << wValue); + break; + case USB_DEVICE_A_HNP_SUPPORT: dev->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) + dev->dev_status |= (1 << wValue); + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: dev->gadget.a_alt_hnp_support = 1; - else + dev->dev_status |= (1 << wValue); break; + default: + rc = -EOPNOTSUPP; + break; + } } else break; @@ -2829,12 +2829,6 @@ static void handle_usb_reset(struct langwell_udc *dev) dev->usb_state = USB_STATE_ATTACHED; } -#ifdef OTG_TRANSCEIVER - /* refer to USB OTG 6.6.2.3 b_hnp_en is cleared */ - if (!dev->lotg->otg.default_a) - dev->lotg->hsm.b_hnp_enable = 0; -#endif - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); } @@ -2848,26 +2842,8 @@ static void handle_bus_suspend(struct langwell_udc *dev) dev->usb_state = USB_STATE_SUSPENDED; #ifdef OTG_TRANSCEIVER - if (dev->lotg->otg.default_a) { - if (dev->lotg->hsm.b_bus_suspend_vld == 1) { - dev->lotg->hsm.b_bus_suspend = 1; - /* notify transceiver the state changes */ - if (spin_trylock(&dev->lotg->wq_lock)) { - langwell_update_transceiver(); - spin_unlock(&dev->lotg->wq_lock); - } - } - dev->lotg->hsm.b_bus_suspend_vld++; - } else { - if (!dev->lotg->hsm.a_bus_suspend) { - dev->lotg->hsm.a_bus_suspend = 1; - /* notify transceiver the state changes */ - if (spin_trylock(&dev->lotg->wq_lock)) { - langwell_update_transceiver(); - spin_unlock(&dev->lotg->wq_lock); - } - } - } + atomic_notifier_call_chain(&dev->iotg->iotg_notifier, + MID_OTG_NOTIFY_CSUSPEND, dev->iotg); #endif /* report suspend to the driver */ @@ -2901,8 +2877,8 @@ static void handle_bus_resume(struct langwell_udc *dev) langwell_phy_low_power(dev, 0); #ifdef OTG_TRANSCEIVER - if (dev->lotg->otg.default_a == 0) - dev->lotg->hsm.a_bus_suspend = 0; + atomic_notifier_call_chain(&dev->iotg->iotg_notifier, + MID_OTG_NOTIFY_CRESUME, dev->iotg); #endif /* report resume to the driver */ @@ -3136,7 +3112,7 @@ static void langwell_udc_remove(struct pci_dev *pdev) if (dev->transceiver) { otg_put_transceiver(dev->transceiver); dev->transceiver = NULL; - dev->lotg = NULL; + dev->iotg = NULL; } #endif @@ -3200,8 +3176,10 @@ static int langwell_udc_probe(struct pci_dev *pdev, /* mem region and register base */ dev->region = 1; dev->transceiver = otg_get_transceiver(); - dev->lotg = otg_to_langwell(dev->transceiver); - base = dev->lotg->regs; + + dev->iotg = otg_to_mid_xceiv(dev->transceiver); + + base = dev->iotg->base; #else pci_set_drvdata(pdev, dev); @@ -3300,6 +3278,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, goto error; } +#ifndef OTG_TRANSCEIVER /* allocate device dQH memory */ size = dev->ep_max * sizeof(struct langwell_dqh); dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size); @@ -3318,6 +3297,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, } dev->ep_dqh_size = size; dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); +#endif /* initialize ep0 status request structure */ dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); @@ -3369,7 +3349,6 @@ static int langwell_udc_probe(struct pci_dev *pdev, #ifndef OTG_TRANSCEIVER /* reset ep0 dQH and endptctrl */ ep0_reset(dev); -#endif /* create dTD dma_pool resource */ dev->dtd_pool = dma_pool_create("langwell_dtd", @@ -3382,6 +3361,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, retval = -ENOMEM; goto error; } +#endif /* done */ dev_info(&dev->pdev->dev, "%s\n", driver_desc); @@ -3598,11 +3578,110 @@ static struct pci_driver langwell_pci_driver = { .shutdown = langwell_udc_shutdown, }; +#ifdef OTG_TRANSCEIVER +static int intel_mid_start_peripheral(struct intel_mid_otg_xceiv *iotg) +{ + struct pci_dev *pdev; + int retval; + + if (iotg == NULL) + return -EINVAL; + + pdev = to_pci_dev(iotg->otg.dev); + + retval = langwell_udc_resume(pdev); + if (retval) + dev_dbg(&pdev->dev, "Failed to start peripheral driver\n"); + + return retval; +} + +static int intel_mid_stop_peripheral(struct intel_mid_otg_xceiv *iotg) +{ + struct pci_dev *pdev; + int retval; + + if (iotg == NULL) + return -EINVAL; + + pdev = to_pci_dev(iotg->otg.dev); + + retval = langwell_udc_suspend(pdev, PMSG_FREEZE); + if (retval) + dev_dbg(&pdev->dev, "Failed to stop peripheral driver\n"); + + return retval; +} + +static int intel_mid_register_peripheral(struct pci_driver *peripheral_driver) +{ + struct otg_transceiver *otg; + struct intel_mid_otg_xceiv *iotg; + struct pci_dev *pdev; + int retval; + + otg = otg_get_transceiver(); + if (otg == NULL) + return -ENODEV; + + if (peripheral_driver == NULL || peripheral_driver->probe == NULL) + return -EINVAL; + + pdev = to_pci_dev(otg->dev); + retval = peripheral_driver->probe(pdev, peripheral_driver->id_table); + if (retval) { + dev_dbg(&pdev->dev, "client probe function failed\n"); + return retval; + } + + iotg = otg_to_mid_xceiv(otg); + + iotg->start_peripheral = intel_mid_start_peripheral; + iotg->stop_peripheral = intel_mid_stop_peripheral; + + atomic_notifier_call_chain(&iotg->iotg_notifier, + MID_OTG_NOTIFY_CLIENTADD, iotg); + + otg_put_transceiver(otg); + + return 0; +} + + +static void intel_mid_unregister_peripheral(struct pci_driver + *peripheral_driver) +{ + struct otg_transceiver *otg; + struct intel_mid_otg_xceiv *iotg; + struct pci_dev *pdev; + + otg = otg_get_transceiver(); + if (otg == NULL) + return ; + + if (peripheral_driver == NULL || peripheral_driver->remove == NULL) + return ; + + pdev = to_pci_dev(otg->dev); + peripheral_driver->remove(pdev); + + iotg = otg_to_mid_xceiv(otg); + + iotg->start_peripheral = NULL; + iotg->stop_peripheral = NULL; + + atomic_notifier_call_chain(&iotg->iotg_notifier, + MID_OTG_NOTIFY_CLIENTREMOVE, iotg); + + otg_put_transceiver(otg); +} +#endif + static int __init init(void) { #ifdef OTG_TRANSCEIVER - return langwell_register_peripheral(&langwell_pci_driver); + return intel_mid_register_peripheral(&langwell_pci_driver); #else return pci_register_driver(&langwell_pci_driver); #endif @@ -3613,7 +3692,7 @@ module_init(init); static void __exit cleanup(void) { #ifdef OTG_TRANSCEIVER - return langwell_unregister_peripheral(&langwell_pci_driver); + intel_mid_unregister_peripheral(&langwell_pci_driver); #else pci_unregister_driver(&langwell_pci_driver); #endif diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h index fa5563d..23ecd1c 100644 --- a/drivers/usb/gadget/langwell_udc.h +++ b/drivers/usb/gadget/langwell_udc.h @@ -18,6 +18,7 @@ */ #include <linux/usb/langwell_udc.h> +#include <linux/usb/intel_mid_otg.h> #if defined(CONFIG_USB_LANGWELL_OTG) #include <linux/usb/langwell_otg.h> @@ -206,8 +207,8 @@ struct langwell_udc { /* pci state used to access those endpoints */ struct pci_dev *pdev; - /* Langwell otg transceiver */ - struct langwell_otg *lotg; + /* Intel mid otg transceiver */ + struct intel_mid_otg_xceiv *iotg; /* control registers */ struct langwell_cap_regs __iomem *cap_regs; -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html