diff options
Diffstat (limited to 'drivers/usb/gadget/udc/tegra-xudc.c')
| -rw-r--r-- | drivers/usb/gadget/udc/tegra-xudc.c | 247 |
1 files changed, 143 insertions, 104 deletions
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index bbe1a04686da..9d2007f448c0 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2,7 +2,7 @@ /* * NVIDIA Tegra XUSB device mode controller * - * Copyright (c) 2013-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2015, Google Inc. */ @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/phy/tegra/xusb.h> #include <linux/pm_domain.h> @@ -32,9 +31,6 @@ #include <linux/workqueue.h> /* XUSB_DEV registers */ -#define SPARAM 0x000 -#define SPARAM_ERSTMAX_MASK GENMASK(20, 16) -#define SPARAM_ERSTMAX(x) (((x) << 16) & SPARAM_ERSTMAX_MASK) #define DB 0x004 #define DB_TARGET_MASK GENMASK(15, 8) #define DB_TARGET(x) (((x) << 8) & DB_TARGET_MASK) @@ -275,8 +271,10 @@ BUILD_EP_CONTEXT_RW(deq_hi, deq_hi, 0, 0xffffffff) BUILD_EP_CONTEXT_RW(avg_trb_len, tx_info, 0, 0xffff) BUILD_EP_CONTEXT_RW(max_esit_payload, tx_info, 16, 0xffff) BUILD_EP_CONTEXT_RW(edtla, rsvd[0], 0, 0xffffff) -BUILD_EP_CONTEXT_RW(seq_num, rsvd[0], 24, 0xff) +BUILD_EP_CONTEXT_RW(rsvd, rsvd[0], 24, 0x1) BUILD_EP_CONTEXT_RW(partial_td, rsvd[0], 25, 0x1) +BUILD_EP_CONTEXT_RW(splitxstate, rsvd[0], 26, 0x1) +BUILD_EP_CONTEXT_RW(seq_num, rsvd[0], 27, 0x1f) BUILD_EP_CONTEXT_RW(cerrcnt, rsvd[1], 18, 0x3) BUILD_EP_CONTEXT_RW(data_offset, rsvd[2], 0, 0x1ffff) BUILD_EP_CONTEXT_RW(numtrbs, rsvd[2], 22, 0x1f) @@ -504,6 +502,7 @@ struct tegra_xudc { struct clk_bulk_data *clks; bool device_mode; + bool current_device_mode; struct work_struct usb_role_sw_work; struct phy **usb3_phy; @@ -703,18 +702,22 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc) pm_runtime_get_sync(xudc->dev); + tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy); + err = phy_power_on(xudc->curr_utmi_phy); if (err < 0) - dev_err(xudc->dev, "utmi power on failed %d\n", err); + dev_err(xudc->dev, "UTMI power on failed: %d\n", err); err = phy_power_on(xudc->curr_usb3_phy); if (err < 0) - dev_err(xudc->dev, "usb3 phy power on failed %d\n", err); + dev_err(xudc->dev, "USB3 PHY power on failed: %d\n", err); dev_dbg(xudc->dev, "device mode on\n"); phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, USB_ROLE_DEVICE); + + xudc->current_device_mode = true; } static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) @@ -725,6 +728,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) dev_dbg(xudc->dev, "device mode off\n"); + xudc->current_device_mode = false; + connected = !!(xudc_readl(xudc, PORTSC) & PORTSC_CCS); reinit_completion(&xudc->disconnect_complete); @@ -757,13 +762,15 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) /* Make sure interrupt handler has completed before powergating. */ synchronize_irq(xudc->irq); + tegra_phy_xusb_utmi_pad_power_down(xudc->curr_utmi_phy); + err = phy_power_off(xudc->curr_utmi_phy); if (err < 0) - dev_err(xudc->dev, "utmi_phy power off failed %d\n", err); + dev_err(xudc->dev, "UTMI PHY power off failed: %d\n", err); err = phy_power_off(xudc->curr_usb3_phy); if (err < 0) - dev_err(xudc->dev, "usb3_phy power off failed %d\n", err); + dev_err(xudc->dev, "USB3 PHY power off failed: %d\n", err); pm_runtime_put(xudc->dev); } @@ -793,25 +800,19 @@ static int tegra_xudc_get_phy_index(struct tegra_xudc *xudc, return -1; } -static int tegra_xudc_vbus_notify(struct notifier_block *nb, - unsigned long action, void *data) +static void tegra_xudc_update_data_role(struct tegra_xudc *xudc, + struct usb_phy *usbphy) { - struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc, - vbus_nb); - struct usb_phy *usbphy = (struct usb_phy *)data; int phy_index; - dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event); - if ((xudc->device_mode && usbphy->last_event == USB_EVENT_VBUS) || (!xudc->device_mode && usbphy->last_event != USB_EVENT_VBUS)) { dev_dbg(xudc->dev, "Same role(%d) received. Ignore", xudc->device_mode); - return NOTIFY_OK; + return; } - xudc->device_mode = (usbphy->last_event == USB_EVENT_VBUS) ? true : - false; + xudc->device_mode = usbphy->last_event == USB_EVENT_VBUS; phy_index = tegra_xudc_get_phy_index(xudc, usbphy); dev_dbg(xudc->dev, "%s(): current phy index is %d\n", __func__, @@ -823,6 +824,18 @@ static int tegra_xudc_vbus_notify(struct notifier_block *nb, xudc->curr_usbphy = usbphy; schedule_work(&xudc->usb_role_sw_work); } +} + +static int tegra_xudc_vbus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc, + vbus_nb); + struct usb_phy *usbphy = (struct usb_phy *)data; + + dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event); + + tegra_xudc_update_data_role(xudc, usbphy); return NOTIFY_OK; } @@ -1413,18 +1426,20 @@ __tegra_xudc_ep_dequeue(struct tegra_xudc_ep *ep, struct tegra_xudc_request *req) { struct tegra_xudc *xudc = ep->xudc; - struct tegra_xudc_request *r; + struct tegra_xudc_request *r = NULL, *iter; struct tegra_xudc_trb *deq_trb; bool busy, kick_queue = false; int ret = 0; /* Make sure the request is actually queued to this endpoint. */ - list_for_each_entry(r, &ep->queue, list) { - if (r == req) - break; + list_for_each_entry(iter, &ep->queue, list) { + if (iter != req) + continue; + r = iter; + break; } - if (r != req) + if (!r) return -EINVAL; /* Request hasn't been queued in the transfer ring yet. */ @@ -1433,7 +1448,7 @@ __tegra_xudc_ep_dequeue(struct tegra_xudc_ep *ep, return 0; } - /* Halt DMA for this endpiont. */ + /* Halt DMA for this endpoint. */ if (ep_ctx_read_state(ep->context) == EP_STATE_RUNNING) { ep_pause(xudc, ep->index); ep_wait_for_inactive(xudc, ep->index); @@ -1539,16 +1554,10 @@ static int __tegra_xudc_ep_set_halt(struct tegra_xudc_ep *ep, bool halt) return -EINVAL; if (usb_endpoint_xfer_isoc(ep->desc)) { - dev_err(xudc->dev, "can't halt isoc EP\n"); + dev_err(xudc->dev, "can't halt isochronous EP\n"); return -ENOTSUPP; } - if (!!(xudc_readl(xudc, EP_HALT) & BIT(ep->index)) == halt) { - dev_dbg(xudc->dev, "EP %u already %s\n", ep->index, - halt ? "halted" : "not halted"); - return 0; - } - if (halt) { ep_halt(xudc, ep->index); } else { @@ -1557,6 +1566,9 @@ static int __tegra_xudc_ep_set_halt(struct tegra_xudc_ep *ep, bool halt) ep_reload(xudc, ep->index); ep_ctx_write_state(ep->context, EP_STATE_RUNNING); + ep_ctx_write_rsvd(ep->context, 0); + ep_ctx_write_partial_td(ep->context, 0); + ep_ctx_write_splitxstate(ep->context, 0); ep_ctx_write_seq_num(ep->context, 0); ep_reload(xudc, ep->index); @@ -1610,7 +1622,7 @@ static void tegra_xudc_ep_context_setup(struct tegra_xudc_ep *ep) u16 maxpacket, maxburst = 0, esit = 0; u32 val; - maxpacket = usb_endpoint_maxp(desc) & 0x7ff; + maxpacket = usb_endpoint_maxp(desc); if (xudc->gadget.speed == USB_SPEED_SUPER) { if (!usb_endpoint_xfer_control(desc)) maxburst = comp_desc->bMaxBurst; @@ -1621,7 +1633,7 @@ static void tegra_xudc_ep_context_setup(struct tegra_xudc_ep *ep) (usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc))) { if (xudc->gadget.speed == USB_SPEED_HIGH) { - maxburst = (usb_endpoint_maxp(desc) >> 11) & 0x3; + maxburst = usb_endpoint_maxp_mult(desc) - 1; if (maxburst == 0x3) { dev_warn(xudc->dev, "invalid endpoint maxburst\n"); @@ -1735,6 +1747,10 @@ static int __tegra_xudc_ep_disable(struct tegra_xudc_ep *ep) val = xudc_readl(xudc, CTRL); val &= ~CTRL_RUN; xudc_writel(xudc, val, CTRL); + + val = xudc_readl(xudc, ST); + if (val & ST_RC) + xudc_writel(xudc, ST_RC, ST); } dev_info(xudc->dev, "ep %u disabled\n", ep->index); @@ -1788,7 +1804,7 @@ static int __tegra_xudc_ep_enable(struct tegra_xudc_ep *ep, if (usb_endpoint_xfer_isoc(desc)) { if (xudc->nr_isoch_eps > XUDC_MAX_ISOCH_EPS) { - dev_err(xudc->dev, "too many isoch endpoints\n"); + dev_err(xudc->dev, "too many isochronous endpoints\n"); return -EBUSY; } xudc->nr_isoch_eps++; @@ -1907,7 +1923,7 @@ static void tegra_xudc_ep_free_request(struct usb_ep *usb_ep, kfree(req); } -static struct usb_ep_ops tegra_xudc_ep_ops = { +static const struct usb_ep_ops tegra_xudc_ep_ops = { .enable = tegra_xudc_ep_enable, .disable = tegra_xudc_ep_disable, .alloc_request = tegra_xudc_ep_alloc_request, @@ -1928,7 +1944,7 @@ static int tegra_xudc_ep0_disable(struct usb_ep *usb_ep) return -EBUSY; } -static struct usb_ep_ops tegra_xudc_ep0_ops = { +static const struct usb_ep_ops tegra_xudc_ep0_ops = { .enable = tegra_xudc_ep0_enable, .disable = tegra_xudc_ep0_disable, .alloc_request = tegra_xudc_ep_alloc_request, @@ -2147,15 +2163,14 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget) static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, unsigned int m_a) { - int ret = 0; struct tegra_xudc *xudc = to_xudc(gadget); dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); - if (xudc->curr_usbphy->chg_type == SDP_TYPE) - ret = usb_phy_set_power(xudc->curr_usbphy, m_a); + if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE) + return usb_phy_set_power(xudc->curr_usbphy, m_a); - return ret; + return 0; } static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) @@ -2168,7 +2183,7 @@ static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) return 0; } -static struct usb_gadget_ops tegra_xudc_gadget_ops = { +static const struct usb_gadget_ops tegra_xudc_gadget_ops = { .get_frame = tegra_xudc_gadget_get_frame, .wakeup = tegra_xudc_gadget_wakeup, .pullup = tegra_xudc_gadget_pullup, @@ -2742,7 +2757,7 @@ static void tegra_xudc_handle_transfer_event(struct tegra_xudc *xudc, ep_wait_for_stopped(xudc, ep_index); ep->enq_ptr = ep->deq_ptr; tegra_xudc_ep_nuke(ep, -EIO); - /* FALLTHROUGH */ + fallthrough; case TRB_CMPL_CODE_STREAM_NUMP_ERROR: case TRB_CMPL_CODE_CTRL_DIR_ERR: case TRB_CMPL_CODE_INVALID_STREAM_TYPE_ERR: @@ -2812,7 +2827,10 @@ static void tegra_xudc_reset(struct tegra_xudc *xudc) xudc->setup_seq_num = 0; xudc->queued_setup_packet = false; - ep_ctx_write_seq_num(ep0->context, xudc->setup_seq_num); + ep_ctx_write_rsvd(ep0->context, 0); + ep_ctx_write_partial_td(ep0->context, 0); + ep_ctx_write_splitxstate(ep0->context, 0); + ep_ctx_write_seq_num(ep0->context, 0); deq_ptr = trb_virt_to_phys(ep0, &ep0->transfer_ring[ep0->deq_ptr]); @@ -3295,11 +3313,6 @@ static void tegra_xudc_init_event_ring(struct tegra_xudc *xudc) unsigned int i; u32 val; - val = xudc_readl(xudc, SPARAM); - val &= ~(SPARAM_ERSTMAX_MASK); - val |= SPARAM_ERSTMAX(XUDC_NR_EVENT_RINGS); - xudc_writel(xudc, val, SPARAM); - for (i = 0; i < ARRAY_SIZE(xudc->event_ring); i++) { memset(xudc->event_ring[i], 0, XUDC_EVENT_RING_SIZE * sizeof(*xudc->event_ring[i])); @@ -3421,7 +3434,7 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc) } /* - * Compliacne suite appears to be violating polling LFPS tBurst max + * Compliance suite appears to be violating polling LFPS tBurst max * of 1.4us. Send 1.45us instead. */ val = xudc_readl(xudc, SSPX_CORE_CNT32); @@ -3480,8 +3493,8 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc) static int tegra_xudc_phy_get(struct tegra_xudc *xudc) { - int err = 0, usb3; - unsigned int i; + int err = 0, usb3_companion_port; + unsigned int i, j; xudc->utmi_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys, sizeof(*xudc->utmi_phy), GFP_KERNEL); @@ -3508,20 +3521,18 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc) xudc->utmi_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); if (IS_ERR(xudc->utmi_phy[i])) { err = PTR_ERR(xudc->utmi_phy[i]); - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to get usb2-%d phy: %d\n", - i, err); - + dev_err_probe(xudc->dev, err, + "failed to get PHY for phy-name usb2-%d\n", i); goto clean_up; } else if (xudc->utmi_phy[i]) { /* Get usb-phy, if utmi phy is available */ xudc->usbphy[i] = devm_usb_get_phy_by_node(xudc->dev, xudc->utmi_phy[i]->dev.of_node, - &xudc->vbus_nb); + NULL); if (IS_ERR(xudc->usbphy[i])) { err = PTR_ERR(xudc->usbphy[i]); - dev_err(xudc->dev, "failed to get usbphy-%d: %d\n", - i, err); + dev_err_probe(xudc->dev, err, + "failed to get usbphy-%d\n", i); goto clean_up; } } else if (!xudc->utmi_phy[i]) { @@ -3530,21 +3541,30 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc) } /* Get USB3 phy */ - usb3 = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i); - if (usb3 < 0) + usb3_companion_port = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i); + if (usb3_companion_port < 0) continue; - snprintf(phy_name, sizeof(phy_name), "usb3-%d", usb3); - xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); - if (IS_ERR(xudc->usb3_phy[i])) { - err = PTR_ERR(xudc->usb3_phy[i]); - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to get usb3-%d phy: %d\n", - usb3, err); - - goto clean_up; - } else if (xudc->usb3_phy[i]) - dev_dbg(xudc->dev, "usb3_phy-%d registered", usb3); + for (j = 0; j < xudc->soc->num_phys; j++) { + snprintf(phy_name, sizeof(phy_name), "usb3-%d", j); + xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); + if (IS_ERR(xudc->usb3_phy[i])) { + err = PTR_ERR(xudc->usb3_phy[i]); + dev_err_probe(xudc->dev, err, + "failed to get PHY for phy-name usb3-%d\n", j); + goto clean_up; + } else if (xudc->usb3_phy[i]) { + int usb2_port = + tegra_xusb_padctl_get_port_number(xudc->utmi_phy[i]); + int usb3_port = + tegra_xusb_padctl_get_port_number(xudc->usb3_phy[i]); + if (usb3_port == usb3_companion_port) { + dev_dbg(xudc->dev, "USB2 port %d is paired with USB3 port %d for device mode port %d\n", + usb2_port, usb3_port, i); + break; + } + } + } } return err; @@ -3577,13 +3597,13 @@ static int tegra_xudc_phy_init(struct tegra_xudc *xudc) for (i = 0; i < xudc->soc->num_phys; i++) { err = phy_init(xudc->utmi_phy[i]); if (err < 0) { - dev_err(xudc->dev, "utmi phy init failed: %d\n", err); + dev_err(xudc->dev, "UTMI PHY #%u initialization failed: %d\n", i, err); goto exit_phy; } err = phy_init(xudc->usb3_phy[i]); if (err < 0) { - dev_err(xudc->dev, "usb3 phy init failed: %d\n", err); + dev_err(xudc->dev, "USB3 PHY #%u initialization failed: %d\n", i, err); goto exit_phy; } } @@ -3658,6 +3678,19 @@ static struct tegra_xudc_soc tegra194_xudc_soc_data = { .has_ipfs = false, }; +static struct tegra_xudc_soc tegra234_xudc_soc_data = { + .clock_names = tegra186_xudc_clock_names, + .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names), + .num_phys = 4, + .u1_enable = true, + .u2_enable = true, + .lpm_enable = true, + .invalid_seq_num = false, + .pls_quirk = false, + .port_reset_quirk = false, + .has_ipfs = false, +}; + static const struct of_device_id tegra_xudc_of_match[] = { { .compatible = "nvidia,tegra210-xudc", @@ -3671,6 +3704,10 @@ static const struct of_device_id tegra_xudc_of_match[] = { .compatible = "nvidia,tegra194-xudc", .data = &tegra194_xudc_soc_data }, + { + .compatible = "nvidia,tegra234-xudc", + .data = &tegra234_xudc_soc_data + }, { } }; MODULE_DEVICE_TABLE(of, tegra_xudc_of_match); @@ -3692,34 +3729,33 @@ static int tegra_xudc_powerdomain_init(struct tegra_xudc *xudc) struct device *dev = xudc->dev; int err; - xudc->genpd_dev_device = dev_pm_domain_attach_by_name(dev, - "dev"); + xudc->genpd_dev_device = dev_pm_domain_attach_by_name(dev, "dev"); if (IS_ERR(xudc->genpd_dev_device)) { err = PTR_ERR(xudc->genpd_dev_device); - dev_err(dev, "failed to get dev pm-domain: %d\n", err); + dev_err(dev, "failed to get device power domain: %d\n", err); return err; } xudc->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "ss"); if (IS_ERR(xudc->genpd_dev_ss)) { err = PTR_ERR(xudc->genpd_dev_ss); - dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); + dev_err(dev, "failed to get SuperSpeed power domain: %d\n", err); return err; } xudc->genpd_dl_device = device_link_add(dev, xudc->genpd_dev_device, - DL_FLAG_PM_RUNTIME | - DL_FLAG_STATELESS); + DL_FLAG_PM_RUNTIME | + DL_FLAG_STATELESS); if (!xudc->genpd_dl_device) { - dev_err(dev, "adding usb device device link failed!\n"); + dev_err(dev, "failed to add USB device link\n"); return -ENODEV; } xudc->genpd_dl_ss = device_link_add(dev, xudc->genpd_dev_ss, - DL_FLAG_PM_RUNTIME | - DL_FLAG_STATELESS); + DL_FLAG_PM_RUNTIME | + DL_FLAG_STATELESS); if (!xudc->genpd_dl_ss) { - dev_err(dev, "adding superspeed device link failed!\n"); + dev_err(dev, "failed to add SuperSpeed device link\n"); return -ENODEV; } @@ -3733,7 +3769,7 @@ static int tegra_xudc_probe(struct platform_device *pdev) unsigned int i; int err; - xudc = devm_kzalloc(&pdev->dev, sizeof(*xudc), GFP_ATOMIC); + xudc = devm_kzalloc(&pdev->dev, sizeof(*xudc), GFP_KERNEL); if (!xudc) return -ENOMEM; @@ -3750,15 +3786,12 @@ static int tegra_xudc_probe(struct platform_device *pdev) return PTR_ERR(xudc->base); xudc->phys_base = res->start; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fpci"); - xudc->fpci = devm_ioremap_resource(&pdev->dev, res); + xudc->fpci = devm_platform_ioremap_resource_byname(pdev, "fpci"); if (IS_ERR(xudc->fpci)) return PTR_ERR(xudc->fpci); if (xudc->soc->has_ipfs) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "ipfs"); - xudc->ipfs = devm_ioremap_resource(&pdev->dev, res); + xudc->ipfs = devm_platform_ioremap_resource_byname(pdev, "ipfs"); if (IS_ERR(xudc->ipfs)) return PTR_ERR(xudc->ipfs); } @@ -3775,18 +3808,17 @@ static int tegra_xudc_probe(struct platform_device *pdev) return err; } - xudc->clks = devm_kcalloc(&pdev->dev, xudc->soc->num_clks, - sizeof(*xudc->clks), GFP_KERNEL); + xudc->clks = devm_kcalloc(&pdev->dev, xudc->soc->num_clks, sizeof(*xudc->clks), + GFP_KERNEL); if (!xudc->clks) return -ENOMEM; for (i = 0; i < xudc->soc->num_clks; i++) xudc->clks[i].id = xudc->soc->clock_names[i]; - err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, - xudc->clks); + err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, xudc->clks); if (err) { - dev_err(xudc->dev, "failed to request clks %d\n", err); + dev_err_probe(xudc->dev, err, "failed to request clocks\n"); return err; } @@ -3801,7 +3833,7 @@ static int tegra_xudc_probe(struct platform_device *pdev) err = devm_regulator_bulk_get(&pdev->dev, xudc->soc->num_supplies, xudc->supplies); if (err) { - dev_err(xudc->dev, "failed to request regulators %d\n", err); + dev_err_probe(xudc->dev, err, "failed to request regulators\n"); return err; } @@ -3811,7 +3843,7 @@ static int tegra_xudc_probe(struct platform_device *pdev) err = regulator_bulk_enable(xudc->soc->num_supplies, xudc->supplies); if (err) { - dev_err(xudc->dev, "failed to enable regulators %d\n", err); + dev_err(xudc->dev, "failed to enable regulators: %d\n", err); goto put_padctl; } @@ -3859,9 +3891,18 @@ static int tegra_xudc_probe(struct platform_device *pdev) goto free_eps; } + for (i = 0; i < xudc->soc->num_phys; i++) { + if (!xudc->usbphy[i]) + continue; + + usb_register_notifier(xudc->usbphy[i], &xudc->vbus_nb); + tegra_xudc_update_data_role(xudc, xudc->usbphy[i]); + } + return 0; free_eps: + pm_runtime_disable(&pdev->dev); tegra_xudc_free_eps(xudc); free_event_ring: tegra_xudc_free_event_ring(xudc); @@ -3877,14 +3918,14 @@ put_padctl: return err; } -static int tegra_xudc_remove(struct platform_device *pdev) +static void tegra_xudc_remove(struct platform_device *pdev) { struct tegra_xudc *xudc = platform_get_drvdata(pdev); unsigned int i; pm_runtime_get_sync(xudc->dev); - cancel_delayed_work(&xudc->plc_reset_work); + cancel_delayed_work_sync(&xudc->plc_reset_work); cancel_work_sync(&xudc->usb_role_sw_work); usb_del_gadget_udc(&xudc->gadget); @@ -3907,8 +3948,6 @@ static int tegra_xudc_remove(struct platform_device *pdev) pm_runtime_put(xudc->dev); tegra_xusb_padctl_put(xudc->padctl); - - return 0; } static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc) @@ -4003,10 +4042,10 @@ static int __maybe_unused tegra_xudc_resume(struct device *dev) spin_lock_irqsave(&xudc->lock, flags); xudc->suspended = false; + if (xudc->device_mode != xudc->current_device_mode) + schedule_work(&xudc->usb_role_sw_work); spin_unlock_irqrestore(&xudc->lock, flags); - schedule_work(&xudc->usb_role_sw_work); - pm_runtime_enable(dev); return 0; |
