summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/udc/tegra-xudc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/udc/tegra-xudc.c')
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c247
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;