diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/chipidea/ci.h | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.c | 14 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 95 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/configfs.c | 14 |
5 files changed, 124 insertions, 13 deletions
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 33c99e2fc8fe..91b475685c77 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -173,6 +173,7 @@ struct hw_bank { * @enabled_otg_timer_bits: bits of enabled otg timers * @next_otg_timer: next nearest enabled timer to be expired * @work: work for role changing + * @work_dr: work for role changing for non-OTG controllers * @wq: workqueue thread * @qh_pool: allocation pool for queue heads * @td_pool: allocation pool for transfer descriptors @@ -222,6 +223,7 @@ struct ci_hdrc { unsigned enabled_otg_timer_bits; enum otg_fsm_timer next_otg_timer; struct work_struct work; + struct work_struct work_dr; struct workqueue_struct *wq; struct dma_pool *qh_pool; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 53f48cc2eeb5..00bb8d6caec1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -130,6 +130,7 @@ struct ci_hdrc_imx_data { struct pm_qos_request pm_qos_req; }; +#ifdef CONFIG_POWER_SUPPLY static char *imx_usb_charger_supplied_to[] = { "imx_usb_charger", }; @@ -139,6 +140,7 @@ static enum power_supply_property imx_usb_charger_power_props[] = { POWER_SUPPLY_PROP_ONLINE, /* VBUS online */ POWER_SUPPLY_PROP_CURRENT_MAX, /* Maximum current in mA */ }; +#endif /* Common functions shared by usbmisc drivers */ @@ -319,6 +321,7 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event) int ret = 0; switch (event) { +#ifdef CONFIG_POWER_SUPPLY case CI_HDRC_CONTROLLER_VBUS_EVENT: if (data->usbmisc_data && ci->vbus_active) { if (data->imx_usb_charger_detection) { @@ -339,6 +342,7 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event) return ret; imx_usbmisc_charger_secondary_detection(data->usbmisc_data); break; +#endif case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: if (!IS_ERR(data->pinctrl) && !IS_ERR(data->pinctrl_hsic_active)) { @@ -378,6 +382,7 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event) return ret; } +#ifdef CONFIG_POWER_SUPPLY static int imx_usb_charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -441,6 +446,7 @@ static int imx_usb_register_charger(struct usb_charger *charger, return 0; } +#endif static int ci_hdrc_imx_probe(struct platform_device *pdev) { @@ -575,6 +581,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (of_find_property(np, "imx-usb-charger-detection", NULL) && data->usbmisc_data) { +#ifdef CONFIG_POWER_SUPPLY data->imx_usb_charger_detection = true; data->charger.dev = dev; data->usbmisc_data->charger = &data->charger; @@ -583,7 +590,12 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret && ret != -ENODEV) goto disable_hsic_regulator; if (!ret) - dev_dbg(dev, "USB Charger is created\n"); + dev_dbg(&pdev->dev, + "USB Charger is created\n"); +#else + dev_err(&pdev->dev, + "USB Charger requires CONFIG_POWER_SUPPLY\n"); +#endif } ret = imx_usbmisc_init(data->usbmisc_data); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a9b3795a150b..8269046b684d 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -569,16 +569,71 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } +static void usb_roleswitch_workqueue(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work_dr); + struct ci_hdrc_cable *id, *vbus; + int ret; + + pm_runtime_get_sync(ci->dev); + + id = &ci->platdata->id_extcon; + if (!IS_ERR(id->edev)) { + int new_role; + + ci_role_stop(ci); + hw_wait_phy_stable(); + + ret = extcon_get_cable_state_(id->edev, EXTCON_USB_HOST); + if (ret) { + new_role = CI_ROLE_HOST; + dev_info(ci->dev, "switching to host role\n"); + } else { + new_role = CI_ROLE_GADGET; + dev_info(ci->dev, "switching to gadget role\n"); + } + ci_role_start(ci, new_role); + } + + vbus = &ci->platdata->vbus_extcon; + if (!IS_ERR(vbus->edev)) { + ret = extcon_get_cable_state_(vbus->edev, EXTCON_USB); + if (ret) { + usb_gadget_vbus_connect(&ci->gadget); + } else { + usb_gadget_vbus_disconnect(&ci->gadget); + } + } + + pm_runtime_put_sync(ci->dev); + + enable_irq(ci->irq); +} + static int ci_cable_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { struct ci_hdrc_cable *cbl = container_of(nb, struct ci_hdrc_cable, nb); struct ci_hdrc *ci = cbl->ci; - cbl->connected = event; - cbl->changed = true; + if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) { + disable_irq_nosync(ci->irq); + + /* + * This notifier might get called twice in succession, + * once for the ID pin and once for the VBUS pin. Make + * sure we only disable irq in case we successfully add + * work to the work queue. + */ + if (!queue_work(system_power_efficient_wq, &ci->work_dr)) + enable_irq(ci->irq); + } else { + cbl->connected = event; + cbl->changed = true; + + ci_irq(ci->irq, ci); + } - ci_irq(ci->irq, ci); return NOTIFY_DONE; } @@ -858,6 +913,13 @@ static enum ci_role ci_get_role(struct ci_hdrc *ci) * role switch, the defalt role is gadget, and the * user can switch it through debugfs. */ + struct ci_hdrc_cable *id = &ci->platdata->id_extcon; + if (!IS_ERR(id->edev)) { + if (extcon_get_cable_state_(id->edev, EXTCON_USB_HOST)) + return CI_ROLE_HOST; + else + return CI_ROLE_GADGET; + } return CI_ROLE_GADGET; } } else { @@ -1020,7 +1082,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci_get_otg_capable(ci); + if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) + INIT_WORK(&ci->work_dr, usb_roleswitch_workqueue); + + ret = ci_extcon_register(ci); + if (ret) + goto stop; + dr_mode = ci->platdata->dr_mode; + /* initialize role(s) before the interrupt is requested */ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { ret = ci_hdrc_host_init(ci); @@ -1062,6 +1132,21 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci_handle_vbus_connected(ci); if (!ci_otg_is_fsm_mode(ci)) { + + /* only update vbus status for peripheral */ + if (dr_mode == USB_DR_MODE_PERIPHERAL) { + usb_gadget_vbus_connect(&ci->gadget); + } else if (ci->role == CI_ROLE_GADGET) { + struct ci_hdrc_cable *vbus = &ci->platdata->vbus_extcon; + + /* Use vbus state from extcon if provided */ + if (!IS_ERR(vbus->edev) && + extcon_get_cable_state_(vbus->edev, EXTCON_USB)) + usb_gadget_vbus_connect(&ci->gadget); + else + ci_handle_vbus_change(ci); + } + ret = ci_role_start(ci, ci->role); if (ret) { dev_err(dev, "can't start %s role\n", @@ -1076,10 +1161,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - ret = ci_extcon_register(ci); - if (ret) - goto stop; - if (ci->supports_runtime_pm) { pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index b7d21b052c19..6ed020113926 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -609,6 +609,7 @@ static int usbmisc_imx7d_power_lost_check(struct imx_usbmisc_data *data) /***************************************************************************/ /* imx usb charger detecton */ /***************************************************************************/ +#ifdef CONFIG_POWER_SUPPLY static void usb_charger_is_present(struct usb_charger *charger, bool present) { if (present) @@ -762,7 +763,9 @@ static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data) else return 0; } +#endif +#ifdef CONFIG_POWER_SUPPLY static void imx7_disable_charger_detector(struct imx_usbmisc_data *data) { struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); @@ -919,6 +922,7 @@ int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data) return 0; } +#endif static int usbmisc_term_select_override(struct imx_usbmisc_data *data, bool enable, int val) @@ -967,8 +971,10 @@ static const struct usbmisc_ops imx53_usbmisc_ops = { static const struct usbmisc_ops imx6q_usbmisc_ops = { .set_wakeup = usbmisc_imx6q_set_wakeup, .init = usbmisc_imx6q_init, +#ifdef CONFIG_POWER_SUPPLY .charger_primary_detection = imx6_charger_primary_detection, .charger_secondary_detection = imx6_charger_secondary_detection, +#endif .hsic_set_connect = usbmisc_imx6_hsic_set_connect, .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; @@ -980,9 +986,11 @@ static const struct usbmisc_ops vf610_usbmisc_ops = { static const struct usbmisc_ops imx6sx_usbmisc_ops = { .set_wakeup = usbmisc_imx6q_set_wakeup, .init = usbmisc_imx6sx_init, +#ifdef CONFIG_POWER_SUPPLY .charger_primary_detection = imx6_charger_primary_detection, .charger_secondary_detection = imx6_charger_secondary_detection, .power_lost_check = usbmisc_imx6sx_power_lost_check, +#endif .hsic_set_connect = usbmisc_imx6_hsic_set_connect, .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; @@ -990,9 +998,11 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = { static const struct usbmisc_ops imx7d_usbmisc_ops = { .init = usbmisc_imx7d_init, .set_wakeup = usbmisc_imx7d_set_wakeup, +#ifdef CONFIG_POWER_SUPPLY .power_lost_check = usbmisc_imx7d_power_lost_check, .charger_primary_detection = imx7d_charger_primary_detection, .charger_secondary_detection = imx7d_charger_secondary_detection, +#endif .term_select_override = usbmisc_term_select_override, .hsic_set_connect = usbmisc_imx6_hsic_set_connect, .hsic_set_clk = usbmisc_imx6_hsic_set_clk, @@ -1048,6 +1058,7 @@ int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled) } EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup); +#ifdef CONFIG_POWER_SUPPLY int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect) { struct imx_usbmisc *usbmisc; @@ -1099,6 +1110,7 @@ int imx_usbmisc_charger_secondary_detection(struct imx_usbmisc_data *data) return usbmisc->ops->charger_secondary_detection(data); } EXPORT_SYMBOL_GPL(imx_usbmisc_charger_secondary_detection); +#endif int imx_usbmisc_power_lost_check(struct imx_usbmisc_data *data) { diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index a5ca409dc97e..91a11c7b30e6 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -739,7 +739,7 @@ static inline struct gadget_info *os_desc_item_to_gadget_info( static ssize_t os_desc_use_show(struct config_item *item, char *page) { - return sprintf(page, "%d", + return sprintf(page, "%d\n", os_desc_item_to_gadget_info(item)->use_os_desc); } @@ -763,7 +763,7 @@ static ssize_t os_desc_use_store(struct config_item *item, const char *page, static ssize_t os_desc_b_vendor_code_show(struct config_item *item, char *page) { - return sprintf(page, "%d", + return sprintf(page, "0x%02x\n", os_desc_item_to_gadget_info(item)->b_vendor_code); } @@ -788,9 +788,13 @@ static ssize_t os_desc_b_vendor_code_store(struct config_item *item, static ssize_t os_desc_qw_sign_show(struct config_item *item, char *page) { struct gadget_info *gi = os_desc_item_to_gadget_info(item); + int res; + + res = utf16s_to_utf8s((wchar_t *) gi->qw_sign, OS_STRING_QW_SIGN_LEN, + UTF16_LITTLE_ENDIAN, page, PAGE_SIZE - 1); + page[res++] = '\n'; - memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); - return OS_STRING_QW_SIGN_LEN; + return res; } static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page, @@ -902,7 +906,7 @@ static inline struct usb_os_desc_ext_prop static ssize_t ext_prop_type_show(struct config_item *item, char *page) { - return sprintf(page, "%d", to_usb_os_desc_ext_prop(item)->type); + return sprintf(page, "%d\n", to_usb_os_desc_ext_prop(item)->type); } static ssize_t ext_prop_type_store(struct config_item *item, |