summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/atm/cxacru.c2
-rw-r--r--drivers/usb/cdns3/cdns3-ep0.c6
-rw-r--r--drivers/usb/cdns3/cdns3-gadget.c40
-rw-r--r--drivers/usb/cdns3/cdns3-imx.c2
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c2
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.c7
-rw-r--r--drivers/usb/cdns3/cdnsp-mem.c5
-rw-r--r--drivers/usb/cdns3/core.c4
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/core.c2
-rw-r--r--drivers/usb/chipidea/debug.c34
-rw-r--r--drivers/usb/chipidea/otg.c9
-rw-r--r--drivers/usb/chipidea/udc.c2
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/class/cdc-wdm.c5
-rw-r--r--drivers/usb/common/ulpi.c2
-rw-r--r--drivers/usb/common/usb-conn-gpio.c62
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/hcd.c130
-rw-r--r--drivers/usb/core/hub.c34
-rw-r--r--drivers/usb/core/message.c6
-rw-r--r--drivers/usb/core/quirks.c1
-rw-r--r--drivers/usb/core/sysfs.c24
-rw-r--r--drivers/usb/core/urb.c9
-rw-r--r--drivers/usb/dwc2/core.c30
-rw-r--r--drivers/usb/dwc2/gadget.c14
-rw-r--r--drivers/usb/dwc2/hcd_queue.c2
-rw-r--r--drivers/usb/dwc2/params.c4
-rw-r--r--drivers/usb/dwc2/pci.c2
-rw-r--r--drivers/usb/dwc2/platform.c2
-rw-r--r--drivers/usb/dwc3/core.c7
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/debugfs.c8
-rw-r--r--drivers/usb/dwc3/drd.c1
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c8
-rw-r--r--drivers/usb/dwc3/gadget.c4
-rw-r--r--drivers/usb/dwc3/trace.h2
-rw-r--r--drivers/usb/gadget/function/f_eem.c43
-rw-r--r--drivers/usb/gadget/function/f_fs.c65
-rw-r--r--drivers/usb/gadget/function/f_hid.c4
-rw-r--r--drivers/usb/gadget/function/f_printer.c3
-rw-r--r--drivers/usb/gadget/function/f_uac2.c144
-rw-r--r--drivers/usb/gadget/function/u_audio.c225
-rw-r--r--drivers/usb/gadget/function/u_audio.h12
-rw-r--r--drivers/usb/gadget/function/u_hid.h4
-rw-r--r--drivers/usb/gadget/function/u_midi.h4
-rw-r--r--drivers/usb/gadget/function/u_uac2.h4
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c5
-rw-r--r--drivers/usb/gadget/legacy/hid.c4
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c7
-rw-r--r--drivers/usb/gadget/udc/core.c49
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c11
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c5
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c44
-rw-r--r--drivers/usb/gadget/udc/fsl_usb2_udc.h19
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c7
-rw-r--r--drivers/usb/gadget/udc/gr_udc.h2
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c5
-rw-r--r--drivers/usb/gadget/udc/mv_u3d_core.c2
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/net2272.c41
-rw-r--r--drivers/usb/gadget/udc/net2272.h1
-rw-r--r--drivers/usb/gadget/udc/net2280.c51
-rw-r--r--drivers/usb/gadget/udc/net2280.h1
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c4
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.h4
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c6
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.h4
-rw-r--r--drivers/usb/gadget/udc/s3c-hsudc.c5
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c9
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c30
-rw-r--r--drivers/usb/gadget/udc/trace.c2
-rw-r--r--drivers/usb/gadget/udc/trace.h2
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c4
-rw-r--r--drivers/usb/host/ehci-fsl.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ehci-hub.c139
-rw-r--r--drivers/usb/host/ehci-q.c2
-rw-r--r--drivers/usb/host/fotg210-hcd.c5
-rw-r--r--drivers/usb/host/fotg210.h3
-rw-r--r--drivers/usb/host/u132-hcd.c6
-rw-r--r--drivers/usb/host/xhci-mem.c3
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c60
-rw-r--r--drivers/usb/host/xhci-mtk.c2
-rw-r--r--drivers/usb/host/xhci-mtk.h10
-rw-r--r--drivers/usb/host/xhci-pci-renesas.c18
-rw-r--r--drivers/usb/host/xhci-ring.c7
-rw-r--r--drivers/usb/host/xhci-tegra.c621
-rw-r--r--drivers/usb/host/xhci.c10
-rw-r--r--drivers/usb/host/xhci.h11
-rw-r--r--drivers/usb/isp1760/Kconfig5
-rw-r--r--drivers/usb/isp1760/isp1760-core.c513
-rw-r--r--drivers/usb/isp1760/isp1760-core.h44
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.c1020
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.h57
-rw-r--r--drivers/usb/isp1760/isp1760-if.c41
-rw-r--r--drivers/usb/isp1760/isp1760-regs.h435
-rw-r--r--drivers/usb/isp1760/isp1760-udc.c251
-rw-r--r--drivers/usb/isp1760/isp1760-udc.h13
-rw-r--r--drivers/usb/misc/ftdi-elan.c1
-rw-r--r--drivers/usb/mtu3/mtu3.h30
-rw-r--r--drivers/usb/mtu3/mtu3_core.c20
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c1
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c169
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c2
-rw-r--r--drivers/usb/mtu3/mtu3_host.c6
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c95
-rw-r--r--drivers/usb/musb/musb_core.c71
-rw-r--r--drivers/usb/musb/musb_gadget.c2
-rw-r--r--drivers/usb/musb/musb_host.c18
-rw-r--r--drivers/usb/musb/musb_host.h4
-rw-r--r--drivers/usb/musb/musb_trace.h17
-rw-r--r--drivers/usb/musb/omap2430.c32
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c2
-rw-r--r--drivers/usb/phy/phy-isp1301.c25
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c15
-rw-r--r--drivers/usb/phy/phy.c55
-rw-r--r--drivers/usb/roles/class.c9
-rw-r--r--drivers/usb/serial/cp210x.c189
-rw-r--r--drivers/usb/serial/cyberjack.c4
-rw-r--r--drivers/usb/serial/cypress_m8.c16
-rw-r--r--drivers/usb/serial/digi_acceleport.c46
-rw-r--r--drivers/usb/serial/garmin_gps.c2
-rw-r--r--drivers/usb/serial/generic.c12
-rw-r--r--drivers/usb/serial/io_edgeport.c39
-rw-r--r--drivers/usb/serial/io_ti.c12
-rw-r--r--drivers/usb/serial/ir-usb.c6
-rw-r--r--drivers/usb/serial/keyspan.c4
-rw-r--r--drivers/usb/serial/kobil_sct.c4
-rw-r--r--drivers/usb/serial/metro-usb.c12
-rw-r--r--drivers/usb/serial/mos7720.c29
-rw-r--r--drivers/usb/serial/mos7840.c17
-rw-r--r--drivers/usb/serial/opticon.c6
-rw-r--r--drivers/usb/serial/oti6858.c12
-rw-r--r--drivers/usb/serial/quatech2.c6
-rw-r--r--drivers/usb/serial/sierra.c8
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c16
-rw-r--r--drivers/usb/serial/usb-wwan.h4
-rw-r--r--drivers/usb/serial/usb_wwan.c12
-rw-r--r--drivers/usb/typec/class.c4
-rw-r--r--drivers/usb/typec/mux.c39
-rw-r--r--drivers/usb/typec/mux.h6
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c28
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c46
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c86
-rw-r--r--drivers/usb/typec/tcpm/wcove.c2
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c4
149 files changed, 3915 insertions, 1942 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 4d3947476f0e..4ce7cba2b48a 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -180,7 +180,7 @@ struct cxacru_data {
struct mutex poll_state_serialize;
enum cxacru_poll_state poll_state;
- /* contol handles */
+ /* control handles */
struct mutex cm_serialize;
u8 *rcv_buf;
u8 *snd_buf;
diff --git a/drivers/usb/cdns3/cdns3-ep0.c b/drivers/usb/cdns3/cdns3-ep0.c
index 9a17802275d5..02ec7ab4bb48 100644
--- a/drivers/usb/cdns3/cdns3-ep0.c
+++ b/drivers/usb/cdns3/cdns3-ep0.c
@@ -677,7 +677,7 @@ static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
}
/**
- * cdns3_gadget_ep0_queue Transfer data on endpoint zero
+ * cdns3_gadget_ep0_queue - Transfer data on endpoint zero
* @ep: pointer to endpoint zero object
* @request: pointer to request object
* @gfp_flags: gfp flags
@@ -772,7 +772,7 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint
+ * cdns3_gadget_ep_set_wedge - Set wedge on selected endpoint
* @ep: endpoint object
*
* Returns 0
@@ -865,7 +865,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev)
}
/**
- * cdns3_init_ep0 Initializes software endpoint 0 of gadget
+ * cdns3_init_ep0 - Initializes software endpoint 0 of gadget
* @priv_dev: extended gadget object
* @priv_ep: extended endpoint object
*
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index 5281f8d3fb3d..5d8c982019af 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -155,7 +155,7 @@ static struct cdns3_request *cdns3_next_priv_request(struct list_head *list)
}
/**
- * select_ep - selects endpoint
+ * cdns3_select_ep - selects endpoint
* @priv_dev: extended gadget object
* @ep: endpoint address
*/
@@ -430,9 +430,7 @@ static int cdns3_start_all_request(struct cdns3_device *priv_dev,
if (ret)
return ret;
- list_del(&request->list);
- list_add_tail(&request->list,
- &priv_ep->pending_req_list);
+ list_move_tail(&request->list, &priv_ep->pending_req_list);
if (request->stream_id != 0 || (priv_ep->flags & EP_TDLCHK_EN))
break;
}
@@ -484,7 +482,7 @@ static void __cdns3_descmiss_copy_data(struct usb_request *request,
}
/**
- * cdns3_wa2_descmiss_copy_data copy data from internal requests to
+ * cdns3_wa2_descmiss_copy_data - copy data from internal requests to
* request queued by class driver.
* @priv_ep: extended endpoint object
* @request: request object
@@ -1835,7 +1833,7 @@ __must_hold(&priv_dev->lock)
}
/**
- * cdns3_device_irq_handler- interrupt handler for device part of controller
+ * cdns3_device_irq_handler - interrupt handler for device part of controller
*
* @irq: irq number for cdns3 core device
* @data: structure of cdns3
@@ -1879,7 +1877,7 @@ static irqreturn_t cdns3_device_irq_handler(int irq, void *data)
}
/**
- * cdns3_device_thread_irq_handler- interrupt handler for device part
+ * cdns3_device_thread_irq_handler - interrupt handler for device part
* of controller
*
* @irq: irq number for cdns3 core device
@@ -2022,7 +2020,7 @@ static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
}
/**
- * cdns3_ep_config Configure hardware endpoint
+ * cdns3_ep_config - Configure hardware endpoint
* @priv_ep: extended endpoint object
* @enable: set EP_CFG_ENABLE bit in ep_cfg register.
*/
@@ -2221,7 +2219,7 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget,
}
/**
- * cdns3_gadget_ep_alloc_request Allocates request
+ * cdns3_gadget_ep_alloc_request - Allocates request
* @ep: endpoint object associated with request
* @gfp_flags: gfp flags
*
@@ -2244,7 +2242,7 @@ struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_free_request Free memory occupied by request
+ * cdns3_gadget_ep_free_request - Free memory occupied by request
* @ep: endpoint object associated with request
* @request: request to free memory
*/
@@ -2261,7 +2259,7 @@ void cdns3_gadget_ep_free_request(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_enable Enable endpoint
+ * cdns3_gadget_ep_enable - Enable endpoint
* @ep: endpoint object
* @desc: endpoint descriptor
*
@@ -2396,7 +2394,7 @@ exit:
}
/**
- * cdns3_gadget_ep_disable Disable endpoint
+ * cdns3_gadget_ep_disable - Disable endpoint
* @ep: endpoint object
*
* Returns 0 on success, error code elsewhere
@@ -2486,7 +2484,7 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep)
}
/**
- * cdns3_gadget_ep_queue Transfer data on endpoint
+ * __cdns3_gadget_ep_queue - Transfer data on endpoint
* @ep: endpoint object
* @request: request object
* @gfp_flags: gfp flags
@@ -2586,7 +2584,7 @@ static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
}
/**
- * cdns3_gadget_ep_dequeue Remove request from transfer queue
+ * cdns3_gadget_ep_dequeue - Remove request from transfer queue
* @ep: endpoint object associated with request
* @request: request object
*
@@ -2653,7 +2651,7 @@ not_found:
}
/**
- * __cdns3_gadget_ep_set_halt Sets stall on selected endpoint
+ * __cdns3_gadget_ep_set_halt - Sets stall on selected endpoint
* Should be called after acquiring spin_lock and selecting ep
* @priv_ep: endpoint object to set stall on.
*/
@@ -2674,7 +2672,7 @@ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep)
}
/**
- * __cdns3_gadget_ep_clear_halt Clears stall on selected endpoint
+ * __cdns3_gadget_ep_clear_halt - Clears stall on selected endpoint
* Should be called after acquiring spin_lock and selecting ep
* @priv_ep: endpoint object to clear stall on
*/
@@ -2719,7 +2717,7 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep)
}
/**
- * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint
+ * cdns3_gadget_ep_set_halt - Sets/clears stall on selected endpoint
* @ep: endpoint object to set/clear stall on
* @value: 1 for set stall, 0 for clear stall
*
@@ -2765,7 +2763,7 @@ static const struct usb_ep_ops cdns3_gadget_ep_ops = {
};
/**
- * cdns3_gadget_get_frame Returns number of actual ITP frame
+ * cdns3_gadget_get_frame - Returns number of actual ITP frame
* @gadget: gadget object
*
* Returns number of actual ITP frame
@@ -2874,7 +2872,7 @@ static void cdns3_gadget_config(struct cdns3_device *priv_dev)
}
/**
- * cdns3_gadget_udc_start Gadget start
+ * cdns3_gadget_udc_start - Gadget start
* @gadget: gadget object
* @driver: driver which operates on this gadget
*
@@ -2920,7 +2918,7 @@ static int cdns3_gadget_udc_start(struct usb_gadget *gadget,
}
/**
- * cdns3_gadget_udc_stop Stops gadget
+ * cdns3_gadget_udc_stop - Stops gadget
* @gadget: gadget object
*
* Returns 0
@@ -2983,7 +2981,7 @@ static void cdns3_free_all_eps(struct cdns3_device *priv_dev)
}
/**
- * cdns3_init_eps Initializes software endpoints of gadget
+ * cdns3_init_eps - Initializes software endpoints of gadget
* @priv_dev: extended gadget object
*
* Returns 0 on success, error code elsewhere
diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c
index 74e758dc0895..59860d1753fd 100644
--- a/drivers/usb/cdns3/cdns3-imx.c
+++ b/drivers/usb/cdns3/cdns3-imx.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* cdns3-imx.c - NXP i.MX specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2019 NXP
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index e1deeada425c..4d0f027e5bd3 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -170,7 +170,7 @@ err_phy3_init:
}
/**
- * cdns3_remove - unbind drd driver and clean up
+ * cdns3_plat_remove() - unbind drd driver and clean up
* @pdev: Pointer to Linux platform device
*
* Returns 0 on success otherwise negative errno
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index eccb1c766bba..07c318770362 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index c083985e387b..c23f53e9b1ef 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -56,7 +56,8 @@ u32 cdnsp_port_state_to_neutral(u32 state)
}
/**
- * Find the offset of the extended capabilities with capability ID id.
+ * cdnsp_find_next_ext_cap - Find the offset of the extended capabilities
+ * with capability ID id.
* @base: PCI MMIO registers base address.
* @start: Address at which to start looking, (0 or HCC_PARAMS to start at
* beginning of list)
@@ -1151,7 +1152,7 @@ static int cdnsp_gadget_ep_set_halt(struct usb_ep *ep, int value)
struct cdnsp_ep *pep = to_cdnsp_ep(ep);
struct cdnsp_device *pdev = pep->pdev;
struct cdnsp_request *preq;
- unsigned long flags = 0;
+ unsigned long flags;
int ret;
spin_lock_irqsave(&pdev->lock, flags);
@@ -1176,7 +1177,7 @@ static int cdnsp_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct cdnsp_ep *pep = to_cdnsp_ep(ep);
struct cdnsp_device *pdev = pep->pdev;
- unsigned long flags = 0;
+ unsigned long flags;
int ret;
spin_lock_irqsave(&pdev->lock, flags);
diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
index 5d4c4bfe15b7..a47948a1623f 100644
--- a/drivers/usb/cdns3/cdnsp-mem.c
+++ b/drivers/usb/cdns3/cdnsp-mem.c
@@ -1082,9 +1082,8 @@ void cdnsp_mem_cleanup(struct cdnsp_device *pdev)
dma_pool_destroy(pdev->device_pool);
pdev->device_pool = NULL;
- if (pdev->dcbaa)
- dma_free_coherent(dev, sizeof(*pdev->dcbaa),
- pdev->dcbaa, pdev->dcbaa->dma);
+ dma_free_coherent(dev, sizeof(*pdev->dcbaa),
+ pdev->dcbaa, pdev->dcbaa->dma);
pdev->dcbaa = NULL;
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index bb739d88179f..dbcdf3b24b47 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -332,7 +332,7 @@ exit:
}
/**
- * cdsn3_role_get - get current role of controller.
+ * cdns_role_get - get current role of controller.
*
* @sw: pointer to USB role switch structure
*
@@ -419,7 +419,7 @@ static irqreturn_t cdns_wakeup_irq(int irq, void *data)
}
/**
- * cdns_probe - probe for cdns3/cdnsp core device
+ * cdns_init - probe for cdns3/cdnsp core device
* @cdns: Pointer to cdns structure.
*
* Returns 0 on success otherwise negative errno
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 0697eb980e5f..99440baa6458 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -195,7 +195,6 @@ struct hw_bank {
* @phy: pointer to PHY, if any
* @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework
* @hcd: pointer to usb_hcd for ehci host driver
- * @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
* @b_sess_valid_event: indicates there is a vbus event, and handled
* at ci_otg_work
@@ -249,7 +248,6 @@ struct ci_hdrc {
/* old usb_phy interface */
struct usb_phy *usb_phy;
struct usb_hcd *hcd;
- struct dentry *debugfs;
bool id_event;
bool b_sess_valid_event;
bool imx28_write_fix;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3f6c21406dbd..2b18f5088ae4 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -335,7 +335,7 @@ static int _ci_usb_phy_init(struct ci_hdrc *ci)
}
/**
- * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
+ * ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
* interfaces
* @ci: the controller
*/
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index da5d18cf6840..faf6b078b6c4 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -342,26 +342,20 @@ DEFINE_SHOW_ATTRIBUTE(ci_registers);
*/
void dbg_create_files(struct ci_hdrc *ci)
{
- ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
-
- debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
- &ci_device_fops);
- debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, ci,
- &ci_port_test_fops);
- debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
- &ci_qheads_fops);
- debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
- &ci_requests_fops);
-
- if (ci_otg_is_fsm_mode(ci)) {
- debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci,
- &ci_otg_fops);
- }
+ struct dentry *dir;
+
+ dir = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
+
+ debugfs_create_file("device", S_IRUGO, dir, ci, &ci_device_fops);
+ debugfs_create_file("port_test", S_IRUGO | S_IWUSR, dir, ci, &ci_port_test_fops);
+ debugfs_create_file("qheads", S_IRUGO, dir, ci, &ci_qheads_fops);
+ debugfs_create_file("requests", S_IRUGO, dir, ci, &ci_requests_fops);
+
+ if (ci_otg_is_fsm_mode(ci))
+ debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops);
- debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
- &ci_role_fops);
- debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
- &ci_registers_fops);
+ debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops);
+ debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
}
/**
@@ -370,5 +364,5 @@ void dbg_create_files(struct ci_hdrc *ci)
*/
void dbg_remove_files(struct ci_hdrc *ci)
{
- debugfs_remove_recursive(ci->debugfs);
+ debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root));
}
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index d3aada3ce7ec..8dd59282827b 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -22,7 +22,7 @@
#include "otg_fsm.h"
/**
- * hw_read_otgsc returns otgsc register bits value.
+ * hw_read_otgsc - returns otgsc register bits value.
* @ci: the controller
* @mask: bitfield mask
*/
@@ -75,7 +75,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
}
/**
- * hw_write_otgsc updates target bits of OTGSC register.
+ * hw_write_otgsc - updates target bits of OTGSC register.
* @ci: the controller
* @mask: bitfield mask
* @data: to be written
@@ -140,8 +140,9 @@ void ci_handle_vbus_change(struct ci_hdrc *ci)
}
/**
- * When we switch to device mode, the vbus value should be lower
- * than OTGSC_BSV before connecting to host.
+ * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value
+ * should be lower than OTGSC_BSV before connecting
+ * to host.
*
* @ci: the controller
*
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 393f216b9161..8834ca613721 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -238,7 +238,7 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
}
/**
- * hw_is_port_high_speed: test if port is high speed
+ * hw_port_is_high_speed: test if port is high speed
* @ci: the controller
*
* This function returns true if high speed port
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index c9954eb56e00..4895325b16a4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1946,6 +1946,11 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
+ /* Exclude Heimann Sensor GmbH USB appset demo */
+ { USB_DEVICE(0x32a7, 0x0000),
+ .driver_info = IGNORE_DEVICE,
+ },
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 8e5490ac13a2..fdf79bcf7eb0 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -1035,9 +1035,10 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
INIT_WORK(&desc->rxwork, wdm_rxwork);
INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
- rv = -EINVAL;
- if (!usb_endpoint_is_int_in(ep))
+ if (!usb_endpoint_is_int_in(ep)) {
+ rv = -EINVAL;
goto err;
+ }
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index ce5e6f6711f7..7e13b74e60e5 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -141,7 +141,7 @@ static const struct device_type ulpi_dev_type = {
/* -------------------------------------------------------------------------- */
/**
- * ulpi_register_driver - register a driver with the ULPI bus
+ * __ulpi_register_driver - register a driver with the ULPI bus
* @drv: driver being registered
* @module: ends up being THIS_MODULE
*
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
index 6c4e3a19f42c..0158148cb054 100644
--- a/drivers/usb/common/usb-conn-gpio.c
+++ b/drivers/usb/common/usb-conn-gpio.c
@@ -83,11 +83,11 @@ static void usb_conn_detect_cable(struct work_struct *work)
else
role = USB_ROLE_NONE;
- dev_dbg(info->dev, "role %d/%d, gpios: id %d, vbus %d\n",
- info->last_role, role, id, vbus);
+ dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
+ usb_role_string(info->last_role), usb_role_string(role), id, vbus);
if (info->last_role == role) {
- dev_warn(info->dev, "repeated role: %d\n", role);
+ dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
return;
}
@@ -149,14 +149,32 @@ static int usb_charger_get_property(struct power_supply *psy,
return 0;
}
-static int usb_conn_probe(struct platform_device *pdev)
+static int usb_conn_psy_register(struct usb_conn_info *info)
{
- struct device *dev = &pdev->dev;
- struct power_supply_desc *desc;
- struct usb_conn_info *info;
+ struct device *dev = info->dev;
+ struct power_supply_desc *desc = &info->desc;
struct power_supply_config cfg = {
.of_node = dev->of_node,
};
+
+ desc->name = "usb-charger";
+ desc->properties = usb_charger_properties;
+ desc->num_properties = ARRAY_SIZE(usb_charger_properties);
+ desc->get_property = usb_charger_get_property;
+ desc->type = POWER_SUPPLY_TYPE_USB;
+ cfg.drv_data = info;
+
+ info->charger = devm_power_supply_register(dev, desc, &cfg);
+ if (IS_ERR(info->charger))
+ dev_err(dev, "Unable to register charger\n");
+
+ return PTR_ERR_OR_ZERO(info->charger);
+}
+
+static int usb_conn_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_conn_info *info;
bool need_vbus = true;
int ret = 0;
@@ -205,18 +223,18 @@ static int usb_conn_probe(struct platform_device *pdev)
}
if (IS_ERR(info->vbus)) {
- if (PTR_ERR(info->vbus) != -EPROBE_DEFER)
- dev_err(dev, "failed to get vbus: %ld\n", PTR_ERR(info->vbus));
- return PTR_ERR(info->vbus);
+ ret = PTR_ERR(info->vbus);
+ return dev_err_probe(dev, ret, "failed to get vbus :%d\n", ret);
}
info->role_sw = usb_role_switch_get(dev);
- if (IS_ERR(info->role_sw)) {
- if (PTR_ERR(info->role_sw) != -EPROBE_DEFER)
- dev_err(dev, "failed to get role switch\n");
+ if (IS_ERR(info->role_sw))
+ return dev_err_probe(dev, PTR_ERR(info->role_sw),
+ "failed to get role switch\n");
- return PTR_ERR(info->role_sw);
- }
+ ret = usb_conn_psy_register(info);
+ if (ret)
+ goto put_role_sw;
if (info->id_gpiod) {
info->id_irq = gpiod_to_irq(info->id_gpiod);
@@ -252,20 +270,6 @@ static int usb_conn_probe(struct platform_device *pdev)
}
}
- desc = &info->desc;
- desc->name = "usb-charger";
- desc->properties = usb_charger_properties;
- desc->num_properties = ARRAY_SIZE(usb_charger_properties);
- desc->get_property = usb_charger_get_property;
- desc->type = POWER_SUPPLY_TYPE_USB;
- cfg.drv_data = info;
-
- info->charger = devm_power_supply_register(dev, desc, &cfg);
- if (IS_ERR(info->charger)) {
- dev_err(dev, "Unable to register charger\n");
- return PTR_ERR(info->charger);
- }
-
platform_set_drvdata(pdev, info);
/* Perform initial detection */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 2218941d35a3..b97464498763 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1162,7 +1162,7 @@ static int do_proc_control(struct usb_dev_state *ps,
tbuf, ctrl->wLength);
usb_unlock_device(dev);
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest,
+ i = usb_control_msg(dev, pipe, ctrl->bRequest,
ctrl->bRequestType, ctrl->wValue, ctrl->wIndex,
tbuf, ctrl->wLength, tmo);
usb_lock_device(dev);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 6119fb41d736..0f8b7c93310e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2111,6 +2111,136 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+static void usb_ehset_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = (void *)dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = usb_ehset_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+ usb_put_urb(urb);
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->context = done;
+ return urb;
+}
+
+int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval = -ENOMEM;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct usb_device_descriptor *buf;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = usb_hub_find_child(hcd->self.root_hub, port);
+ if (!udev) {
+ dev_err(hcd->self.controller, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Submit just the SETUP stage */
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
+ if (retval)
+ goto out1;
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and STATUS stages using the same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
+/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index df8e69e60aaf..d1efc7141333 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2434,6 +2434,8 @@ static void set_usb_port_removable(struct usb_device *udev)
u16 wHubCharacteristics;
bool removable = true;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE_UNKNOWN);
+
if (!hdev)
return;
@@ -2445,11 +2447,11 @@ static void set_usb_port_removable(struct usb_device *udev)
*/
switch (hub->ports[udev->portnum - 1]->connect_type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
- udev->removable = USB_DEVICE_REMOVABLE;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
return;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
case USB_PORT_NOT_USED:
- udev->removable = USB_DEVICE_FIXED;
+ dev_set_removable(&udev->dev, DEVICE_FIXED);
return;
default:
break;
@@ -2474,9 +2476,9 @@ static void set_usb_port_removable(struct usb_device *udev)
}
if (removable)
- udev->removable = USB_DEVICE_REMOVABLE;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
else
- udev->removable = USB_DEVICE_FIXED;
+ dev_set_removable(&udev->dev, DEVICE_FIXED);
}
@@ -2548,8 +2550,7 @@ int usb_new_device(struct usb_device *udev)
device_enable_async_suspend(&udev->dev);
/* check whether the hub or firmware marks this port as non-removable */
- if (udev->parent)
- set_usb_port_removable(udev);
+ set_usb_port_removable(udev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
@@ -3387,6 +3388,26 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
status = 0;
}
if (status) {
+ /* Check if the port has been suspended for the timeout case
+ * to prevent the suspended port from incorrect handling.
+ */
+ if (status == -ETIMEDOUT) {
+ int ret;
+ u16 portstatus, portchange;
+
+ portstatus = portchange = 0;
+ ret = hub_port_status(hub, port1, &portstatus,
+ &portchange);
+
+ dev_dbg(&port_dev->dev,
+ "suspend timeout, status %04x\n", portstatus);
+
+ if (ret == 0 && port_is_suspended(hub, portstatus)) {
+ status = 0;
+ goto suspend_done;
+ }
+ }
+
dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
/* Try to enable USB3 LTM again */
@@ -3403,6 +3424,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (!PMSG_IS_AUTO(msg))
status = 0;
} else {
+ suspend_done:
dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
udev->do_remote_wakeup);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 30e9e680c74c..4d59d927ae3e 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -783,6 +783,9 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
int i;
int result;
+ if (size <= 0) /* No point in asking for no data */
+ return -EINVAL;
+
memset(buf, 0, size); /* Make sure we parse really received data */
for (i = 0; i < 3; ++i) {
@@ -832,6 +835,9 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
int i;
int result;
+ if (size <= 0) /* No point in asking for no data */
+ return -EINVAL;
+
for (i = 0; i < 3; ++i) {
/* retry on length 0 or stall; some devices are flakey */
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 21e7522655ac..6114cf83bb44 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -406,7 +406,6 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Realtek hub in Dell WD19 (Type-C) */
{ USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
- { USB_DEVICE(0x0bda, 0x5487), .driver_info = USB_QUIRK_RESET_RESUME },
/* Generic RTL8153 based ethernet adapters */
{ USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5a168ba9fc51..fa2e49d432ff 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -301,29 +301,6 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(urbnum);
-static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct usb_device *udev;
- char *state;
-
- udev = to_usb_device(dev);
-
- switch (udev->removable) {
- case USB_DEVICE_REMOVABLE:
- state = "removable";
- break;
- case USB_DEVICE_FIXED:
- state = "fixed";
- break;
- default:
- state = "unknown";
- }
-
- return sprintf(buf, "%s\n", state);
-}
-static DEVICE_ATTR_RO(removable);
-
static ssize_t ltm_capable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -828,7 +805,6 @@ static struct attribute *dev_attrs[] = {
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
- &dev_attr_removable.attr,
&dev_attr_ltm_capable.attr,
#ifdef CONFIG_OF
&dev_attr_devspec.attr,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 357b149b20d3..30727729a44c 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -407,6 +407,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
+ dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out),
+ "BOGUS control dir, pipe %x doesn't match bRequestType %x\n",
+ urb->pipe, setup->bRequestType);
+ if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) {
+ dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n",
+ le16_to_cpu(setup->wLength),
+ urb->transfer_buffer_length);
+ return -EBADR;
+ }
} else {
is_out = usb_endpoint_dir_out(&ep->desc);
}
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 6f70ab9577b4..272ae5722c86 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -1111,15 +1111,6 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
if (hsotg->params.phy_utmi_width == 16)
usbcfg |= GUSBCFG_PHYIF16;
-
- /* Set turnaround time */
- if (dwc2_is_device_mode(hsotg)) {
- usbcfg &= ~GUSBCFG_USBTRDTIM_MASK;
- if (hsotg->params.phy_utmi_width == 16)
- usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT;
- else
- usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT;
- }
break;
default:
dev_err(hsotg->dev, "FS PHY selected at HS!\n");
@@ -1141,6 +1132,24 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
return retval;
}
+static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+
+ if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI)
+ return;
+
+ usbcfg = dwc2_readl(hsotg, GUSBCFG);
+
+ usbcfg &= ~GUSBCFG_USBTRDTIM_MASK;
+ if (hsotg->params.phy_utmi_width == 16)
+ usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT;
+ else
+ usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT;
+
+ dwc2_writel(hsotg, usbcfg, GUSBCFG);
+}
+
int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
u32 usbcfg;
@@ -1158,6 +1167,9 @@ int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
retval = dwc2_hs_phy_init(hsotg, select_phy);
if (retval)
return retval;
+
+ if (dwc2_is_device_mode(hsotg))
+ dwc2_set_turnaround_time(hsotg);
}
if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 184964174dc0..c581ee41ac81 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1496,8 +1496,8 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
{
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent;
- unsigned long flags = 0;
- int ret = 0;
+ unsigned long flags;
+ int ret;
spin_lock_irqsave(&hs->lock, flags);
ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags);
@@ -3338,7 +3338,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
- * dwc2_hsotg_core_init - issue softreset to the core
+ * dwc2_hsotg_core_init_disconnected - issue softreset to the core
* @hsotg: The device state
* @is_usb_reset: Usb resetting flag
*
@@ -4374,8 +4374,8 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
{
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent;
- unsigned long flags = 0;
- int ret = 0;
+ unsigned long flags;
+ int ret;
spin_lock_irqsave(&hs->lock, flags);
ret = dwc2_hsotg_ep_sethalt(ep, value, false);
@@ -4505,7 +4505,7 @@ err:
static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
- unsigned long flags = 0;
+ unsigned long flags;
int ep;
if (!hsotg)
@@ -4577,7 +4577,7 @@ static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on,
hsotg->op_state);
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 621a4846bd05..89a788326c56 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -675,7 +675,7 @@ static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
}
/**
- * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
+ * dwc2_hs_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
*
* @hsotg: The HCD state structure for the DWC OTG controller.
* @qh: QH for the periodic transfer.
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 7a6089fa81e1..67c5eb140232 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -784,8 +784,8 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
}
/**
- * During device initialization, read various hardware configuration
- * registers and interpret the contents.
+ * dwc2_get_hwparams() - During device initialization, read various hardware
+ * configuration registers and interpret the contents.
*
* @hsotg: Programming view of the DWC_otg controller
*
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
index 0000151e3ca9..a93559b4ecdb 100644
--- a/drivers/usb/dwc2/pci.c
+++ b/drivers/usb/dwc2/pci.c
@@ -64,7 +64,7 @@ struct dwc2_pci_glue {
};
/**
- * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI
+ * dwc2_pci_remove() - Provides the cleanup entry points for the DWC_otg PCI
* driver
*
* @pci: The programming view of DWC_otg PCI
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 520a0beef77c..c8f18f3ba9e3 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -408,7 +408,7 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
}
/**
- * Check core version
+ * dwc2_check_core_version() - Check core version
*
* @hsotg: Programming view of the DWC_otg controller
*
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 4ac397e43e19..ba74ad7f6995 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1545,6 +1545,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_properties(dwc);
+ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
@@ -1616,17 +1620,18 @@ static int dwc3_probe(struct platform_device *pdev)
}
dwc3_check_params(dwc);
+ dwc3_debugfs_init(dwc);
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err5;
- dwc3_debugfs_init(dwc);
pm_runtime_put(dev);
return 0;
err5:
+ dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
usb_phy_shutdown(dwc->usb2_phy);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index c5d5760cdf53..dccdf13b5f9e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1013,7 +1013,6 @@ struct dwc3_scratchpad_array {
* @link_state: link state
* @speed: device speed (super, high, full, low)
* @hwparams: copy of hwparams registers
- * @root: debugfs root folder pointer
* @regset: debugfs pointer to regdump file
* @dbg_lsp_select: current debug lsp mux register selection
* @test_mode: true when we're entering a USB test mode
@@ -1222,7 +1221,6 @@ struct dwc3 {
u8 num_eps;
struct dwc3_hwparams hwparams;
- struct dentry *root;
struct debugfs_regset32 *regset;
u32 dbg_lsp_select;
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 5dbbe53269d3..f2b7675c7f62 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -889,8 +889,10 @@ static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
{
struct dentry *dir;
+ struct dentry *root;
- dir = debugfs_create_dir(dep->name, dep->dwc->root);
+ root = debugfs_lookup(dev_name(dep->dwc->dev), usb_debug_root);
+ dir = debugfs_create_dir(dep->name, root);
dwc3_debugfs_create_endpoint_files(dep, dir);
}
@@ -909,8 +911,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root);
- dwc->root = root;
-
debugfs_create_regset32("regdump", 0444, root, dwc->regset);
debugfs_create_file("lsp_dump", 0644, root, dwc, &dwc3_lsp_fops);
@@ -929,6 +929,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
void dwc3_debugfs_exit(struct dwc3 *dwc)
{
- debugfs_remove_recursive(dwc->root);
+ debugfs_remove(debugfs_lookup(dev_name(dwc->dev), usb_debug_root));
kfree(dwc->regset);
}
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index e2b68bb770d1..8fcbac10510c 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -596,7 +596,6 @@ int dwc3_drd_init(struct dwc3 *dwc)
dwc3_drd_update(dwc);
} else {
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
- dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
/* use OTG block to get ID event */
irq = dwc3_otg_get_irq(dwc);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 1e51460938b8..2b37bdd39a74 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -36,7 +36,7 @@
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0
#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
-#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
+#define PCI_DEVICE_ID_INTEL_EHL 0x4b7e
#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
#define PCI_DEVICE_ID_INTEL_TGPH 0x43ee
#define PCI_DEVICE_ID_INTEL_JSP 0x4dee
@@ -167,7 +167,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M ||
- pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) {
+ pdev->device == PCI_DEVICE_ID_INTEL_EHL) {
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
dwc->has_dsm_for_pm = true;
}
@@ -375,8 +375,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL),
+ (kernel_ulong_t) &dwc3_pci_intel_swnode, },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f14c2aa83759..af6d7f157989 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2798,7 +2798,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
list_del(&dep->endpoint.ep_list);
}
- debugfs_remove_recursive(debugfs_lookup(dep->name, dwc->root));
+ debugfs_remove_recursive(debugfs_lookup(dep->name,
+ debugfs_lookup(dev_name(dep->dwc->dev),
+ usb_debug_root)));
kfree(dep);
}
}
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 51d18e8d1602..cb998ba50fea 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -222,8 +222,6 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_STRUCT__entry(
__string(name, dep->name)
__field(struct dwc3_trb *, trb)
- __field(u32, allocated)
- __field(u32, queued)
__field(u32, bpl)
__field(u32, bph)
__field(u32, size)
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 2cd9942707b4..5d38f29bda72 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -30,6 +30,11 @@ struct f_eem {
u8 ctrl_id;
};
+struct in_context {
+ struct sk_buff *skb;
+ struct usb_ep *ep;
+};
+
static inline struct f_eem *func_to_eem(struct usb_function *f)
{
return container_of(f, struct f_eem, port.func);
@@ -320,9 +325,12 @@ fail:
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct sk_buff *skb = (struct sk_buff *)req->context;
+ struct in_context *ctx = req->context;
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(ctx->skb);
+ kfree(req->buf);
+ usb_ep_free_request(ctx->ep, req);
+ kfree(ctx);
}
/*
@@ -410,7 +418,9 @@ static int eem_unwrap(struct gether *port,
* b15: bmType (0 == data, 1 == command)
*/
if (header & BIT(15)) {
- struct usb_request *req = cdev->req;
+ struct usb_request *req;
+ struct in_context *ctx;
+ struct usb_ep *ep;
u16 bmEEMCmd;
/* EEM command packet format:
@@ -439,11 +449,36 @@ static int eem_unwrap(struct gether *port,
skb_trim(skb2, len);
put_unaligned_le16(BIT(15) | BIT(11) | len,
skb_push(skb2, 2));
+
+ ep = port->in_ep;
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (!req) {
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+
+ req->buf = kmalloc(skb2->len, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+ ctx->skb = skb2;
+ ctx->ep = ep;
+
skb_copy_bits(skb2, 0, req->buf, skb2->len);
req->length = skb2->len;
req->complete = eem_cmd_complete;
req->zero = 1;
- req->context = skb2;
+ req->context = ctx;
if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
DBG(cdev, "echo response queue fail\n");
break;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index d4844afeaffc..9c0c393abb39 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -250,8 +250,8 @@ EXPORT_SYMBOL_GPL(ffs_lock);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
static void _ffs_free_dev(struct ffs_dev *dev);
-static void *ffs_acquire_dev(const char *dev_name);
-static void ffs_release_dev(struct ffs_data *ffs_data);
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
+static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
@@ -1554,8 +1554,8 @@ unmapped_value:
static int ffs_fs_get_tree(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx = fc->fs_private;
- void *ffs_dev;
struct ffs_data *ffs;
+ int ret;
ENTER();
@@ -1574,13 +1574,12 @@ static int ffs_fs_get_tree(struct fs_context *fc)
return -ENOMEM;
}
- ffs_dev = ffs_acquire_dev(ffs->dev_name);
- if (IS_ERR(ffs_dev)) {
+ ret = ffs_acquire_dev(ffs->dev_name, ffs);
+ if (ret) {
ffs_data_put(ffs);
- return PTR_ERR(ffs_dev);
+ return ret;
}
- ffs->private_data = ffs_dev;
ctx->ffs_data = ffs;
return get_tree_nodev(fc, ffs_sb_fill);
}
@@ -1591,7 +1590,6 @@ static void ffs_fs_free_fc(struct fs_context *fc)
if (ctx) {
if (ctx->ffs_data) {
- ffs_release_dev(ctx->ffs_data);
ffs_data_put(ctx->ffs_data);
}
@@ -1630,10 +1628,8 @@ ffs_fs_kill_sb(struct super_block *sb)
ENTER();
kill_litter_super(sb);
- if (sb->s_fs_info) {
- ffs_release_dev(sb->s_fs_info);
+ if (sb->s_fs_info)
ffs_data_closed(sb->s_fs_info);
- }
}
static struct file_system_type ffs_fs_type = {
@@ -1703,6 +1699,7 @@ static void ffs_data_put(struct ffs_data *ffs)
if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
+ ffs_release_dev(ffs->private_data);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
swait_active(&ffs->ep0req_completion.wait) ||
waitqueue_active(&ffs->wait));
@@ -3032,6 +3029,7 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
struct ffs_function *func = ffs_func_from_usb(f);
struct f_fs_opts *ffs_opts =
container_of(f->fi, struct f_fs_opts, func_inst);
+ struct ffs_data *ffs_data;
int ret;
ENTER();
@@ -3046,12 +3044,13 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
if (!ffs_opts->no_configfs)
ffs_dev_lock();
ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
- func->ffs = ffs_opts->dev->ffs_data;
+ ffs_data = ffs_opts->dev->ffs_data;
if (!ffs_opts->no_configfs)
ffs_dev_unlock();
if (ret)
return ERR_PTR(ret);
+ func->ffs = ffs_data;
func->conf = c;
func->gadget = c->cdev->gadget;
@@ -3506,6 +3505,7 @@ static void ffs_free_inst(struct usb_function_instance *f)
struct f_fs_opts *opts;
opts = to_f_fs_opts(f);
+ ffs_release_dev(opts->dev);
ffs_dev_lock();
_ffs_free_dev(opts->dev);
ffs_dev_unlock();
@@ -3693,47 +3693,48 @@ static void _ffs_free_dev(struct ffs_dev *dev)
{
list_del(&dev->entry);
- /* Clear the private_data pointer to stop incorrect dev access */
- if (dev->ffs_data)
- dev->ffs_data->private_data = NULL;
-
kfree(dev);
if (list_empty(&ffs_devices))
functionfs_cleanup();
}
-static void *ffs_acquire_dev(const char *dev_name)
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
{
+ int ret = 0;
struct ffs_dev *ffs_dev;
ENTER();
ffs_dev_lock();
ffs_dev = _ffs_find_dev(dev_name);
- if (!ffs_dev)
- ffs_dev = ERR_PTR(-ENOENT);
- else if (ffs_dev->mounted)
- ffs_dev = ERR_PTR(-EBUSY);
- else if (ffs_dev->ffs_acquire_dev_callback &&
- ffs_dev->ffs_acquire_dev_callback(ffs_dev))
- ffs_dev = ERR_PTR(-ENOENT);
- else
+ if (!ffs_dev) {
+ ret = -ENOENT;
+ } else if (ffs_dev->mounted) {
+ ret = -EBUSY;
+ } else if (ffs_dev->ffs_acquire_dev_callback &&
+ ffs_dev->ffs_acquire_dev_callback(ffs_dev)) {
+ ret = -ENOENT;
+ } else {
ffs_dev->mounted = true;
+ ffs_dev->ffs_data = ffs_data;
+ ffs_data->private_data = ffs_dev;
+ }
ffs_dev_unlock();
- return ffs_dev;
+ return ret;
}
-static void ffs_release_dev(struct ffs_data *ffs_data)
+static void ffs_release_dev(struct ffs_dev *ffs_dev)
{
- struct ffs_dev *ffs_dev;
-
ENTER();
ffs_dev_lock();
- ffs_dev = ffs_data->private_data;
- if (ffs_dev) {
+ if (ffs_dev && ffs_dev->mounted) {
ffs_dev->mounted = false;
+ if (ffs_dev->ffs_data) {
+ ffs_dev->ffs_data->private_data = NULL;
+ ffs_dev->ffs_data = NULL;
+ }
if (ffs_dev->ffs_release_dev_callback)
ffs_dev->ffs_release_dev_callback(ffs_dev);
@@ -3761,7 +3762,6 @@ static int ffs_ready(struct ffs_data *ffs)
}
ffs_obj->desc_ready = true;
- ffs_obj->ffs_data = ffs;
if (ffs_obj->ffs_ready_callback) {
ret = ffs_obj->ffs_ready_callback(ffs);
@@ -3789,7 +3789,6 @@ static void ffs_closed(struct ffs_data *ffs)
goto done;
ffs_obj->desc_ready = false;
- ffs_obj->ffs_data = NULL;
if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
ffs_obj->ffs_closed_callback)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index e55699308117..02683ac0719d 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -88,7 +88,7 @@ static struct usb_interface_descriptor hidg_interface_desc = {
static struct hid_descriptor hidg_desc = {
.bLength = sizeof hidg_desc,
.bDescriptorType = HID_DT_HID,
- .bcdHID = 0x0101,
+ .bcdHID = cpu_to_le16(0x0101),
.bCountryCode = 0x00,
.bNumDescriptors = 0x1,
/*.desc[0].bDescriptorType = DYNAMIC */
@@ -1118,7 +1118,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
hidg->func.setup = hidg_setup;
hidg->func.free_func = hidg_free;
- /* this could me made configurable at some point */
+ /* this could be made configurable at some point */
hidg->qlen = 4;
return &hidg->func;
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 59d382fe1bbf..abec5c58f525 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -667,8 +667,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
spin_lock(&dev->lock);
if (value) {
- list_del(&req->list);
- list_add(&req->list, &dev->tx_reqs);
+ list_move(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return -EAGAIN;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 7aa4c8bc5a1a..ae29ff2b2b68 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -44,6 +44,7 @@
#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC)
struct f_uac2 {
struct g_audio g_audio;
@@ -273,7 +274,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 1,
};
@@ -282,7 +283,7 @@ static struct usb_endpoint_descriptor hs_epout_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -292,7 +293,7 @@ static struct usb_endpoint_descriptor ss_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -317,6 +318,37 @@ static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
.wLockDelay = 0,
};
+/* STD AS ISO IN Feedback Endpoint */
+static struct usb_endpoint_descriptor fs_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(3),
+ .bInterval = 1,
+};
+
+static struct usb_endpoint_descriptor hs_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(4),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor ss_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(4),
+ .bInterval = 4,
+};
+
+
/* Audio Streaming IN Interface - Alt0 */
static struct usb_interface_descriptor std_as_in_if0_desc = {
.bLength = sizeof std_as_in_if0_desc,
@@ -431,6 +463,7 @@ static struct usb_descriptor_header *fs_audio_desc[] = {
(struct usb_descriptor_header *)&as_out_fmt1_desc,
(struct usb_descriptor_header *)&fs_epout_desc,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&fs_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -461,6 +494,7 @@ static struct usb_descriptor_header *hs_audio_desc[] = {
(struct usb_descriptor_header *)&as_out_fmt1_desc,
(struct usb_descriptor_header *)&hs_epout_desc,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&hs_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -492,6 +526,7 @@ static struct usb_descriptor_header *ss_audio_desc[] = {
(struct usb_descriptor_header *)&ss_epout_desc,
(struct usb_descriptor_header *)&ss_epout_desc_comp,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&ss_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -549,8 +584,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
ssize = uac2_opts->c_ssize;
}
+ if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC))
+ srate = srate * (1000 + uac2_opts->fb_max) / 1000;
+
max_size_bw = num_channels(chmask) * ssize *
- ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
+ DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
@@ -568,22 +606,26 @@ static void setup_headers(struct f_uac2_opts *opts,
struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL;
struct usb_endpoint_descriptor *epout_desc;
struct usb_endpoint_descriptor *epin_desc;
+ struct usb_endpoint_descriptor *epin_fback_desc;
int i;
switch (speed) {
case USB_SPEED_FULL:
epout_desc = &fs_epout_desc;
epin_desc = &fs_epin_desc;
+ epin_fback_desc = &fs_epin_fback_desc;
break;
case USB_SPEED_HIGH:
epout_desc = &hs_epout_desc;
epin_desc = &hs_epin_desc;
+ epin_fback_desc = &hs_epin_fback_desc;
break;
default:
epout_desc = &ss_epout_desc;
epin_desc = &ss_epin_desc;
epout_desc_comp = &ss_epout_desc_comp;
epin_desc_comp = &ss_epin_desc_comp;
+ epin_fback_desc = &ss_epin_fback_desc;
}
i = 0;
@@ -611,6 +653,9 @@ static void setup_headers(struct f_uac2_opts *opts,
headers[i++] = USBDHDR(epout_desc_comp);
headers[i++] = USBDHDR(&as_iso_out_desc);
+
+ if (EPOUT_FBACK_IN_EN(opts))
+ headers[i++] = USBDHDR(epin_fback_desc);
}
if (EPIN_EN(opts)) {
headers[i++] = USBDHDR(&std_as_in_if0_desc);
@@ -781,6 +826,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
std_as_out_if1_desc.bInterfaceNumber = ret;
uac2->as_out_intf = ret;
uac2->as_out_alt = 0;
+
+ if (EPOUT_FBACK_IN_EN(uac2_opts)) {
+ fs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ hs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ ss_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ std_as_out_if1_desc.bNumEndpoints++;
+ } else {
+ fs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ hs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ ss_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ }
}
if (EPIN_EN(uac2_opts)) {
@@ -844,6 +906,15 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return -ENODEV;
}
+ if (EPOUT_FBACK_IN_EN(uac2_opts)) {
+ agdev->in_ep_fback = usb_ep_autoconfig(gadget,
+ &fs_epin_fback_desc);
+ if (!agdev->in_ep_fback) {
+ dev_err(dev, "%s:%d Error!\n",
+ __func__, __LINE__);
+ return -ENODEV;
+ }
+ }
}
if (EPIN_EN(uac2_opts)) {
@@ -867,8 +938,10 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
le16_to_cpu(ss_epout_desc.wMaxPacketSize));
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
setup_descriptor(uac2_opts);
@@ -887,6 +960,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
agdev->params.c_srate = uac2_opts->c_srate;
agdev->params.c_ssize = uac2_opts->c_ssize;
agdev->params.req_number = uac2_opts->req_number;
+ agdev->params.fb_max = uac2_opts->fb_max;
ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget");
if (ret)
goto err_free_descs;
@@ -1195,13 +1269,71 @@ end: \
\
CONFIGFS_ATTR(f_uac2_opts_, name)
+#define UAC2_ATTRIBUTE_SYNC(name) \
+static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
+ int result; \
+ char *str; \
+ \
+ mutex_lock(&opts->lock); \
+ switch (opts->name) { \
+ case USB_ENDPOINT_SYNC_ASYNC: \
+ str = "async"; \
+ break; \
+ case USB_ENDPOINT_SYNC_ADAPTIVE: \
+ str = "adaptive"; \
+ break; \
+ default: \
+ str = "unknown"; \
+ break; \
+ } \
+ result = sprintf(page, "%s\n", str); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
+ const char *page, size_t len) \
+{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
+ int ret = 0; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ if (!strncmp(page, "async", 5)) \
+ opts->name = USB_ENDPOINT_SYNC_ASYNC; \
+ else if (!strncmp(page, "adaptive", 8)) \
+ opts->name = USB_ENDPOINT_SYNC_ADAPTIVE; \
+ else { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ \
+ ret = len; \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+CONFIGFS_ATTR(f_uac2_opts_, name)
+
UAC2_ATTRIBUTE(p_chmask);
UAC2_ATTRIBUTE(p_srate);
UAC2_ATTRIBUTE(p_ssize);
UAC2_ATTRIBUTE(c_chmask);
UAC2_ATTRIBUTE(c_srate);
+UAC2_ATTRIBUTE_SYNC(c_sync);
UAC2_ATTRIBUTE(c_ssize);
UAC2_ATTRIBUTE(req_number);
+UAC2_ATTRIBUTE(fb_max);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_p_chmask,
@@ -1210,7 +1342,9 @@ static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_c_chmask,
&f_uac2_opts_attr_c_srate,
&f_uac2_opts_attr_c_ssize,
+ &f_uac2_opts_attr_c_sync,
&f_uac2_opts_attr_req_number,
+ &f_uac2_opts_attr_fb_max,
NULL,
};
@@ -1248,7 +1382,9 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->c_chmask = UAC2_DEF_CCHMASK;
opts->c_srate = UAC2_DEF_CSRATE;
opts->c_ssize = UAC2_DEF_CSSIZE;
+ opts->c_sync = UAC2_DEF_CSYNC;
opts->req_number = UAC2_DEF_REQ_NUM;
+ opts->fb_max = UAC2_DEF_FB_MAX;
return &opts->func_inst;
}
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index 5fbceee897a3..018dd0978995 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -16,6 +16,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/control.h>
#include "u_audio.h"
@@ -35,9 +36,13 @@ struct uac_rtd_params {
void *rbuf;
+ unsigned int pitch; /* Stream pitch ratio to 1000000 */
unsigned int max_psize; /* MaxPacketSize of endpoint */
struct usb_request **reqs;
+
+ struct usb_request *req_fback; /* Feedback endpoint request */
+ bool fb_ep_enabled; /* if the ep is enabled */
};
struct snd_uac_chip {
@@ -70,6 +75,48 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
.periods_min = MIN_PERIODS,
};
+static void u_audio_set_fback_frequency(enum usb_device_speed speed,
+ unsigned long long freq,
+ unsigned int pitch,
+ void *buf)
+{
+ u32 ff = 0;
+
+ /*
+ * Because the pitch base is 1000000, the final divider here
+ * will be 1000 * 1000000 = 1953125 << 9
+ *
+ * Instead of dealing with big numbers lets fold this 9 left shift
+ */
+
+ if (speed == USB_SPEED_FULL) {
+ /*
+ * Full-speed feedback endpoints report frequency
+ * in samples/frame
+ * Format is encoded in Q10.10 left-justified in the 24 bits,
+ * so that it has a Q10.14 format.
+ *
+ * ff = (freq << 14) / 1000
+ */
+ freq <<= 5;
+ } else {
+ /*
+ * High-speed feedback endpoints report frequency
+ * in samples/microframe.
+ * Format is encoded in Q12.13 fitted into four bytes so that
+ * the binary point is located between the second and the third
+ * byte fromat (that is Q16.16)
+ *
+ * ff = (freq << 16) / 8000
+ */
+ freq <<= 4;
+ }
+
+ ff = DIV_ROUND_CLOSEST_ULL((freq * pitch), 1953125);
+
+ *(__le32 *)buf = cpu_to_le32(ff);
+}
+
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
{
unsigned int pending;
@@ -173,6 +220,35 @@ exit:
dev_err(uac->card->dev, "%d Error!\n", __LINE__);
}
+static void u_audio_iso_fback_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct uac_rtd_params *prm = req->context;
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ int status = req->status;
+
+ /* i/f shutting down */
+ if (!prm->fb_ep_enabled || req->status == -ESHUTDOWN)
+ return;
+
+ /*
+ * We can't really do much about bad xfers.
+ * Afterall, the ISOCH xfers could fail legitimately.
+ */
+ if (status)
+ pr_debug("%s: iso_complete status(%d) %d/%d\n",
+ __func__, status, req->actual, req->length);
+
+ u_audio_set_fback_frequency(audio_dev->gadget->speed,
+ params->c_srate, prm->pitch,
+ req->buf);
+
+ if (usb_ep_queue(ep, req, GFP_ATOMIC))
+ dev_err(uac->card->dev, "%d Error!\n", __LINE__);
+}
+
static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
@@ -335,14 +411,33 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep)
dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
}
+static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep)
+{
+ struct snd_uac_chip *uac = prm->uac;
+
+ if (!prm->fb_ep_enabled)
+ return;
+
+ prm->fb_ep_enabled = false;
+
+ if (prm->req_fback) {
+ usb_ep_dequeue(ep, prm->req_fback);
+ kfree(prm->req_fback->buf);
+ usb_ep_free_request(ep, prm->req_fback);
+ prm->req_fback = NULL;
+ }
+
+ if (usb_ep_disable(ep))
+ dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
+}
int u_audio_start_capture(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct usb_gadget *gadget = audio_dev->gadget;
struct device *dev = &gadget->dev;
- struct usb_request *req;
- struct usb_ep *ep;
+ struct usb_request *req, *req_fback;
+ struct usb_ep *ep, *ep_fback;
struct uac_rtd_params *prm;
struct uac_params *params = &audio_dev->params;
int req_len, i;
@@ -374,6 +469,43 @@ int u_audio_start_capture(struct g_audio *audio_dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
}
+ ep_fback = audio_dev->in_ep_fback;
+ if (!ep_fback)
+ return 0;
+
+ /* Setup feedback endpoint */
+ config_ep_by_speed(gadget, &audio_dev->func, ep_fback);
+ prm->fb_ep_enabled = true;
+ usb_ep_enable(ep_fback);
+ req_len = ep_fback->maxpacket;
+
+ req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC);
+ if (req_fback == NULL)
+ return -ENOMEM;
+
+ prm->req_fback = req_fback;
+ req_fback->zero = 0;
+ req_fback->context = prm;
+ req_fback->length = req_len;
+ req_fback->complete = u_audio_iso_fback_complete;
+
+ req_fback->buf = kzalloc(req_len, GFP_ATOMIC);
+ if (!req_fback->buf)
+ return -ENOMEM;
+
+ /*
+ * Configure the feedback endpoint's reported frequency.
+ * Always start with original frequency since its deviation can't
+ * be meauserd at start of playback
+ */
+ prm->pitch = 1000000;
+ u_audio_set_fback_frequency(audio_dev->gadget->speed,
+ params->c_srate, prm->pitch,
+ req_fback->buf);
+
+ if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC))
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_start_capture);
@@ -382,6 +514,8 @@ void u_audio_stop_capture(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
+ if (audio_dev->in_ep_fback)
+ free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
free_ep(&uac->c_prm, audio_dev->out_ep);
}
EXPORT_SYMBOL_GPL(u_audio_stop_capture);
@@ -463,12 +597,82 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
}
EXPORT_SYMBOL_GPL(u_audio_stop_playback);
+static int u_audio_pitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ unsigned int pitch_min, pitch_max;
+
+ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
+ pitch_max = (1000 + params->fb_max) * 1000;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = pitch_min;
+ uinfo->value.integer.max = pitch_max;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int u_audio_pitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = prm->pitch;
+
+ return 0;
+}
+
+static int u_audio_pitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ unsigned int val;
+ unsigned int pitch_min, pitch_max;
+ int change = 0;
+
+ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
+ pitch_max = (1000 + params->fb_max) * 1000;
+
+ val = ucontrol->value.integer.value[0];
+
+ if (val < pitch_min)
+ val = pitch_min;
+ if (val > pitch_max)
+ val = pitch_max;
+
+ if (prm->pitch != val) {
+ prm->pitch = val;
+ change = 1;
+ }
+
+ return change;
+}
+
+static const struct snd_kcontrol_new u_audio_controls[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "Capture Pitch 1000000",
+ .info = u_audio_pitch_info,
+ .get = u_audio_pitch_get,
+ .put = u_audio_pitch_put,
+},
+};
+
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
const char *card_name)
{
struct snd_uac_chip *uac;
struct snd_card *card;
struct snd_pcm *pcm;
+ struct snd_kcontrol *kctl;
struct uac_params *params;
int p_chmask, c_chmask;
int err;
@@ -556,6 +760,23 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
+ if (c_chmask && g_audio->in_ep_fback) {
+ strscpy(card->mixername, card_name, sizeof(card->driver));
+
+ kctl = snd_ctl_new1(&u_audio_controls[0], &uac->c_prm);
+ if (!kctl) {
+ err = -ENOMEM;
+ goto snd_fail;
+ }
+
+ kctl->id.device = pcm->device;
+ kctl->id.subdevice = 0;
+
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ goto snd_fail;
+ }
+
strscpy(card->driver, card_name, sizeof(card->driver));
strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h
index 5ea6b86f1fda..a218cdf771fe 100644
--- a/drivers/usb/gadget/function/u_audio.h
+++ b/drivers/usb/gadget/function/u_audio.h
@@ -11,6 +11,14 @@
#include <linux/usb/composite.h>
+/*
+ * Same maximum frequency deviation on the slower side as in
+ * sound/usb/endpoint.c. Value is expressed in per-mil deviation.
+ * The maximum deviation on the faster side will be provided as
+ * parameter, as it impacts the endpoint required bandwidth.
+ */
+#define FBACK_SLOW_MAX 250
+
struct uac_params {
/* playback */
int p_chmask; /* channel mask */
@@ -23,6 +31,7 @@ struct uac_params {
int c_ssize; /* sample size */
int req_number; /* number of preallocated requests */
+ int fb_max; /* upper frequency drift feedback limit per-mil */
};
struct g_audio {
@@ -30,7 +39,10 @@ struct g_audio {
struct usb_gadget *gadget;
struct usb_ep *in_ep;
+
struct usb_ep *out_ep;
+ /* feedback IN endpoint corresponding to out_ep */
+ struct usb_ep *in_ep_fback;
/* Max packet size for all in_ep possible speeds */
unsigned int in_ep_maxpsize;
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
index 84e6da302499..98d6af558c03 100644
--- a/drivers/usb/gadget/function/u_hid.h
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -29,8 +29,8 @@ struct f_hid_opts {
* Protect the data form concurrent access by read/write
* and create symlink/remove symlink.
*/
- struct mutex lock;
- int refcnt;
+ struct mutex lock;
+ int refcnt;
};
int ghid_setup(struct usb_gadget *g, int count);
diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h
index f6e14af7f566..2e400b495cb8 100644
--- a/drivers/usb/gadget/function/u_midi.h
+++ b/drivers/usb/gadget/function/u_midi.h
@@ -29,8 +29,8 @@ struct f_midi_opts {
* Protect the data form concurrent access by read/write
* and create symlink/remove symlink.
*/
- struct mutex lock;
- int refcnt;
+ struct mutex lock;
+ int refcnt;
};
#endif /* U_MIDI_H */
diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h
index b5035711172d..179d3ef6a195 100644
--- a/drivers/usb/gadget/function/u_uac2.h
+++ b/drivers/usb/gadget/function/u_uac2.h
@@ -21,7 +21,9 @@
#define UAC2_DEF_CCHMASK 0x3
#define UAC2_DEF_CSRATE 64000
#define UAC2_DEF_CSSIZE 2
+#define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC
#define UAC2_DEF_REQ_NUM 2
+#define UAC2_DEF_FB_MAX 5
struct f_uac2_opts {
struct usb_function_instance func_inst;
@@ -31,7 +33,9 @@ struct f_uac2_opts {
int c_chmask;
int c_srate;
int c_ssize;
+ int c_sync;
int req_number;
+ int fb_max;
bool bound;
struct mutex lock;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index cd28dec837dd..77d64031aa9c 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -914,8 +914,6 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
- if (!target_fmt)
- goto out;
uvcg_format_set_indices(to_config_group(target));
@@ -955,8 +953,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
mutex_lock(&opts->lock);
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
- if (!target_fmt)
- goto out;
list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
if (format_ptr->fmt == target_fmt) {
@@ -968,7 +964,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
--target_fmt->linked;
-out:
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
}
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index c4eda7fe7ab4..5b27d289443f 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -171,8 +171,10 @@ static int hid_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(gadget);
- if (!usb_desc)
+ if (!usb_desc) {
+ status = -ENOMEM;
goto put;
+ }
usb_otg_descriptor_init(gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index 9cd4a70ccdd6..a9f07c59fc37 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -288,7 +288,6 @@ struct bcm63xx_req {
* @ep0_req_completed: ep0 request has completed; worker has not seen it yet.
* @ep0_reply: Pending reply from gadget driver.
* @ep0_request: Outstanding ep0 request.
- * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>.
*/
struct bcm63xx_udc {
spinlock_t lock;
@@ -327,8 +326,6 @@ struct bcm63xx_udc {
unsigned ep0_req_completed:1;
struct usb_request *ep0_reply;
struct usb_request *ep0_request;
-
- struct dentry *debugfs_root;
};
static const struct usb_ep_ops bcm63xx_udc_ep_ops;
@@ -2250,8 +2247,6 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
return;
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
- udc->debugfs_root = root;
-
debugfs_create_file("usbd", 0400, root, udc, &bcm63xx_usbd_dbg_fops);
debugfs_create_file("iudma", 0400, root, udc, &bcm63xx_iudma_dbg_fops);
}
@@ -2264,7 +2259,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
*/
static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
{
- debugfs_remove_recursive(udc->debugfs_root);
+ debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
}
/***********************************************************************
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 493ff93f7dda..b7f0b1ebaaa8 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1148,6 +1148,53 @@ static inline void usb_gadget_udc_set_speed(struct usb_udc *udc,
}
/**
+ * usb_gadget_enable_async_callbacks - tell usb device controller to enable asynchronous callbacks
+ * @udc: The UDC which should enable async callbacks
+ *
+ * This routine is used when binding gadget drivers. It undoes the effect
+ * of usb_gadget_disable_async_callbacks(); the UDC driver should enable IRQs
+ * (if necessary) and resume issuing callbacks.
+ *
+ * This routine will always be called in process context.
+ */
+static inline void usb_gadget_enable_async_callbacks(struct usb_udc *udc)
+{
+ struct usb_gadget *gadget = udc->gadget;
+
+ if (gadget->ops->udc_async_callbacks)
+ gadget->ops->udc_async_callbacks(gadget, true);
+}
+
+/**
+ * usb_gadget_disable_async_callbacks - tell usb device controller to disable asynchronous callbacks
+ * @udc: The UDC which should disable async callbacks
+ *
+ * This routine is used when unbinding gadget drivers. It prevents a race:
+ * The UDC driver doesn't know when the gadget driver's ->unbind callback
+ * runs, so unless it is told to disable asynchronous callbacks, it might
+ * issue a callback (such as ->disconnect) after the unbind has completed.
+ *
+ * After this function runs, the UDC driver must suppress all ->suspend,
+ * ->resume, ->disconnect, ->reset, and ->setup callbacks to the gadget driver
+ * until async callbacks are again enabled. A simple-minded but effective
+ * way to accomplish this is to tell the UDC hardware not to generate any
+ * more IRQs.
+ *
+ * Request completion callbacks must still be issued. However, it's okay
+ * to defer them until the request is cancelled, since the pull-up will be
+ * turned off during the time period when async callbacks are disabled.
+ *
+ * This routine will always be called in process context.
+ */
+static inline void usb_gadget_disable_async_callbacks(struct usb_udc *udc)
+{
+ struct usb_gadget *gadget = udc->gadget;
+
+ if (gadget->ops->udc_async_callbacks)
+ gadget->ops->udc_async_callbacks(gadget, false);
+}
+
+/**
* usb_udc_release - release the usb_udc struct
* @dev: the dev member within usb_udc
*
@@ -1361,6 +1408,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
usb_gadget_disconnect(udc->gadget);
+ usb_gadget_disable_async_callbacks(udc);
if (udc->gadget->irq)
synchronize_irq(udc->gadget->irq);
udc->driver->unbind(udc->gadget);
@@ -1442,6 +1490,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
driver->unbind(udc->gadget);
goto err1;
}
+ usb_gadget_enable_async_callbacks(udc);
usb_udc_connect_control(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 7db773c87379..a2d956af42a2 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -934,6 +934,15 @@ static void dummy_udc_set_speed(struct usb_gadget *_gadget,
dummy_udc_update_ep0(dum);
}
+static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct dummy *dum = gadget_dev_to_dummy(&_gadget->dev);
+
+ spin_lock_irq(&dum->lock);
+ dum->ints_enabled = enable;
+ spin_unlock_irq(&dum->lock);
+}
+
static int dummy_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
static int dummy_udc_stop(struct usb_gadget *g);
@@ -946,6 +955,7 @@ static const struct usb_gadget_ops dummy_ops = {
.udc_start = dummy_udc_start,
.udc_stop = dummy_udc_stop,
.udc_set_speed = dummy_udc_set_speed,
+ .udc_async_callbacks = dummy_udc_async_callbacks,
};
/*-------------------------------------------------------------------------*/
@@ -1005,7 +1015,6 @@ static int dummy_udc_start(struct usb_gadget *g,
spin_lock_irq(&dum->lock);
dum->devstatus = 0;
dum->driver = driver;
- dum->ints_enabled = 1;
spin_unlock_irq(&dum->lock);
return 0;
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index fa66449b3907..8e8588933628 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -541,6 +541,7 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if ((max == 128) || (max == 256) || (max == 512))
break;
+ fallthrough;
default:
switch (max) {
case 4:
@@ -562,9 +563,11 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if (max <= 1024)
break;
+ fallthrough;
case USB_SPEED_FULL:
if (max <= 64)
break;
+ fallthrough;
default:
if (max <= 8)
break;
@@ -579,6 +582,7 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if (max <= 1024)
break;
+ fallthrough;
case USB_SPEED_FULL:
if (max <= 1023)
break;
@@ -605,6 +609,7 @@ static int qe_ep_init(struct qe_udc *udc,
default:
goto en_done;
}
+ fallthrough;
case USB_SPEED_LOW:
switch (max) {
case 1:
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index ad6ff9c4188e..29fcb9b461d7 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -36,7 +36,6 @@
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
-#include <linux/delay.h>
#include <linux/of_device.h>
#include <asm/byteorder.h>
@@ -323,13 +322,11 @@ static int dr_controller_setup(struct fsl_udc *udc)
fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
}
/* Config control enable i/o output, cpu endian register */
-#ifndef CONFIG_ARCH_MXC
if (udc->pdata->have_sysif_regs) {
ctrl = __raw_readl(&usb_sys_regs->control);
ctrl |= USB_CTRL_IOENB;
__raw_writel(ctrl, &usb_sys_regs->control);
}
-#endif
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
/* Turn on cache snooping hardware, since some PowerPC platforms
@@ -547,7 +544,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
unsigned short max = 0;
unsigned char mult = 0, zlt;
int retval = -EINVAL;
- unsigned long flags = 0;
+ unsigned long flags;
ep = container_of(_ep, struct fsl_ep, ep);
@@ -631,7 +628,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
{
struct fsl_udc *udc = NULL;
struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
+ unsigned long flags;
u32 epctrl;
int ep_num;
@@ -1001,7 +998,7 @@ out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
{
struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
+ unsigned long flags;
int status = -EOPNOTSUPP; /* operation not supported */
unsigned char ep_dir = 0, ep_num = 0;
struct fsl_udc *udc = NULL;
@@ -1938,7 +1935,7 @@ static int fsl_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
int retval = 0;
- unsigned long flags = 0;
+ unsigned long flags;
/* lock is needed but whether should use this lock or another */
spin_lock_irqsave(&udc_controller->lock, flags);
@@ -2153,7 +2150,6 @@ static int fsl_proc_read(struct seq_file *m, void *v)
tmp_reg = fsl_readl(&dr_regs->endpointprime);
seq_printf(m, "EP Prime Reg = [0x%x]\n\n", tmp_reg);
-#ifndef CONFIG_ARCH_MXC
if (udc->pdata->have_sysif_regs) {
tmp_reg = usb_sys_regs->snoop1;
seq_printf(m, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
@@ -2161,7 +2157,6 @@ static int fsl_proc_read(struct seq_file *m, void *v)
tmp_reg = usb_sys_regs->control;
seq_printf(m, "General Control Reg : = [0x%x]\n\n", tmp_reg);
}
-#endif
/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
ep = &udc->eps[0];
@@ -2412,28 +2407,21 @@ static int fsl_udc_probe(struct platform_device *pdev)
*/
if (pdata->init && pdata->init(pdev)) {
ret = -ENODEV;
- goto err_iounmap_noclk;
+ goto err_iounmap;
}
/* Set accessors only after pdata->init() ! */
fsl_set_accessors(pdata);
-#ifndef CONFIG_ARCH_MXC
if (pdata->have_sysif_regs)
usb_sys_regs = (void *)dr_regs + USB_DR_SYS_OFFSET;
-#endif
-
- /* Initialize USB clocks */
- ret = fsl_udc_clk_init(pdev);
- if (ret < 0)
- goto err_iounmap_noclk;
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl(&dr_regs->dccparams);
if (!(dccparams & DCCPARAMS_DC)) {
ERR("This SOC doesn't support device role\n");
ret = -ENODEV;
- goto err_iounmap;
+ goto err_exit;
}
/* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */
@@ -2442,7 +2430,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
ret = ret ? : -ENODEV;
- goto err_iounmap;
+ goto err_exit;
}
udc_controller->irq = ret;
@@ -2451,7 +2439,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
if (ret != 0) {
ERR("cannot request irq %d err %d\n",
udc_controller->irq, ret);
- goto err_iounmap;
+ goto err_exit;
}
/* Initialize the udc structure including QH member and other member */
@@ -2467,10 +2455,6 @@ static int fsl_udc_probe(struct platform_device *pdev)
dr_controller_setup(udc_controller);
}
- ret = fsl_udc_clk_finalize(pdev);
- if (ret)
- goto err_free_irq;
-
/* Setup gadget structure */
udc_controller->gadget.ops = &fsl_gadget_ops;
udc_controller->gadget.max_speed = USB_SPEED_HIGH;
@@ -2530,11 +2514,10 @@ err_del_udc:
dma_pool_destroy(udc_controller->td_pool);
err_free_irq:
free_irq(udc_controller->irq, udc_controller);
-err_iounmap:
+err_exit:
if (pdata->exit)
pdata->exit(pdev);
- fsl_udc_clk_release();
-err_iounmap_noclk:
+err_iounmap:
iounmap(dr_regs);
err_release_mem_region:
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
@@ -2561,8 +2544,6 @@ static int fsl_udc_remove(struct platform_device *pdev)
udc_controller->done = &done;
usb_del_gadget_udc(&udc_controller->gadget);
- fsl_udc_clk_release();
-
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();
@@ -2677,10 +2658,6 @@ static int fsl_udc_otg_resume(struct device *dev)
--------------------------------------------------------------------------*/
static const struct platform_device_id fsl_udc_devtype[] = {
{
- .name = "imx-udc-mx27",
- }, {
- .name = "imx-udc-mx51",
- }, {
.name = "fsl-usb2-udc",
}, {
/* sentinel */
@@ -2689,7 +2666,6 @@ static const struct platform_device_id fsl_udc_devtype[] = {
MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
static struct platform_driver udc_driver = {
.remove = fsl_udc_remove,
- /* Just for FSL i.mx SoC currently */
.id_table = fsl_udc_devtype,
/* these suspend and resume are not usb suspend and resume */
.suspend = fsl_udc_suspend,
diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h
index 4ba651ae9048..2efc5a930b48 100644
--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h
@@ -588,23 +588,4 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
USB_DIR_IN) ? 1 : 0];
}
-struct platform_device;
-#ifdef CONFIG_ARCH_MXC
-int fsl_udc_clk_init(struct platform_device *pdev);
-int fsl_udc_clk_finalize(struct platform_device *pdev);
-void fsl_udc_clk_release(void);
-#else
-static inline int fsl_udc_clk_init(struct platform_device *pdev)
-{
- return 0;
-}
-static inline int fsl_udc_clk_finalize(struct platform_device *pdev)
-{
- return 0;
-}
-static inline void fsl_udc_clk_release(void)
-{
-}
-#endif
-
#endif
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index f8f3aa52383b..4b35739d3695 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -207,14 +207,15 @@ DEFINE_SHOW_ATTRIBUTE(gr_dfs);
static void gr_dfs_create(struct gr_udc *dev)
{
const char *name = "gr_udc_state";
+ struct dentry *root;
- dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), usb_debug_root);
- debugfs_create_file(name, 0444, dev->dfs_root, dev, &gr_dfs_fops);
+ root = debugfs_create_dir(dev_name(dev->dev), usb_debug_root);
+ debugfs_create_file(name, 0444, root, dev, &gr_dfs_fops);
}
static void gr_dfs_delete(struct gr_udc *dev)
{
- debugfs_remove_recursive(dev->dfs_root);
+ debugfs_remove(debugfs_lookup(dev_name(dev->dev), usb_debug_root));
}
#else /* !CONFIG_USB_GADGET_DEBUG_FS */
diff --git a/drivers/usb/gadget/udc/gr_udc.h b/drivers/usb/gadget/udc/gr_udc.h
index ac5b3f65adb5..70134239179e 100644
--- a/drivers/usb/gadget/udc/gr_udc.h
+++ b/drivers/usb/gadget/udc/gr_udc.h
@@ -215,8 +215,6 @@ struct gr_udc {
struct list_head ep_list;
spinlock_t lock; /* General lock, a.k.a. "dev->lock" in comments */
-
- struct dentry *dfs_root;
};
#define to_gr_udc(gadget) (container_of((gadget), struct gr_udc, gadget))
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 3f1c62adce4b..a25d01c89564 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -127,7 +127,6 @@ struct lpc32xx_udc {
struct usb_gadget_driver *driver;
struct platform_device *pdev;
struct device *dev;
- struct dentry *pde;
spinlock_t lock;
struct i2c_client *isp1301_i2c_client;
@@ -528,12 +527,12 @@ DEFINE_SHOW_ATTRIBUTE(udc);
static void create_debug_file(struct lpc32xx_udc *udc)
{
- udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops);
+ debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops);
}
static void remove_debug_file(struct lpc32xx_udc *udc)
{
- debugfs_remove(udc->pde);
+ debugfs_remove(debugfs_lookup(debug_filename, NULL));
}
#else
diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c
index 5486f5a70868..ce3d7a3eb7e3 100644
--- a/drivers/usb/gadget/udc/mv_u3d_core.c
+++ b/drivers/usb/gadget/udc/mv_u3d_core.c
@@ -941,7 +941,7 @@ mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall)
static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
{
struct mv_u3d_ep *ep;
- unsigned long flags = 0;
+ unsigned long flags;
int status = 0;
struct mv_u3d *u3d;
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 0fb4ef464321..7f24ce400b59 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -888,7 +888,7 @@ static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
{
struct mv_ep *ep;
- unsigned long flags = 0;
+ unsigned long flags;
int status = 0;
struct mv_udc *udc;
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 89f479b78d80..7c38057dcb4a 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1150,6 +1150,7 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
static int net2272_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
static int net2272_stop(struct usb_gadget *_gadget);
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable);
static const struct usb_gadget_ops net2272_ops = {
.get_frame = net2272_get_frame,
@@ -1158,6 +1159,7 @@ static const struct usb_gadget_ops net2272_ops = {
.pullup = net2272_pullup,
.udc_start = net2272_start,
.udc_stop = net2272_stop,
+ .udc_async_callbacks = net2272_async_callbacks,
};
/*---------------------------------------------------------------------------*/
@@ -1476,7 +1478,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
net2272_dequeue_all(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */
- if (driver) {
+ if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
@@ -1501,6 +1503,15 @@ static int net2272_stop(struct usb_gadget *_gadget)
return 0;
}
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct net2272 *dev = container_of(_gadget, struct net2272, gadget);
+
+ spin_lock_irq(&dev->lock);
+ dev->async_callbacks = enable;
+ spin_unlock_irq(&dev->lock);
+}
+
/*---------------------------------------------------------------------------*/
/* handle ep-a/ep-b dma completions */
static void
@@ -1910,9 +1921,11 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
u.r.bRequestType, u.r.bRequest,
u.r.wValue, u.r.wIndex,
net2272_ep_read(ep, EP_CFG));
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &u.r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &u.r);
+ spin_lock(&dev->lock);
+ }
}
/* stall ep0 on error */
@@ -1994,14 +2007,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
if (disconnect || reset) {
stop_activity(dev, dev->driver);
net2272_ep0_start(dev);
- spin_unlock(&dev->lock);
- if (reset)
- usb_gadget_udc_reset
- (&dev->gadget, dev->driver);
- else
- (dev->driver->disconnect)
- (&dev->gadget);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
return;
}
}
@@ -2015,14 +2028,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
if (stat & tmp) {
net2272_write(dev, IRQSTAT1, tmp);
if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
- if (dev->driver->suspend)
+ if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
if (!enable_suspend) {
stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
dev_dbg(dev->dev, "Suspend disabled, ignoring\n");
}
} else {
- if (dev->driver->resume)
+ if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget);
}
stat &= ~tmp;
diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h
index c669308111c2..a9994f737588 100644
--- a/drivers/usb/gadget/udc/net2272.h
+++ b/drivers/usb/gadget/udc/net2272.h
@@ -442,6 +442,7 @@ struct net2272 {
softconnect:1,
wakeup:1,
added:1,
+ async_callbacks:1,
dma_eot_polarity:1,
dma_dack_polarity:1,
dma_dreq_polarity:1,
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index fc9f99fe7f37..16e7d2db6411 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
static int net2280_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
static int net2280_stop(struct usb_gadget *_gadget);
+static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable);
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
@@ -1625,6 +1626,7 @@ static const struct usb_gadget_ops net2280_ops = {
.pullup = net2280_pullup,
.udc_start = net2280_start,
.udc_stop = net2280_stop,
+ .udc_async_callbacks = net2280_async_callbacks,
.match_ep = net2280_match_ep,
};
@@ -2472,7 +2474,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
nuke(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */
- if (driver) {
+ if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
@@ -2502,6 +2504,15 @@ static int net2280_stop(struct usb_gadget *_gadget)
return 0;
}
+static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct net2280 *dev = container_of(_gadget, struct net2280, gadget);
+
+ spin_lock_irq(&dev->lock);
+ dev->async_callbacks = enable;
+ spin_unlock_irq(&dev->lock);
+}
+
/*-------------------------------------------------------------------------*/
/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq.
@@ -2814,8 +2825,6 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
* - Wait and try again.
*/
udelay(DEFECT_7374_PROCESSOR_WAIT_TIME);
-
- continue;
}
@@ -3042,9 +3051,11 @@ usb3_delegate:
readl(&ep->cfg->ep_cfg));
ep->responded = 0;
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &r);
+ spin_lock(&dev->lock);
+ }
}
do_stall3:
if (tmp < 0) {
@@ -3284,9 +3295,11 @@ delegate:
w_value, w_index, w_length,
readl(&ep->cfg->ep_cfg));
ep->responded = 0;
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &u.r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &u.r);
+ spin_lock(&dev->lock);
+ }
}
/* stall ep0 on error */
@@ -3391,14 +3404,14 @@ __acquires(dev->lock)
if (disconnect || reset) {
stop_activity(dev, dev->driver);
ep0_start(dev);
- spin_unlock(&dev->lock);
- if (reset)
- usb_gadget_udc_reset
- (&dev->gadget, dev->driver);
- else
- (dev->driver->disconnect)
- (&dev->gadget);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
return;
}
}
@@ -3419,12 +3432,12 @@ __acquires(dev->lock)
writel(tmp, &dev->regs->irqstat1);
spin_unlock(&dev->lock);
if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) {
- if (dev->driver->suspend)
+ if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
if (!enable_suspend)
stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT);
} else {
- if (dev->driver->resume)
+ if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget);
/* at high speed, note erratum 0133 */
}
diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h
index 7da3dc1e9729..34716a9f4926 100644
--- a/drivers/usb/gadget/udc/net2280.h
+++ b/drivers/usb/gadget/udc/net2280.h
@@ -162,6 +162,7 @@ struct net2280 {
ltm_enable:1,
wakeup_enable:1,
addressed_state:1,
+ async_callbacks:1,
bug7734_patched:1;
u16 chiprev;
int enhanced_mode;
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 10324a7334fe..69ef1e669d0c 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1338,10 +1338,10 @@ DEFINE_SHOW_ATTRIBUTE(udc_debug);
#define create_debug_files(dev) \
do { \
- dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
+ debugfs_create_file(dev->gadget.name, \
S_IRUGO, NULL, dev, &udc_debug_fops); \
} while (0)
-#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc)
+#define remove_debug_files(dev) debugfs_remove(debugfs_lookup(dev->gadget.name, NULL))
#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h
index ccc6b921f067..aa4b68fd9fc0 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.h
+++ b/drivers/usb/gadget/udc/pxa25x_udc.h
@@ -116,10 +116,6 @@ struct pxa25x_udc {
struct usb_phy *transceiver;
u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- struct dentry *debugfs_udc;
-#endif
void __iomem *regs;
};
#define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget))
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index ce57961dfd2d..f4b7a2a3e711 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -208,8 +208,6 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
struct dentry *root;
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
- udc->debugfs_root = root;
-
debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops);
debugfs_create_file("queues", 0400, root, udc, &queues_dbg_fops);
debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops);
@@ -217,7 +215,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
static void pxa_cleanup_debugfs(struct pxa_udc *udc)
{
- debugfs_remove_recursive(udc->debugfs_root);
+ debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
}
#else
@@ -1730,7 +1728,7 @@ static void udc_enable(struct pxa_udc *udc)
}
/**
- * pxa27x_start - Register gadget driver
+ * pxa27x_udc_start - Register gadget driver
* @g: gadget
* @driver: gadget driver
*
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h
index 13b2977399ab..0a6bc18a1264 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.h
+++ b/drivers/usb/gadget/udc/pxa27x_udc.h
@@ -440,7 +440,6 @@ struct udc_stats {
* @last_interface: UDC interface of the last SET_INTERFACE host request
* @last_alternate: UDC altsetting of the last SET_INTERFACE host request
* @udccsr0: save of udccsr0 in case of suspend
- * @debugfs_root: root entry of debug filesystem
* @debugfs_state: debugfs entry for "udcstate"
* @debugfs_queues: debugfs entry for "queues"
* @debugfs_eps: debugfs entry for "epstate"
@@ -474,9 +473,6 @@ struct pxa_udc {
#ifdef CONFIG_PM
unsigned udccsr0;
#endif
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- struct dentry *debugfs_root;
-#endif
};
#define to_pxa(g) (container_of((g), struct pxa_udc, gadget))
diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c
index 7bd5182ce3ef..89f1f8c9f02e 100644
--- a/drivers/usb/gadget/udc/s3c-hsudc.c
+++ b/drivers/usb/gadget/udc/s3c-hsudc.c
@@ -1220,9 +1220,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
int ret, i;
- hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
- sizeof(struct s3c_hsudc_ep) * pd->epnum,
- GFP_KERNEL);
+ hsudc = devm_kzalloc(&pdev->dev, struct_size(hsudc, ep, pd->epnum),
+ GFP_KERNEL);
if (!hsudc)
return -ENOMEM;
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index b154b62abefa..179777cb699f 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -198,7 +198,7 @@ static inline void s3c2410_udc_set_ep0_de(void __iomem *base)
udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG);
}
-inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
+static inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
{
udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG);
@@ -1843,9 +1843,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
if (retval)
goto err_add_udc;
- udc->regs_info = debugfs_create_file("registers", S_IRUGO,
- s3c2410_udc_debugfs_root, udc,
- &s3c2410_udc_debugfs_fops);
+ debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, udc,
+ &s3c2410_udc_debugfs_fops);
dev_dbg(dev, "probe ok\n");
@@ -1889,7 +1888,7 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&udc->gadget);
- debugfs_remove(udc->regs_info);
+ debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root));
if (udc_info && !udc_info->udc_command &&
gpio_is_valid(udc_info->pullup_pin))
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h
index 68bdf3e5aac2..135a5bff3c74 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.h
+++ b/drivers/usb/gadget/udc/s3c2410_udc.h
@@ -89,7 +89,6 @@ struct s3c2410_udc {
unsigned req_config : 1;
unsigned req_pending : 1;
u8 vbus;
- struct dentry *regs_info;
int irq;
};
#define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget))
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 2319c9737c2b..a54d1cef17db 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -1907,7 +1907,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 +1928,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,
@@ -2168,7 +2168,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,
@@ -3508,10 +3508,8 @@ 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 usb2-%d PHY\n", i);
goto clean_up;
} else if (xudc->utmi_phy[i]) {
/* Get usb-phy, if utmi phy is available */
@@ -3520,8 +3518,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
&xudc->vbus_nb);
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]) {
@@ -3538,10 +3536,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
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);
-
+ dev_err_probe(xudc->dev, err,
+ "failed to get usb3-%d PHY\n", usb3);
goto clean_up;
} else if (xudc->usb3_phy[i])
dev_dbg(xudc->dev, "usb3-%d PHY registered", usb3);
@@ -3781,9 +3777,7 @@ static int tegra_xudc_probe(struct platform_device *pdev)
err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, xudc->clks);
if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to request clocks: %d\n", err);
-
+ dev_err_probe(xudc->dev, err, "failed to request clocks\n");
return err;
}
@@ -3798,9 +3792,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) {
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to request regulators: %d\n", err);
-
+ dev_err_probe(xudc->dev, err, "failed to request regulators\n");
return err;
}
diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c
index 7430624c0bd7..19e837de2a20 100644
--- a/drivers/usb/gadget/udc/trace.c
+++ b/drivers/usb/gadget/udc/trace.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* trace.c - USB Gadget Framework Trace Support
*
* Copyright (C) 2016 Intel Corporation
diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h
index 2d1f68b5ea76..98584f6b6c66 100644
--- a/drivers/usb/gadget/udc/trace.h
+++ b/drivers/usb/gadget/udc/trace.h
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* udc.c - Core UDC Framework
*
* Copyright (C) 2016 Intel Corporation
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 72f2ea062d55..fb4ffedd6f0d 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -791,7 +791,7 @@ static int xudc_ep_set_halt(struct usb_ep *_ep, int value)
}
/**
- * xudc_ep_enable - Enables the given endpoint.
+ * __xudc_ep_enable - Enables the given endpoint.
* @ep: pointer to the xusb endpoint structure.
* @desc: pointer to usb endpoint descriptor.
*
@@ -987,7 +987,7 @@ static void xudc_free_request(struct usb_ep *_ep, struct usb_request *_req)
}
/**
- * xudc_ep0_queue - Adds the request to endpoint 0 queue.
+ * __xudc_ep0_queue - Adds the request to endpoint 0 queue.
* @ep0: pointer to the xusb endpoint 0 structure.
* @req: pointer to the xusb request structure.
*
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 6f7bd6641694..385be30baad3 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -387,11 +387,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
-#ifdef CONFIG_PPC_83xx
+#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_85xx)
/*
- * Deal with MPC834X that need port power to be cycled after the power
- * fault condition is removed. Otherwise the state machine does not
- * reflect PORTSC[CSC] correctly.
+ * Deal with MPC834X/85XX that need port power to be cycled
+ * after the power fault condition is removed. Otherwise the
+ * state machine does not reflect PORTSC[CSC] correctly.
*/
ehci->need_oc_pp_cycle = 1;
#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 94b5e64ae9a2..36f5bf6a0752 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -76,12 +76,12 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */
/* Initial IRQ latency: faster than hw default */
-static int log2_irq_thresh = 0; // 0 to 6
+static int log2_irq_thresh; // 0 to 6
module_param (log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
/* initial park setting: slower than hw default */
-static unsigned park = 0;
+static unsigned park;
module_param (park, uint, S_IRUGO);
MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
@@ -1238,6 +1238,10 @@ static const struct hc_driver ehci_hc_driver = {
* device support
*/
.free_dev = ehci_remove_device,
+#ifdef CONFIG_USB_HCD_TEST_MODE
+ /* EH SINGLE_STEP_SET_FEATURE test support */
+ .submit_single_step_set_feature = ehci_submit_single_step_set_feature,
+#endif
};
void ehci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 159cc27b1a36..c4f6a2559a98 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -727,145 +727,6 @@ ehci_hub_descriptor (
}
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_HCD_TEST_MODE
-
-#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
-
-static void usb_ehset_completion(struct urb *urb)
-{
- struct completion *done = urb->context;
-
- complete(done);
-}
-static int submit_single_step_set_feature(
- struct usb_hcd *hcd,
- struct urb *urb,
- int is_setup
-);
-
-/*
- * Allocate and initialize a control URB. This request will be used by the
- * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
- * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
- * Return NULL if failed.
- */
-static struct urb *request_single_step_set_feature_urb(
- struct usb_device *udev,
- void *dr,
- void *buf,
- struct completion *done
-) {
- struct urb *urb;
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
- struct usb_host_endpoint *ep;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return NULL;
-
- urb->pipe = usb_rcvctrlpipe(udev, 0);
- ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep) {
- usb_free_urb(urb);
- return NULL;
- }
-
- urb->ep = ep;
- urb->dev = udev;
- urb->setup_packet = (void *)dr;
- urb->transfer_buffer = buf;
- urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
- urb->complete = usb_ehset_completion;
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- urb->transfer_flags = URB_DIR_IN;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- urb->setup_dma = dma_map_single(
- hcd->self.sysdev,
- urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- urb->transfer_dma = dma_map_single(
- hcd->self.sysdev,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- DMA_FROM_DEVICE);
- urb->context = done;
- return urb;
-}
-
-static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
-{
- int retval = -ENOMEM;
- struct usb_ctrlrequest *dr;
- struct urb *urb;
- struct usb_device *udev;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct usb_device_descriptor *buf;
- DECLARE_COMPLETION_ONSTACK(done);
-
- /* Obtain udev of the rhub's child port */
- udev = usb_hub_find_child(hcd->self.root_hub, port);
- if (!udev) {
- ehci_err(ehci, "No device attached to the RootHub\n");
- return -ENODEV;
- }
- buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!dr) {
- kfree(buf);
- return -ENOMEM;
- }
-
- /* Fill Setup packet for GetDescriptor */
- dr->bRequestType = USB_DIR_IN;
- dr->bRequest = USB_REQ_GET_DESCRIPTOR;
- dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
- dr->wIndex = 0;
- dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
- urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
- if (!urb)
- goto cleanup;
-
- /* Submit just the SETUP stage */
- retval = submit_single_step_set_feature(hcd, urb, 1);
- if (retval)
- goto out1;
- if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
- goto out1;
- }
- msleep(15 * 1000);
-
- /* Complete remaining DATA and STATUS stages using the same URB */
- urb->status = -EINPROGRESS;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- retval = submit_single_step_set_feature(hcd, urb, 0);
- if (!retval && !wait_for_completion_timeout(&done,
- msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
- }
-out1:
- usb_free_urb(urb);
-cleanup:
- kfree(dr);
- kfree(buf);
- return retval;
-}
-#endif /* CONFIG_USB_HCD_TEST_MODE */
-/*-------------------------------------------------------------------------*/
int ehci_hub_control(
struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index a826715ae9bd..2cbf4f85bff3 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1165,7 +1165,7 @@ submit_async (
* performed; TRUE - SETUP and FALSE - IN+STATUS
* Returns 0 if success
*/
-static int submit_single_step_set_feature(
+static int ehci_submit_single_step_set_feature(
struct usb_hcd *hcd,
struct urb *urb,
int is_setup
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 9c2eda0918e1..05fb8d97cf02 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -850,7 +850,6 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210)
struct dentry *root;
root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
- fotg210->debug_dir = root;
debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
debugfs_create_file("periodic", S_IRUGO, root, bus,
@@ -861,7 +860,9 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210)
static inline void remove_debug_files(struct fotg210_hcd *fotg210)
{
- debugfs_remove_recursive(fotg210->debug_dir);
+ struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+
+ debugfs_remove(debugfs_lookup(bus->bus_name, fotg210_debug_root));
}
/* handshake - spin reading hc until handshake completes or fails
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
index 6cee40ec65b4..0a91061a0551 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/host/fotg210.h
@@ -184,9 +184,6 @@ struct fotg210_hcd { /* one per controller */
/* silicon clock */
struct clk *pclk;
-
- /* debug files */
- struct dentry *debug_dir;
};
/* convert between an HCD pointer and the corresponding FOTG210_HCD */
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5a783c423d8e..ae882d76612b 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2392,8 +2392,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
- } else
- continue;
+ }
}
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
"[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
@@ -2448,8 +2447,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
queue_scan];
break;
- } else
- continue;
+ }
}
while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
*urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index f66815fe8482..0e312066c5c6 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1924,6 +1924,7 @@ no_bw:
xhci->hw_ports = NULL;
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
+ xhci->port_caps = NULL;
xhci->page_size = 0;
xhci->page_shift = 0;
@@ -2547,6 +2548,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Wrote ERST address to ir_set 0.");
+ xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
+
/*
* XXX: Might need to set the Interrupter Moderation Register to
* something other than the default (~1ms minimum between interrupts).
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 8b90da5a6ed1..cffcaf4dfa9f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -470,11 +470,12 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
{
- struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
u32 start_ss, last_ss;
u32 start_cs, last_cs;
- int i;
+
+ if (!sch_ep->sch_tt)
+ return 0;
start_ss = offset % 8;
@@ -488,10 +489,6 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
if (!(start_ss == 7 || last_ss < 6))
return -ESCH_SS_Y6;
- for (i = 0; i < sch_ep->cs_count; i++)
- if (test_bit(offset + i, tt->ss_bit_map))
- return -ESCH_SS_OVERLAP;
-
} else {
u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
@@ -518,9 +515,6 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
if (cs_count > 7)
cs_count = 7; /* HW limit */
- if (test_bit(offset, tt->ss_bit_map))
- return -ESCH_SS_OVERLAP;
-
sch_ep->cs_count = cs_count;
/* one for ss, the other for idle */
sch_ep->num_budget_microframes = cs_count + 2;
@@ -541,11 +535,9 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used)
struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 base, num_esit;
int bw_updated;
- int bits;
int i, j;
num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
- bits = (sch_ep->ep_type == ISOC_OUT_EP) ? sch_ep->cs_count : 1;
if (used)
bw_updated = sch_ep->bw_cost_per_microframe;
@@ -555,13 +547,6 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used)
for (i = 0; i < num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit;
- for (j = 0; j < bits; j++) {
- if (used)
- set_bit(base + j, tt->ss_bit_map);
- else
- clear_bit(base + j, tt->ss_bit_map);
- }
-
for (j = 0; j < sch_ep->cs_count; j++)
tt->fs_bus_bw[base + j] += bw_updated;
}
@@ -603,54 +588,47 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep)
static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
struct mu3h_sch_ep_info *sch_ep)
{
+ const u32 esit_boundary = get_esit_boundary(sch_ep);
+ const u32 bw_boundary = get_bw_boundary(sch_ep->speed);
u32 offset;
- u32 min_bw;
- u32 min_index;
u32 worst_bw;
- u32 bw_boundary;
- u32 esit_boundary;
- u32 min_num_budget;
- u32 min_cs_count;
+ u32 min_bw = ~0;
+ int min_index = -1;
int ret = 0;
/*
* Search through all possible schedule microframes.
* and find a microframe where its worst bandwidth is minimum.
*/
- min_bw = ~0;
- min_index = 0;
- min_cs_count = sch_ep->cs_count;
- min_num_budget = sch_ep->num_budget_microframes;
- esit_boundary = get_esit_boundary(sch_ep);
for (offset = 0; offset < sch_ep->esit; offset++) {
- if (sch_ep->sch_tt) {
- ret = check_sch_tt(sch_ep, offset);
- if (ret)
- continue;
- }
+ ret = check_sch_tt(sch_ep, offset);
+ if (ret)
+ continue;
if ((offset + sch_ep->num_budget_microframes) > esit_boundary)
break;
worst_bw = get_max_bw(sch_bw, sch_ep, offset);
+ if (worst_bw > bw_boundary)
+ continue;
+
if (min_bw > worst_bw) {
min_bw = worst_bw;
min_index = offset;
- min_cs_count = sch_ep->cs_count;
- min_num_budget = sch_ep->num_budget_microframes;
}
+
+ /* use first-fit for LS/FS */
+ if (sch_ep->sch_tt && min_index >= 0)
+ break;
+
if (min_bw == 0)
break;
}
- bw_boundary = get_bw_boundary(sch_ep->speed);
- /* check bandwidth */
- if (min_bw > bw_boundary)
+ if (min_index < 0)
return ret ? ret : -ESCH_BW_OVERFLOW;
sch_ep->offset = min_index;
- sch_ep->cs_count = min_cs_count;
- sch_ep->num_budget_microframes = min_num_budget;
return load_ep_bw(sch_bw, sch_ep, true);
}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index b2058b3bc834..2548976bcf05 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -495,8 +495,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
goto put_usb2_hcd;
}
mtk->has_ippc = true;
- } else {
- mtk->has_ippc = false;
}
device_init_wakeup(dev, true);
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index cd3a37bb73e6..ace432356c41 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -24,12 +24,10 @@
#define XHCI_MTK_MAX_ESIT 64
/**
- * @ss_bit_map: used to avoid start split microframes overlay
* @fs_bus_bw: array to keep track of bandwidth already used for FS
* @ep_list: Endpoints using this TT
*/
struct mu3h_sch_tt {
- DECLARE_BITMAP(ss_bit_map, XHCI_MTK_MAX_ESIT);
u32 fs_bus_bw[XHCI_MTK_MAX_ESIT];
struct list_head ep_list;
};
@@ -138,17 +136,17 @@ struct xhci_hcd_mtk {
struct mu3h_sch_bw_info *sch_array;
struct list_head bw_ep_chk_list;
struct mu3c_ippc_regs __iomem *ippc_regs;
- bool has_ippc;
int num_u2_ports;
int num_u3_ports;
int u3p_dis_msk;
struct regulator *vusb33;
struct regulator *vbus;
struct clk_bulk_data clks[BULK_CLKS_NUM];
- bool lpm_support;
- bool u2_lpm_disable;
+ unsigned int has_ippc:1;
+ unsigned int lpm_support:1;
+ unsigned int u2_lpm_disable:1;
/* usb remote wakeup */
- bool uwk_en;
+ unsigned int uwk_en:1;
struct regmap *uwk;
u32 uwk_reg_base;
u32 uwk_vers;
diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c
index f97ac9f52bf4..1da647961c25 100644
--- a/drivers/usb/host/xhci-pci-renesas.c
+++ b/drivers/usb/host/xhci-pci-renesas.c
@@ -197,7 +197,7 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
if (err)
return pcibios_err_to_errno(err);
- if (rom_state & BIT(15)) {
+ if (rom_state & RENESAS_ROM_STATUS_ROM_EXISTS) {
/* ROM exists */
dev_dbg(&pdev->dev, "ROM exists\n");
@@ -207,7 +207,8 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
return 0;
case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */
- return 0;
+ dev_dbg(&pdev->dev, "Unknown ROM status ...\n");
+ break;
case RENESAS_ROM_STATUS_ERROR: /* Error State */
default: /* All other states are marked as "Reserved states" */
@@ -224,13 +225,12 @@ static int renesas_fw_check_running(struct pci_dev *pdev)
u8 fw_state;
int err;
- /* Check if device has ROM and loaded, if so skip everything */
- err = renesas_check_rom(pdev);
- if (err) { /* we have rom */
- err = renesas_check_rom_state(pdev);
- if (!err)
- return err;
- }
+ /*
+ * Only if device has ROM and loaded FW we can skip loading and
+ * return success. Otherwise (even unknown state), attempt to load FW.
+ */
+ if (renesas_check_rom(pdev) && !renesas_check_rom_state(pdev))
+ return 0;
/*
* Test if the device is actually needing the firmware. As most
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 6acd2329e08d..8fea44bbc266 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3076,6 +3076,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (event_loop++ < TRBS_PER_SEGMENT / 2)
continue;
xhci_update_erst_dequeue(xhci, event_ring_deq);
+
+ /* ring is half-full, force isoc trbs to interrupt more often */
+ if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
+ xhci->isoc_bei_interval = xhci->isoc_bei_interval / 2;
+
event_loop = 0;
}
@@ -3956,7 +3961,7 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
* generate an event at least every 8th TD to clear the event ring
*/
if (i && xhci->quirks & XHCI_AVOID_BEI)
- return !!(i % 8);
+ return !!(i % xhci->isoc_bei_interval);
return true;
}
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index c7387677a26a..575fa89a783f 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -2,7 +2,7 @@
/*
* NVIDIA Tegra xHCI host controller driver
*
- * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2014 Google, Inc.
*/
@@ -15,9 +15,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/phy/phy.h>
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
@@ -224,6 +226,7 @@ struct tegra_xusb {
int xhci_irq;
int mbox_irq;
+ int padctl_irq;
void __iomem *ipfs_base;
void __iomem *fpci_base;
@@ -249,8 +252,7 @@ struct tegra_xusb {
struct device *genpd_dev_host;
struct device *genpd_dev_ss;
- struct device_link *genpd_dl_host;
- struct device_link *genpd_dl_ss;
+ bool use_genpd;
struct phy **phys;
unsigned int num_phys;
@@ -270,6 +272,7 @@ struct tegra_xusb {
dma_addr_t phys;
} fw;
+ bool suspended;
struct tegra_xusb_context context;
};
@@ -666,6 +669,9 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
mutex_lock(&tegra->lock);
+ if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
+ goto out;
+
value = fpci_readl(tegra, tegra->soc->mbox.data_out);
tegra_xusb_mbox_unpack(&msg, value);
@@ -679,6 +685,7 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
tegra_xusb_mbox_handle(tegra, &msg);
+out:
mutex_unlock(&tegra->lock);
return IRQ_HANDLED;
}
@@ -819,40 +826,6 @@ static void tegra_xusb_phy_disable(struct tegra_xusb *tegra)
}
}
-static int tegra_xusb_runtime_suspend(struct device *dev)
-{
- struct tegra_xusb *tegra = dev_get_drvdata(dev);
-
- regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
- tegra_xusb_clk_disable(tegra);
-
- return 0;
-}
-
-static int tegra_xusb_runtime_resume(struct device *dev)
-{
- struct tegra_xusb *tegra = dev_get_drvdata(dev);
- int err;
-
- err = tegra_xusb_clk_enable(tegra);
- if (err) {
- dev_err(dev, "failed to enable clocks: %d\n", err);
- return err;
- }
-
- err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
- if (err) {
- dev_err(dev, "failed to enable regulators: %d\n", err);
- goto disable_clk;
- }
-
- return 0;
-
-disable_clk:
- tegra_xusb_clk_disable(tegra);
- return err;
-}
-
#ifdef CONFIG_PM_SLEEP
static int tegra_xusb_init_context(struct tegra_xusb *tegra)
{
@@ -1022,10 +995,9 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
static void tegra_xusb_powerdomain_remove(struct device *dev,
struct tegra_xusb *tegra)
{
- if (tegra->genpd_dl_ss)
- device_link_del(tegra->genpd_dl_ss);
- if (tegra->genpd_dl_host)
- device_link_del(tegra->genpd_dl_host);
+ if (!tegra->use_genpd)
+ return;
+
if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss))
dev_pm_domain_detach(tegra->genpd_dev_ss, true);
if (!IS_ERR_OR_NULL(tegra->genpd_dev_host))
@@ -1051,20 +1023,84 @@ static int tegra_xusb_powerdomain_init(struct device *dev,
return err;
}
- tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host,
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS);
- if (!tegra->genpd_dl_host) {
- dev_err(dev, "adding host device link failed!\n");
- return -ENODEV;
+ tegra->use_genpd = true;
+
+ return 0;
+}
+
+static int tegra_xusb_unpowergate_partitions(struct tegra_xusb *tegra)
+{
+ struct device *dev = tegra->dev;
+ int rc;
+
+ if (tegra->use_genpd) {
+ rc = pm_runtime_get_sync(tegra->genpd_dev_ss);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB SS partition\n");
+ return rc;
+ }
+
+ rc = pm_runtime_get_sync(tegra->genpd_dev_host);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB Host partition\n");
+ pm_runtime_put_sync(tegra->genpd_dev_ss);
+ return rc;
+ }
+ } else {
+ rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
+ tegra->ss_clk,
+ tegra->ss_rst);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB SS partition\n");
+ return rc;
+ }
+
+ rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
+ tegra->host_clk,
+ tegra->host_rst);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB Host partition\n");
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ return rc;
+ }
}
- tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss,
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS);
- if (!tegra->genpd_dl_ss) {
- dev_err(dev, "adding superspeed device link failed!\n");
- return -ENODEV;
+ return 0;
+}
+
+static int tegra_xusb_powergate_partitions(struct tegra_xusb *tegra)
+{
+ struct device *dev = tegra->dev;
+ int rc;
+
+ if (tegra->use_genpd) {
+ rc = pm_runtime_put_sync(tegra->genpd_dev_host);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB Host partition\n");
+ return rc;
+ }
+
+ rc = pm_runtime_put_sync(tegra->genpd_dev_ss);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB SS partition\n");
+ pm_runtime_get_sync(tegra->genpd_dev_host);
+ return rc;
+ }
+ } else {
+ rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB Host partition\n");
+ return rc;
+ }
+
+ rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB SS partition\n");
+ tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
+ tegra->host_clk,
+ tegra->host_rst);
+ return rc;
+ }
}
return 0;
@@ -1086,6 +1122,24 @@ static int __tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
return err;
}
+static irqreturn_t tegra_xusb_padctl_irq(int irq, void *data)
+{
+ struct tegra_xusb *tegra = data;
+
+ mutex_lock(&tegra->lock);
+
+ if (tegra->suspended) {
+ mutex_unlock(&tegra->lock);
+ return IRQ_HANDLED;
+ }
+
+ mutex_unlock(&tegra->lock);
+
+ pm_runtime_resume(tegra->dev);
+
+ return IRQ_HANDLED;
+}
+
static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
{
int err;
@@ -1209,6 +1263,52 @@ static void tegra_xhci_id_work(struct work_struct *work)
}
}
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP)
+static bool is_usb2_otg_phy(struct tegra_xusb *tegra, unsigned int index)
+{
+ return (tegra->usbphy[index] != NULL);
+}
+
+static bool is_usb3_otg_phy(struct tegra_xusb *tegra, unsigned int index)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+ int port;
+
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ if (is_usb2_otg_phy(tegra, i)) {
+ port = tegra_xusb_padctl_get_usb3_companion(padctl, i);
+ if ((port >= 0) && (index == (unsigned int)port))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool is_host_mode_phy(struct tegra_xusb *tegra, unsigned int phy_type, unsigned int index)
+{
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "hsic") == 0)
+ return true;
+
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "usb2") == 0) {
+ if (is_usb2_otg_phy(tegra, index))
+ return ((index == tegra->otg_usb2_port) && tegra->host_mode);
+ else
+ return true;
+ }
+
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "usb3") == 0) {
+ if (is_usb3_otg_phy(tegra, index))
+ return ((index == tegra->otg_usb3_port) && tegra->host_mode);
+ else
+ return true;
+ }
+
+ return false;
+}
+#endif
+
static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra,
struct usb_phy *usbphy)
{
@@ -1301,6 +1401,7 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
static int tegra_xusb_probe(struct platform_device *pdev)
{
struct tegra_xusb *tegra;
+ struct device_node *np;
struct resource *regs;
struct xhci_hcd *xhci;
unsigned int i, j, k;
@@ -1321,8 +1422,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (err < 0)
return err;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tegra->regs = devm_ioremap_resource(&pdev->dev, regs);
+ tegra->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(tegra->regs))
return PTR_ERR(tegra->regs);
@@ -1348,6 +1448,18 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (IS_ERR(tegra->padctl))
return PTR_ERR(tegra->padctl);
+ np = of_parse_phandle(pdev->dev.of_node, "nvidia,xusb-padctl", 0);
+ if (!np) {
+ err = -ENODEV;
+ goto put_padctl;
+ }
+
+ tegra->padctl_irq = of_irq_get(np, 0);
+ if (tegra->padctl_irq <= 0) {
+ err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq;
+ goto put_padctl;
+ }
+
tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
if (IS_ERR(tegra->host_clk)) {
err = PTR_ERR(tegra->host_clk);
@@ -1428,25 +1540,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
err);
goto put_padctl;
}
-
- err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
- tegra->ss_clk,
- tegra->ss_rst);
- if (err) {
- dev_err(&pdev->dev,
- "failed to enable XUSBA domain: %d\n", err);
- goto put_padctl;
- }
-
- err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
- tegra->host_clk,
- tegra->host_rst);
- if (err) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- dev_err(&pdev->dev,
- "failed to enable XUSBC domain: %d\n", err);
- goto put_padctl;
- }
} else {
err = tegra_xusb_powerdomain_init(&pdev->dev, tegra);
if (err)
@@ -1511,6 +1604,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_powerdomains;
}
+ tegra->hcd->skip_phy_initialization = 1;
tegra->hcd->regs = tegra->regs;
tegra->hcd->rsrc_start = regs->start;
tegra->hcd->rsrc_len = resource_size(regs);
@@ -1521,10 +1615,22 @@ static int tegra_xusb_probe(struct platform_device *pdev)
*/
platform_set_drvdata(pdev, tegra);
+ err = tegra_xusb_clk_enable(tegra);
+ if (err) {
+ dev_err(tegra->dev, "failed to enable clocks: %d\n", err);
+ goto put_hcd;
+ }
+
+ err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
+ if (err) {
+ dev_err(tegra->dev, "failed to enable regulators: %d\n", err);
+ goto disable_clk;
+ }
+
err = tegra_xusb_phy_enable(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err);
- goto put_hcd;
+ goto disable_regulator;
}
/*
@@ -1543,30 +1649,22 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto disable_phy;
}
- pm_runtime_enable(&pdev->dev);
-
- if (!pm_runtime_enabled(&pdev->dev))
- err = tegra_xusb_runtime_resume(&pdev->dev);
- else
- err = pm_runtime_get_sync(&pdev->dev);
-
- if (err < 0) {
- dev_err(&pdev->dev, "failed to enable device: %d\n", err);
+ err = tegra_xusb_unpowergate_partitions(tegra);
+ if (err)
goto free_firmware;
- }
tegra_xusb_config(tegra);
err = tegra_xusb_load_firmware(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to load firmware: %d\n", err);
- goto put_rpm;
+ goto powergate;
}
err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED);
if (err < 0) {
dev_err(&pdev->dev, "failed to add USB HCD: %d\n", err);
- goto put_rpm;
+ goto powergate;
}
device_wakeup_enable(tegra->hcd->self.controller);
@@ -1589,12 +1687,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_usb3;
}
- err = tegra_xusb_enable_firmware_messages(tegra);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
- goto remove_usb3;
- }
-
err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq,
tegra_xusb_mbox_irq,
tegra_xusb_mbox_thread, 0,
@@ -1604,12 +1696,36 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto remove_usb3;
}
+ err = devm_request_threaded_irq(&pdev->dev, tegra->padctl_irq, NULL, tegra_xusb_padctl_irq,
+ IRQF_ONESHOT, dev_name(&pdev->dev), tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request padctl IRQ: %d\n", err);
+ goto remove_usb3;
+ }
+
+ err = tegra_xusb_enable_firmware_messages(tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
+ goto remove_usb3;
+ }
+
err = tegra_xusb_init_usb_phy(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err);
goto remove_usb3;
}
+ /* Enable wake for both USB 2.0 and USB 3.0 roothubs */
+ device_init_wakeup(&tegra->hcd->self.root_hub->dev, true);
+ device_init_wakeup(&xhci->shared_hcd->self.root_hub->dev, true);
+ device_init_wakeup(tegra->dev, true);
+
+ pm_runtime_use_autosuspend(tegra->dev);
+ pm_runtime_set_autosuspend_delay(tegra->dev, 2000);
+ pm_runtime_mark_last_busy(tegra->dev);
+ pm_runtime_set_active(tegra->dev);
+ pm_runtime_enable(tegra->dev);
+
return 0;
remove_usb3:
@@ -1618,25 +1734,23 @@ put_usb3:
usb_put_hcd(xhci->shared_hcd);
remove_usb2:
usb_remove_hcd(tegra->hcd);
-put_rpm:
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra_xusb_runtime_suspend(&pdev->dev);
-put_hcd:
- usb_put_hcd(tegra->hcd);
+powergate:
+ tegra_xusb_powergate_partitions(tegra);
free_firmware:
dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
tegra->fw.phys);
disable_phy:
tegra_xusb_phy_disable(tegra);
- pm_runtime_disable(&pdev->dev);
+disable_regulator:
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
+disable_clk:
+ tegra_xusb_clk_disable(tegra);
+put_hcd:
+ usb_put_hcd(tegra->hcd);
put_powerdomains:
- if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- } else {
- tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
- }
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
put_padctl:
+ of_node_put(np);
tegra_xusb_padctl_put(tegra->padctl);
return err;
}
@@ -1648,6 +1762,7 @@ static int tegra_xusb_remove(struct platform_device *pdev)
tegra_xusb_deinit_usb_phy(tegra);
+ pm_runtime_get_sync(&pdev->dev);
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
@@ -1657,24 +1772,22 @@ static int tegra_xusb_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
tegra->fw.phys);
- pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
- if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- } else {
- tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
- }
+ tegra_xusb_powergate_partitions(tegra);
- tegra_xusb_phy_disable(tegra);
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
+ tegra_xusb_phy_disable(tegra);
+ tegra_xusb_clk_disable(tegra);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
tegra_xusb_padctl_put(tegra->padctl);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP)
static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
{
struct device *dev = hub->hcd->self.controller;
@@ -1700,9 +1813,17 @@ static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
static int tegra_xusb_check_ports(struct tegra_xusb *tegra)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct xhci_bus_state *bus_state = &xhci->usb2_rhub.bus_state;
unsigned long flags;
int err = 0;
+ if (bus_state->bus_suspended) {
+ /* xusb_hub_suspend() has just directed one or more USB2 port(s)
+ * to U3 state, it takes 3ms to enter U3.
+ */
+ usleep_range(3000, 4000);
+ }
+
spin_lock_irqsave(&xhci->lock, flags);
if (!xhci_hub_ports_suspended(&xhci->usb2_rhub) ||
@@ -1748,45 +1869,186 @@ static void tegra_xusb_restore_context(struct tegra_xusb *tegra)
}
}
-static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool wakeup)
+static enum usb_device_speed tegra_xhci_portsc_to_speed(struct tegra_xusb *tegra, u32 portsc)
{
+ if (DEV_LOWSPEED(portsc))
+ return USB_SPEED_LOW;
+
+ if (DEV_HIGHSPEED(portsc))
+ return USB_SPEED_HIGH;
+
+ if (DEV_FULLSPEED(portsc))
+ return USB_SPEED_FULL;
+
+ if (DEV_SUPERSPEED_ANY(portsc))
+ return USB_SPEED_SUPER;
+
+ return USB_SPEED_UNKNOWN;
+}
+
+static void tegra_xhci_enable_phy_sleepwalk_wake(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ enum usb_device_speed speed;
+ struct phy *phy;
+ unsigned int index, offset;
+ unsigned int i, j, k;
+ struct xhci_hub *rhub;
+ u32 portsc;
+
+ for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
+ if (strcmp(tegra->soc->phy_types[i].name, "usb3") == 0)
+ rhub = &xhci->usb3_rhub;
+ else
+ rhub = &xhci->usb2_rhub;
+
+ if (strcmp(tegra->soc->phy_types[i].name, "hsic") == 0)
+ offset = tegra->soc->ports.usb2.count;
+ else
+ offset = 0;
+
+ for (j = 0; j < tegra->soc->phy_types[i].num; j++) {
+ phy = tegra->phys[k++];
+
+ if (!phy)
+ continue;
+
+ index = j + offset;
+
+ if (index >= rhub->num_ports)
+ continue;
+
+ if (!is_host_mode_phy(tegra, i, j))
+ continue;
+
+ portsc = readl(rhub->ports[index]->addr);
+ speed = tegra_xhci_portsc_to_speed(tegra, portsc);
+ tegra_xusb_padctl_enable_phy_sleepwalk(padctl, phy, speed);
+ tegra_xusb_padctl_enable_phy_wake(padctl, phy);
+ }
+ }
+}
+
+static void tegra_xhci_disable_phy_wake(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ tegra_xusb_padctl_disable_phy_wake(padctl, tegra->phys[i]);
+ }
+}
+
+static void tegra_xhci_disable_phy_sleepwalk(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ tegra_xusb_padctl_disable_phy_sleepwalk(padctl, tegra->phys[i]);
+ }
+}
+
+static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct device *dev = tegra->dev;
+ bool wakeup = runtime ? true : device_may_wakeup(dev);
+ unsigned int i;
int err;
+ u32 usbcmd;
+
+ dev_dbg(dev, "entering ELPG\n");
+
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd &= ~CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
err = tegra_xusb_check_ports(tegra);
if (err < 0) {
dev_err(tegra->dev, "not all ports suspended: %d\n", err);
- return err;
+ goto out;
}
err = xhci_suspend(xhci, wakeup);
if (err < 0) {
dev_err(tegra->dev, "failed to suspend XHCI: %d\n", err);
- return err;
+ goto out;
}
tegra_xusb_save_context(tegra);
- tegra_xusb_phy_disable(tegra);
+
+ if (wakeup)
+ tegra_xhci_enable_phy_sleepwalk_wake(tegra);
+
+ tegra_xusb_powergate_partitions(tegra);
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ phy_power_off(tegra->phys[i]);
+ if (!wakeup)
+ phy_exit(tegra->phys[i]);
+ }
+
tegra_xusb_clk_disable(tegra);
- return 0;
+out:
+ if (!err)
+ dev_dbg(tegra->dev, "entering ELPG done\n");
+ else {
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd |= CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
+
+ dev_dbg(tegra->dev, "entering ELPG failed\n");
+ pm_runtime_mark_last_busy(tegra->dev);
+ }
+
+ return err;
}
-static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
+static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct device *dev = tegra->dev;
+ bool wakeup = runtime ? true : device_may_wakeup(dev);
+ unsigned int i;
+ u32 usbcmd;
int err;
+ dev_dbg(dev, "exiting ELPG\n");
+ pm_runtime_mark_last_busy(tegra->dev);
+
err = tegra_xusb_clk_enable(tegra);
if (err < 0) {
dev_err(tegra->dev, "failed to enable clocks: %d\n", err);
- return err;
+ goto out;
}
- err = tegra_xusb_phy_enable(tegra);
- if (err < 0) {
- dev_err(tegra->dev, "failed to enable PHYs: %d\n", err);
- goto disable_clk;
+ err = tegra_xusb_unpowergate_partitions(tegra);
+ if (err)
+ goto disable_clks;
+
+ if (wakeup)
+ tegra_xhci_disable_phy_wake(tegra);
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ if (!wakeup)
+ phy_init(tegra->phys[i]);
+
+ phy_power_on(tegra->phys[i]);
}
tegra_xusb_config(tegra);
@@ -1804,31 +2066,79 @@ static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
goto disable_phy;
}
- err = xhci_resume(xhci, true);
+ if (wakeup)
+ tegra_xhci_disable_phy_sleepwalk(tegra);
+
+ err = xhci_resume(xhci, 0);
if (err < 0) {
dev_err(tegra->dev, "failed to resume XHCI: %d\n", err);
goto disable_phy;
}
- return 0;
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd |= CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
+
+ goto out;
disable_phy:
- tegra_xusb_phy_disable(tegra);
-disable_clk:
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ phy_power_off(tegra->phys[i]);
+ if (!wakeup)
+ phy_exit(tegra->phys[i]);
+ }
+ tegra_xusb_powergate_partitions(tegra);
+disable_clks:
tegra_xusb_clk_disable(tegra);
+out:
+ if (!err)
+ dev_dbg(dev, "exiting ELPG done\n");
+ else
+ dev_dbg(dev, "exiting ELPG failed\n");
+
return err;
}
static int tegra_xusb_suspend(struct device *dev)
{
struct tegra_xusb *tegra = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
int err;
synchronize_irq(tegra->mbox_irq);
mutex_lock(&tegra->lock);
- err = tegra_xusb_enter_elpg(tegra, wakeup);
+
+ if (pm_runtime_suspended(dev)) {
+ err = tegra_xusb_exit_elpg(tegra, true);
+ if (err < 0)
+ goto out;
+ }
+
+ err = tegra_xusb_enter_elpg(tegra, false);
+ if (err < 0) {
+ if (pm_runtime_suspended(dev)) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ goto out;
+ }
+
+out:
+ if (!err) {
+ tegra->suspended = true;
+ pm_runtime_disable(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (enable_irq_wake(tegra->padctl_irq))
+ dev_err(dev, "failed to enable padctl wakes\n");
+ }
+ }
+
mutex_unlock(&tegra->lock);
return err;
@@ -1837,11 +2147,56 @@ static int tegra_xusb_suspend(struct device *dev)
static int tegra_xusb_resume(struct device *dev)
{
struct tegra_xusb *tegra = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
int err;
mutex_lock(&tegra->lock);
- err = tegra_xusb_exit_elpg(tegra, wakeup);
+
+ if (!tegra->suspended) {
+ mutex_unlock(&tegra->lock);
+ return 0;
+ }
+
+ err = tegra_xusb_exit_elpg(tegra, false);
+ if (err < 0) {
+ mutex_unlock(&tegra->lock);
+ return err;
+ }
+
+ if (device_may_wakeup(dev)) {
+ if (disable_irq_wake(tegra->padctl_irq))
+ dev_err(dev, "failed to disable padctl wakes\n");
+ }
+ tegra->suspended = false;
+ mutex_unlock(&tegra->lock);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int tegra_xusb_runtime_suspend(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+ int ret;
+
+ synchronize_irq(tegra->mbox_irq);
+ mutex_lock(&tegra->lock);
+ ret = tegra_xusb_enter_elpg(tegra, true);
+ mutex_unlock(&tegra->lock);
+
+ return ret;
+}
+
+static int tegra_xusb_runtime_resume(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+ int err;
+
+ mutex_lock(&tegra->lock);
+ err = tegra_xusb_exit_elpg(tegra, true);
mutex_unlock(&tegra->lock);
return err;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 27283654ca08..3618070eba78 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1361,12 +1361,17 @@ static void xhci_unmap_temp_buf(struct usb_hcd *hcd, struct urb *urb)
urb->transfer_buffer_length,
dir);
- if (usb_urb_dir_in(urb))
+ if (usb_urb_dir_in(urb)) {
len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs,
urb->transfer_buffer,
buf_len,
0);
-
+ if (len != buf_len) {
+ xhci_dbg(hcd_to_xhci(hcd),
+ "Copy from tmp buf to urb sg list failed\n");
+ urb->actual_length = len;
+ }
+ }
urb->transfer_flags &= ~URB_DMA_MAP_SINGLE;
kfree(urb->transfer_buffer);
urb->transfer_buffer = NULL;
@@ -4840,7 +4845,6 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
if (xhci_update_timeout_for_endpoint(xhci, udev,
&alt->endpoint[j].desc, state, timeout))
return -E2BIG;
- continue;
}
return 0;
}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e417f5ce13d1..3c7d281672ae 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1526,6 +1526,12 @@ static inline const char *xhci_trb_type_string(u8 type)
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
#define MAX_SOFT_RETRY 3
+/*
+ * Limits of consecutive isoc trbs that can Block Event Interrupt (BEI) if
+ * XHCI_AVOID_BEI quirk is in use.
+ */
+#define AVOID_BEI_INTERVAL_MIN 8
+#define AVOID_BEI_INTERVAL_MAX 32
struct xhci_segment {
union xhci_trb *trbs;
@@ -1663,10 +1669,6 @@ struct urb_priv {
* meaning 64 ring segments.
* Initial allocated size of the ERST, in number of entries */
#define ERST_NUM_SEGS 1
-/* Initial allocated size of the ERST, in number of entries */
-#define ERST_SIZE 64
-/* Initial number of event segment rings allocated */
-#define ERST_ENTRIES 1
/* Poll every 60 seconds */
#define POLL_TIMEOUT 60
/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
@@ -1772,6 +1774,7 @@ struct xhci_hcd {
u8 isoc_threshold;
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
+ u32 isoc_bei_interval;
int event_ring_max;
/* 4KB min, 128MB max */
int page_size;
diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig
index b1022cc490a2..2ed2b73291d1 100644
--- a/drivers/usb/isp1760/Kconfig
+++ b/drivers/usb/isp1760/Kconfig
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
config USB_ISP1760
- tristate "NXP ISP 1760/1761 support"
+ tristate "NXP ISP 1760/1761/1763 support"
depends on USB || USB_GADGET
+ select REGMAP_MMIO
help
- Say Y or M here if your system as an ISP1760 USB host controller
+ Say Y or M here if your system as an ISP1760/1763 USB host controller
or an ISP1761 USB dual-role controller.
This driver does not support isochronous transfers or OTG.
diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
index fdeb4cf97cc5..ff07e2890692 100644
--- a/drivers/usb/isp1760/isp1760-core.c
+++ b/drivers/usb/isp1760/isp1760-core.c
@@ -2,12 +2,14 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#include <linux/delay.h>
@@ -15,6 +17,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/usb.h>
@@ -23,10 +26,10 @@
#include "isp1760-regs.h"
#include "isp1760-udc.h"
-static void isp1760_init_core(struct isp1760_device *isp)
+static int isp1760_init_core(struct isp1760_device *isp)
{
- u32 otgctrl;
- u32 hwmode;
+ struct isp1760_hcd *hcd = &isp->hcd;
+ struct isp1760_udc *udc = &isp->udc;
/* Low-level chip reset */
if (isp->rst_gpio) {
@@ -39,24 +42,29 @@ static void isp1760_init_core(struct isp1760_device *isp)
* Reset the host controller, including the CPU interface
* configuration.
*/
- isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
+ isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
- hwmode = HW_DATA_BUS_32BIT;
+ if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) {
+ dev_err(isp->dev, "isp1763 analog overcurrent not available\n");
+ return -EINVAL;
+ }
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
- hwmode &= ~HW_DATA_BUS_32BIT;
+ isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
+ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8)
+ isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH);
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
- hwmode |= HW_ANA_DIGI_OC;
+ isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
- hwmode |= HW_DACK_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
- hwmode |= HW_DREQ_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
- hwmode |= HW_INTR_HIGH_ACT;
+ isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT);
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
- hwmode |= HW_INTR_EDGE_TRIG;
+ isp1760_field_set(hcd->fields, HW_INTR_EDGE_TRIG);
/*
* The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
@@ -65,59 +73,425 @@ static void isp1760_init_core(struct isp1760_device *isp)
* spurious interrupts during HCD registration.
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
- isp1760_write32(isp->regs, DC_MODE, 0);
- hwmode |= HW_COMN_IRQ;
+ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
+ isp1760_field_set(hcd->fields, HW_COMN_IRQ);
}
/*
- * We have to set this first in case we're in 16-bit mode.
- * Write it twice to ensure correct upper bits if switching
- * to 16-bit mode.
- */
- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
-
- /*
* PORT 1 Control register of the ISP1760 is the OTG control register
* on ISP1761.
*
* TODO: Really support OTG. For now we configure port 1 in device mode
- * when OTG is requested.
*/
- if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
- (isp->devflags & ISP1760_FLAG_OTG_EN))
- otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
- | HW_OTG_DISABLE;
- else
- otgctrl = (HW_SW_SEL_HC_DC << 16)
- | (HW_VBUS_DRV | HW_SEL_CP_EXT);
-
- isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
+ if (((isp->devflags & ISP1760_FLAG_ISP1761) ||
+ (isp->devflags & ISP1760_FLAG_ISP1763)) &&
+ (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN)) {
+ isp1760_field_set(hcd->fields, HW_DM_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_DP_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_OTG_DISABLE);
+ } else {
+ isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC);
+ isp1760_field_set(hcd->fields, HW_VBUS_DRV);
+ isp1760_field_set(hcd->fields, HW_SEL_CP_EXT);
+ }
- dev_info(isp->dev, "bus width: %u, oc: %s\n",
+ dev_info(isp->dev, "%s bus width: %u, oc: %s\n",
+ hcd->is_isp1763 ? "isp1763" : "isp1760",
+ isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 :
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
+ hcd->is_isp1763 ? "not available" :
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
+
+ return 0;
}
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
{
- isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
- enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
+ struct isp1760_udc *udc = &isp->udc;
+
+ if (enable)
+ isp1760_field_set(udc->fields, HW_DP_PULLUP);
+ else
+ isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR);
}
+/*
+ * ISP1760/61:
+ *
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+static const struct isp1760_memory_layout isp176x_memory_conf = {
+ .blocks[0] = 32,
+ .blocks_size[0] = 256,
+ .blocks[1] = 20,
+ .blocks_size[1] = 1024,
+ .blocks[2] = 4,
+ .blocks_size[2] = 8192,
+
+ .slot_num = 32,
+ .payload_blocks = 32 + 20 + 4,
+ .payload_area_size = 0xf000,
+};
+
+/*
+ * ISP1763:
+ *
+ * 20kb divided in:
+ * - 8 blocks @ 256 bytes
+ * - 2 blocks @ 1024 bytes
+ * - 4 blocks @ 4096 bytes
+ */
+static const struct isp1760_memory_layout isp1763_memory_conf = {
+ .blocks[0] = 8,
+ .blocks_size[0] = 256,
+ .blocks[1] = 2,
+ .blocks_size[1] = 1024,
+ .blocks[2] = 4,
+ .blocks_size[2] = 4096,
+
+ .slot_num = 16,
+ .payload_blocks = 8 + 2 + 4,
+ .payload_area_size = 0x5000,
+};
+
+static const struct regmap_range isp176x_hc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD),
+ regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY),
+ regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR),
+};
+
+static const struct regmap_access_table isp176x_hc_volatile_table = {
+ .yes_ranges = isp176x_hc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges),
+};
+
+static const struct regmap_config isp1760_hc_regmap_conf = {
+ .name = "isp1760-hc",
+ .reg_bits = 16,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .max_register = ISP176x_HC_OTG_CTRL_CLEAR,
+ .volatile_table = &isp176x_hc_volatile_table,
+};
+
+static const struct reg_field isp1760_hc_reg_fields[] = {
+ [HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4),
+ [HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3),
+ [HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7),
+ [HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6),
+ [CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7),
+ [CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1),
+ [CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0),
+ [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2),
+ [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13),
+ [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0),
+ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31),
+ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31),
+ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31),
+ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31),
+ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31),
+ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31),
+ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31),
+ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31),
+ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31),
+ [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13),
+ [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12),
+ [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11),
+ [PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8),
+ [PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7),
+ [PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6),
+ [PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2),
+ [PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1),
+ [PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0),
+ [ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31),
+ [HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15),
+ [HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10),
+ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8),
+ [HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6),
+ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5),
+ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2),
+ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1),
+ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0),
+ [HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31),
+ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15),
+ [HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7),
+ [HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
+ [ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2),
+ [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1),
+ [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0),
+ [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17),
+ [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15),
+ [HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9),
+ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8),
+ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7),
+ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31),
+ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31),
+ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31),
+ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31),
+ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31),
+ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31),
+ [HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 10, 10),
+ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 7, 7),
+ [HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 4, 4),
+ [HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 3, 3),
+ [HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 2, 2),
+ [HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 1, 1),
+ [HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 0, 0),
+ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 10, 10),
+ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 7, 7),
+ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 4, 4),
+ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 3, 3),
+ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 2, 2),
+ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 1, 1),
+ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 0, 0),
+};
+
+static const struct reg_field isp1763_hc_reg_fields[] = {
+ [CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7),
+ [CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1),
+ [CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0),
+ [STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2),
+ [HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13),
+ [FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0),
+ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15),
+ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15),
+ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15),
+ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15),
+ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15),
+ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15),
+ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15),
+ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15),
+ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15),
+ [PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13),
+ [PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12),
+ [PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11),
+ [PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8),
+ [PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7),
+ [PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6),
+ [PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2),
+ [PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1),
+ [PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0),
+ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4),
+ [HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6),
+ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5),
+ [HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3),
+ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2),
+ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1),
+ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0),
+ [SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0),
+ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15),
+ [HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15),
+ [HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7),
+ [HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15),
+ [ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2),
+ [INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1),
+ [ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0),
+ [MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15),
+ [HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15),
+ [HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10),
+ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8),
+ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7),
+ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15),
+ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15),
+ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15),
+ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15),
+ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15),
+ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15),
+ [HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15),
+ [HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10),
+ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7),
+ [HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4),
+ [HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3),
+ [HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2),
+ [HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1),
+ [HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0),
+ [HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15),
+ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10),
+ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7),
+ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4),
+ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3),
+ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2),
+ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1),
+ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0),
+};
+
+static const struct regmap_range isp1763_hc_volatile_ranges[] = {
+ regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD),
+ regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA),
+ regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR),
+};
+
+static const struct regmap_access_table isp1763_hc_volatile_table = {
+ .yes_ranges = isp1763_hc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges),
+};
+
+static const struct regmap_config isp1763_hc_regmap_conf = {
+ .name = "isp1763-hc",
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .fast_io = true,
+ .max_register = ISP1763_HC_OTG_CTRL_CLEAR,
+ .volatile_table = &isp1763_hc_volatile_table,
+};
+
+static const struct regmap_range isp176x_dc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE),
+ regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX),
+};
+
+static const struct regmap_access_table isp176x_dc_volatile_table = {
+ .yes_ranges = isp176x_dc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges),
+};
+
+static const struct regmap_config isp1761_dc_regmap_conf = {
+ .name = "isp1761-dc",
+ .reg_bits = 16,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .max_register = ISP176x_DC_TESTMODE,
+ .volatile_table = &isp176x_dc_volatile_table,
+};
+
+static const struct reg_field isp1761_dc_reg_fields[] = {
+ [DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7),
+ [DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6),
+ [DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8),
+ [DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4),
+ [DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3),
+ [DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6),
+ [DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4),
+ [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2),
+ [DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0),
+ [DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25),
+ [DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23),
+ [DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21),
+ [DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19),
+ [DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17),
+ [DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15),
+ [DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13),
+ [DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11),
+ [DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8),
+ [DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7),
+ [DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5),
+ [DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4),
+ [DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3),
+ [DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0),
+ [DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5),
+ [DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4),
+ [DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0),
+ [DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4),
+ [DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3),
+ [DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2),
+ [DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1),
+ [DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0),
+ [DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15),
+ [DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10),
+ [DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3),
+ [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1),
+ [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13),
+ [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10),
+ [DC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_DC_CHIPID, 16, 31),
+ [DC_CHIP_ID_LOW] = REG_FIELD(ISP176x_DC_CHIPID, 0, 15),
+ [DC_SCRATCH] = REG_FIELD(ISP176x_DC_SCRATCH, 0, 15),
+};
+
+static const struct regmap_range isp1763_dc_volatile_ranges[] = {
+ regmap_reg_range(ISP1763_DC_EPMAXPKTSZ, ISP1763_DC_EPTYPE),
+ regmap_reg_range(ISP1763_DC_BUFLEN, ISP1763_DC_EPINDEX),
+};
+
+static const struct regmap_access_table isp1763_dc_volatile_table = {
+ .yes_ranges = isp1763_dc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp1763_dc_volatile_ranges),
+};
+
+static const struct reg_field isp1763_dc_reg_fields[] = {
+ [DC_DEVEN] = REG_FIELD(ISP1763_DC_ADDRESS, 7, 7),
+ [DC_DEVADDR] = REG_FIELD(ISP1763_DC_ADDRESS, 0, 6),
+ [DC_VBUSSTAT] = REG_FIELD(ISP1763_DC_MODE, 8, 8),
+ [DC_SFRESET] = REG_FIELD(ISP1763_DC_MODE, 4, 4),
+ [DC_GLINTENA] = REG_FIELD(ISP1763_DC_MODE, 3, 3),
+ [DC_CDBGMOD_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 6, 6),
+ [DC_DDBGMODIN_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 4, 4),
+ [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 2, 2),
+ [DC_INTPOL] = REG_FIELD(ISP1763_DC_INTCONF, 0, 0),
+ [DC_IEPRXTX_7] = REG_FIELD(ISP1763_DC_INTENABLE, 25, 25),
+ [DC_IEPRXTX_6] = REG_FIELD(ISP1763_DC_INTENABLE, 23, 23),
+ [DC_IEPRXTX_5] = REG_FIELD(ISP1763_DC_INTENABLE, 21, 21),
+ [DC_IEPRXTX_4] = REG_FIELD(ISP1763_DC_INTENABLE, 19, 19),
+ [DC_IEPRXTX_3] = REG_FIELD(ISP1763_DC_INTENABLE, 17, 17),
+ [DC_IEPRXTX_2] = REG_FIELD(ISP1763_DC_INTENABLE, 15, 15),
+ [DC_IEPRXTX_1] = REG_FIELD(ISP1763_DC_INTENABLE, 13, 13),
+ [DC_IEPRXTX_0] = REG_FIELD(ISP1763_DC_INTENABLE, 11, 11),
+ [DC_IEP0SETUP] = REG_FIELD(ISP1763_DC_INTENABLE, 8, 8),
+ [DC_IEVBUS] = REG_FIELD(ISP1763_DC_INTENABLE, 7, 7),
+ [DC_IEHS_STA] = REG_FIELD(ISP1763_DC_INTENABLE, 5, 5),
+ [DC_IERESM] = REG_FIELD(ISP1763_DC_INTENABLE, 4, 4),
+ [DC_IESUSP] = REG_FIELD(ISP1763_DC_INTENABLE, 3, 3),
+ [DC_IEBRST] = REG_FIELD(ISP1763_DC_INTENABLE, 0, 0),
+ [DC_EP0SETUP] = REG_FIELD(ISP1763_DC_EPINDEX, 5, 5),
+ [DC_ENDPIDX] = REG_FIELD(ISP1763_DC_EPINDEX, 1, 4),
+ [DC_EPDIR] = REG_FIELD(ISP1763_DC_EPINDEX, 0, 0),
+ [DC_CLBUF] = REG_FIELD(ISP1763_DC_CTRLFUNC, 4, 4),
+ [DC_VENDP] = REG_FIELD(ISP1763_DC_CTRLFUNC, 3, 3),
+ [DC_DSEN] = REG_FIELD(ISP1763_DC_CTRLFUNC, 2, 2),
+ [DC_STATUS] = REG_FIELD(ISP1763_DC_CTRLFUNC, 1, 1),
+ [DC_STALL] = REG_FIELD(ISP1763_DC_CTRLFUNC, 0, 0),
+ [DC_BUFLEN] = REG_FIELD(ISP1763_DC_BUFLEN, 0, 15),
+ [DC_FFOSZ] = REG_FIELD(ISP1763_DC_EPMAXPKTSZ, 0, 10),
+ [DC_EPENABLE] = REG_FIELD(ISP1763_DC_EPTYPE, 3, 3),
+ [DC_ENDPTYP] = REG_FIELD(ISP1763_DC_EPTYPE, 0, 1),
+ [DC_UFRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 11, 13),
+ [DC_FRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 0, 10),
+ [DC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_DC_CHIPID_HIGH, 0, 15),
+ [DC_CHIP_ID_LOW] = REG_FIELD(ISP1763_DC_CHIPID_LOW, 0, 15),
+ [DC_SCRATCH] = REG_FIELD(ISP1763_DC_SCRATCH, 0, 15),
+};
+
+static const struct regmap_config isp1763_dc_regmap_conf = {
+ .name = "isp1763-dc",
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .fast_io = true,
+ .max_register = ISP1763_DC_TESTMODE,
+ .volatile_table = &isp1763_dc_volatile_table,
+};
+
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
+ const struct regmap_config *hc_regmap;
+ const struct reg_field *hc_reg_fields;
+ const struct regmap_config *dc_regmap;
+ const struct reg_field *dc_reg_fields;
struct isp1760_device *isp;
- bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+ struct isp1760_hcd *hcd;
+ struct isp1760_udc *udc;
+ struct regmap_field *f;
+ bool udc_enabled;
int ret;
+ int i;
/*
* If neither the HCD not the UDC is enabled return an error, as no
* device would be registered.
*/
+ udc_enabled = ((devflags & ISP1760_FLAG_ISP1763) ||
+ (devflags & ISP1760_FLAG_ISP1761));
+
if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
- (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
+ (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || !udc_enabled))
return -ENODEV;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
@@ -126,28 +500,81 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
isp->dev = dev;
isp->devflags = devflags;
+ hcd = &isp->hcd;
+ udc = &isp->udc;
+
+ hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
+ udc->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
+
+ if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) {
+ dev_err(dev, "isp1760/61 do not support data width 8\n");
+ return -EINVAL;
+ }
+
+ if (hcd->is_isp1763) {
+ hc_regmap = &isp1763_hc_regmap_conf;
+ hc_reg_fields = &isp1763_hc_reg_fields[0];
+ dc_regmap = &isp1763_dc_regmap_conf;
+ dc_reg_fields = &isp1763_dc_reg_fields[0];
+ } else {
+ hc_regmap = &isp1760_hc_regmap_conf;
+ hc_reg_fields = &isp1760_hc_reg_fields[0];
+ dc_regmap = &isp1761_dc_regmap_conf;
+ dc_reg_fields = &isp1761_dc_reg_fields[0];
+ }
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
- isp->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(isp->regs))
- return PTR_ERR(isp->regs);
+ hcd->base = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hcd->base))
+ return PTR_ERR(hcd->base);
+
+ hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap);
+ if (IS_ERR(hcd->regs))
+ return PTR_ERR(hcd->regs);
+
+ for (i = 0; i < HC_FIELD_MAX; i++) {
+ f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ hcd->fields[i] = f;
+ }
+
+ udc->regs = devm_regmap_init_mmio(dev, hcd->base, dc_regmap);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
+
+ for (i = 0; i < DC_FIELD_MAX; i++) {
+ f = devm_regmap_field_alloc(dev, udc->regs, dc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ udc->fields[i] = f;
+ }
+
+ if (hcd->is_isp1763)
+ hcd->memory_layout = &isp1763_memory_conf;
+ else
+ hcd->memory_layout = &isp176x_memory_conf;
- isp1760_init_core(isp);
+ ret = isp1760_init_core(isp);
+ if (ret < 0)
+ return ret;
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
- ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
+ ret = isp1760_hcd_register(hcd, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
}
- if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
+ if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && udc_enabled) {
ret = isp1760_udc_register(isp, irq, irqflags);
if (ret < 0) {
- isp1760_hcd_unregister(&isp->hcd);
+ isp1760_hcd_unregister(hcd);
return ret;
}
}
diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
index d9a0a4cc467c..91e0ee3992a7 100644
--- a/drivers/usb/isp1760/isp1760-core.h
+++ b/drivers/usb/isp1760/isp1760-core.h
@@ -2,18 +2,21 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP1760_CORE_H_
#define _ISP1760_CORE_H_
#include <linux/ioport.h>
+#include <linux/regmap.h>
#include "isp1760-hcd.h"
#include "isp1760-udc.h"
@@ -27,18 +30,19 @@ struct gpio_desc;
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
-#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
+#define ISP1760_FLAG_PERIPHERAL_EN 0x00000004 /* Port 1 supports Peripheral mode*/
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
+#define ISP1760_FLAG_ISP1763 0x00000200 /* Chip is ISP1763 */
+#define ISP1760_FLAG_BUS_WIDTH_8 0x00000400 /* 8-bit data bus width */
struct isp1760_device {
struct device *dev;
- void __iomem *regs;
unsigned int devflags;
struct gpio_desc *rst_gpio;
@@ -52,14 +56,42 @@ void isp1760_unregister(struct device *dev);
void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
-static inline u32 isp1760_read32(void __iomem *base, u32 reg)
+static inline u32 isp1760_field_read(struct regmap_field **fields, u32 field)
{
- return readl(base + reg);
+ unsigned int val;
+
+ regmap_field_read(fields[field], &val);
+
+ return val;
+}
+
+static inline void isp1760_field_write(struct regmap_field **fields, u32 field,
+ u32 val)
+{
+ regmap_field_write(fields[field], val);
+}
+
+static inline void isp1760_field_set(struct regmap_field **fields, u32 field)
+{
+ isp1760_field_write(fields, field, 0xFFFFFFFF);
}
-static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
+static inline void isp1760_field_clear(struct regmap_field **fields, u32 field)
{
- writel(val, base + reg);
+ isp1760_field_write(fields, field, 0);
}
+static inline u32 isp1760_reg_read(struct regmap *regs, u32 reg)
+{
+ unsigned int val;
+
+ regmap_read(regs, reg, &val);
+
+ return val;
+}
+
+static inline void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val)
+{
+ regmap_write(regs, reg, val);
+}
#endif
diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
index 33ae656c4b68..27168b4a4ef2 100644
--- a/drivers/usb/isp1760/isp1760-hcd.c
+++ b/drivers/usb/isp1760/isp1760-hcd.c
@@ -11,6 +11,8 @@
*
* (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
*
+ * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
+ *
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
@@ -44,6 +46,9 @@ static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
return *(struct isp1760_hcd **)hcd->hcd_priv;
}
+#define dw_to_le32(x) (cpu_to_le32((__force u32)x))
+#define le32_to_dw(x) ((__force __dw)(le32_to_cpu(x)))
+
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
@@ -60,50 +65,69 @@ struct ptd {
__dw dw6;
__dw dw7;
};
+
+struct ptd_le32 {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 dw2;
+ __le32 dw3;
+ __le32 dw4;
+ __le32 dw5;
+ __le32 dw6;
+ __le32 dw7;
+};
+
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
-
-/* ATL */
-/* DW0 */
-#define DW0_VALID_BIT 1
-#define FROM_DW0_VALID(x) ((x) & 0x01)
-#define TO_DW0_LENGTH(x) (((u32) x) << 3)
-#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
-#define TO_DW0_MULTI(x) (((u32) x) << 29)
-#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
+#define ISP_BANK_0 0x00
+#define ISP_BANK_1 0x01
+#define ISP_BANK_2 0x02
+#define ISP_BANK_3 0x03
+
+#define TO_DW(x) ((__force __dw)x)
+#define TO_U32(x) ((__force u32)x)
+
+ /* ATL */
+ /* DW0 */
+#define DW0_VALID_BIT TO_DW(1)
+#define FROM_DW0_VALID(x) (TO_U32(x) & 0x01)
+#define TO_DW0_LENGTH(x) TO_DW((((u32)x) << 3))
+#define TO_DW0_MAXPACKET(x) TO_DW((((u32)x) << 18))
+#define TO_DW0_MULTI(x) TO_DW((((u32)x) << 29))
+#define TO_DW0_ENDPOINT(x) TO_DW((((u32)x) << 31))
/* DW1 */
-#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
-#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
-#define DW1_TRANS_BULK ((u32) 2 << 12)
-#define DW1_TRANS_INT ((u32) 3 << 12)
-#define DW1_TRANS_SPLIT ((u32) 1 << 14)
-#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
-#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
-#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
+#define TO_DW1_DEVICE_ADDR(x) TO_DW((((u32)x) << 3))
+#define TO_DW1_PID_TOKEN(x) TO_DW((((u32)x) << 10))
+#define DW1_TRANS_BULK TO_DW(((u32)2 << 12))
+#define DW1_TRANS_INT TO_DW(((u32)3 << 12))
+#define DW1_TRANS_SPLIT TO_DW(((u32)1 << 14))
+#define DW1_SE_USB_LOSPEED TO_DW(((u32)2 << 16))
+#define TO_DW1_PORT_NUM(x) TO_DW((((u32)x) << 18))
+#define TO_DW1_HUB_NUM(x) TO_DW((((u32)x) << 25))
/* DW2 */
-#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
-#define TO_DW2_RL(x) ((x) << 25)
-#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
+#define TO_DW2_DATA_START_ADDR(x) TO_DW((((u32)x) << 8))
+#define TO_DW2_RL(x) TO_DW(((x) << 25))
+#define FROM_DW2_RL(x) ((TO_U32(x) >> 25) & 0xf)
/* DW3 */
-#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
-#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
-#define TO_DW3_NAKCOUNT(x) ((x) << 19)
-#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
-#define TO_DW3_CERR(x) ((x) << 23)
-#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
-#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
-#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
-#define TO_DW3_PING(x) ((x) << 26)
-#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
-#define DW3_ERROR_BIT (1 << 28)
-#define DW3_BABBLE_BIT (1 << 29)
-#define DW3_HALT_BIT (1 << 30)
-#define DW3_ACTIVE_BIT (1 << 31)
-#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
+#define FROM_DW3_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x3fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x) TO_DW(((x) << 19))
+#define FROM_DW3_NAKCOUNT(x) ((TO_U32(x) >> 19) & 0xf)
+#define TO_DW3_CERR(x) TO_DW(((x) << 23))
+#define FROM_DW3_CERR(x) ((TO_U32(x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x) TO_DW(((x) << 25))
+#define FROM_DW3_DATA_TOGGLE(x) ((TO_U32(x) >> 25) & 0x1)
+#define TO_DW3_PING(x) TO_DW(((x) << 26))
+#define FROM_DW3_PING(x) ((TO_U32(x) >> 26) & 0x1)
+#define DW3_ERROR_BIT TO_DW((1 << 28))
+#define DW3_BABBLE_BIT TO_DW((1 << 29))
+#define DW3_HALT_BIT TO_DW((1 << 30))
+#define DW3_ACTIVE_BIT TO_DW((1 << 31))
+#define FROM_DW3_ACTIVE(x) ((TO_U32(x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
@@ -116,7 +140,7 @@ struct ptd {
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
-#define ERR_COUNTER (2)
+#define ERR_COUNTER (3)
struct isp1760_qtd {
u8 packet_type;
@@ -158,17 +182,124 @@ struct urb_listitem {
struct urb *urb;
};
+static const u32 isp1763_hc_portsc1_fields[] = {
+ [PORT_OWNER] = BIT(13),
+ [PORT_POWER] = BIT(12),
+ [PORT_LSTATUS] = BIT(10),
+ [PORT_RESET] = BIT(8),
+ [PORT_SUSPEND] = BIT(7),
+ [PORT_RESUME] = BIT(6),
+ [PORT_PE] = BIT(2),
+ [PORT_CSC] = BIT(1),
+ [PORT_CONNECT] = BIT(0),
+};
+
+/*
+ * Access functions for isp176x registers regmap fields
+ */
+static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ return isp1760_field_read(priv->fields, field);
+}
+
/*
- * Access functions for isp176x registers (addresses 0..0x03FF).
+ * We need, in isp1763, to write directly the values to the portsc1
+ * register so it will make the other values to trigger.
*/
-static u32 reg_read32(void __iomem *base, u32 reg)
+static void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field,
+ u32 val)
+{
+ u32 bit = isp1763_hc_portsc1_fields[field];
+ u32 port_status = readl(priv->base + ISP1763_HC_PORTSC1);
+
+ if (val)
+ writel(port_status | bit, priv->base + ISP1763_HC_PORTSC1);
+ else
+ writel(port_status & ~bit, priv->base + ISP1763_HC_PORTSC1);
+}
+
+static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (unlikely(priv->is_isp1763 &&
+ (field >= PORT_OWNER && field <= PORT_CONNECT)))
+ return isp1760_hcd_portsc1_set_clear(priv, field, val);
+
+ isp1760_field_write(priv->fields, field, val);
+}
+
+static void isp1760_hcd_set(struct usb_hcd *hcd, u32 field)
+{
+ isp1760_hcd_write(hcd, field, 0xFFFFFFFF);
+}
+
+static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
{
- return isp1760_read32(base, reg);
+ isp1760_hcd_write(hcd, field, 0);
+}
+
+static int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_set(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ val, 10, timeout_us);
+}
+
+static int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_set(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ !val, 10, timeout_us);
+}
+
+static int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_clear(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ !val, 10, timeout_us);
+}
+
+static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
+{
+ return !!isp1760_hcd_read(hcd, field);
+}
+
+static bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (priv->is_isp1763)
+ return true;
+
+ return isp1760_hcd_is_set(hcd, HCS_PPC);
}
-static void reg_write32(void __iomem *base, u32 reg, u32 val)
+static u32 isp1760_hcd_n_ports(struct usb_hcd *hcd)
{
- isp1760_write32(base, reg, val);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (priv->is_isp1763)
+ return 1;
+
+ return isp1760_hcd_read(hcd, HCS_N_PORTS);
}
/*
@@ -176,7 +307,7 @@ static void reg_write32(void __iomem *base, u32 reg, u32 val)
*
* bank_reads8() reads memory locations prefetched by an earlier write to
* HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
- * bank optimizations, you should use the more generic mem_reads8() below.
+ * bank optimizations, you should use the more generic mem_read() below.
*
* For access to ptd memory, use the specialized ptd_read() and ptd_write()
* below.
@@ -196,7 +327,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
if (src_offset < PAYLOAD_OFFSET) {
while (bytes >= 4) {
- *dst = le32_to_cpu(__raw_readl(src));
+ *dst = readl_relaxed(src);
bytes -= 4;
src++;
dst++;
@@ -217,7 +348,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
* allocated.
*/
if (src_offset < PAYLOAD_OFFSET)
- val = le32_to_cpu(__raw_readl(src));
+ val = readl_relaxed(src);
else
val = __raw_readl(src);
@@ -231,16 +362,59 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
}
}
-static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
- u32 bytes)
+static void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst,
+ u32 bytes)
{
- reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
- ndelay(90);
- bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
+ ndelay(100);
+
+ bank_reads8(priv->base, src_offset, ISP_BANK_0, dst, bytes);
}
-static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
- __u32 const *src, u32 bytes)
+/*
+ * ISP1763 does not have the banks direct host controller memory access,
+ * needs to use the HC_DATA register. Add data read/write according to this,
+ * and also adjust 16bit access.
+ */
+static void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr,
+ u16 *dstptr, u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ /* Write the starting device address to the hcd memory register */
+ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, srcaddr);
+ ndelay(100); /* Delay between consecutive access */
+
+ /* As long there are at least 16-bit to read ... */
+ while (bytes >= 2) {
+ *dstptr = __raw_readw(priv->base + ISP1763_HC_DATA);
+ bytes -= 2;
+ dstptr++;
+ }
+
+ /* If there are no more bytes to read, return */
+ if (bytes <= 0)
+ return;
+
+ *((u8 *)dstptr) = (u8)(readw(priv->base + ISP1763_HC_DATA) & 0xFF);
+}
+
+static void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_mem_read(hcd, src_offset, (u16 *)dst, bytes);
+
+ isp1763_mem_read(hcd, (u16)src_offset, (u16 *)dst, bytes);
+}
+
+static void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset,
+ __u32 const *src, u32 bytes)
{
__u32 __iomem *dst;
@@ -248,7 +422,7 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
if (dst_offset < PAYLOAD_OFFSET) {
while (bytes >= 4) {
- __raw_writel(cpu_to_le32(*src), dst);
+ writel_relaxed(*src, dst);
bytes -= 4;
src++;
dst++;
@@ -269,74 +443,168 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
*/
if (dst_offset < PAYLOAD_OFFSET)
- __raw_writel(cpu_to_le32(*src), dst);
+ writel_relaxed(*src, dst);
else
__raw_writel(*src, dst);
}
+static void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ /* Write the starting device address to the hcd memory register */
+ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, dstaddr);
+ ndelay(100); /* Delay between consecutive access */
+
+ while (bytes >= 2) {
+ /* Get and write the data; then adjust the data ptr and len */
+ __raw_writew(*src, priv->base + ISP1763_HC_DATA);
+ bytes -= 2;
+ src++;
+ }
+
+ /* If there are no more bytes to process, return */
+ if (bytes <= 0)
+ return;
+
+ /*
+ * The only way to get here is if there is a single byte left,
+ * get it and write it to the data reg;
+ */
+ writew(*((u8 *)src), priv->base + ISP1763_HC_DATA);
+}
+
+static void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_mem_write(priv->base, dst_offset, src, bytes);
+
+ isp1763_mem_write(hcd, dst_offset, (u16 *)src, bytes);
+}
+
/*
* Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
* INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
*/
-static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
+static void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
{
- reg_write32(base, HC_MEMORY_REG,
- ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
+ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
ndelay(90);
- bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
- (void *) ptd, sizeof(*ptd));
+
+ bank_reads8(priv->base, src_offset, ISP_BANK_0, (void *)ptd,
+ sizeof(*ptd));
+}
+
+static void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
+ struct ptd_le32 le32_ptd;
+
+ isp1763_mem_read(hcd, src_offset, (u16 *)&le32_ptd, sizeof(le32_ptd));
+ /* Normalize the data obtained */
+ ptd->dw0 = le32_to_dw(le32_ptd.dw0);
+ ptd->dw1 = le32_to_dw(le32_ptd.dw1);
+ ptd->dw2 = le32_to_dw(le32_ptd.dw2);
+ ptd->dw3 = le32_to_dw(le32_ptd.dw3);
+ ptd->dw4 = le32_to_dw(le32_ptd.dw4);
+ ptd->dw5 = le32_to_dw(le32_ptd.dw5);
+ ptd->dw6 = le32_to_dw(le32_ptd.dw6);
+ ptd->dw7 = le32_to_dw(le32_ptd.dw7);
+}
+
+static void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_ptd_read(hcd, ptd_offset, slot, ptd);
+
+ isp1763_ptd_read(hcd, ptd_offset, slot, ptd);
+}
+
+static void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *cpu_ptd)
+{
+ u16 dst_offset = ptd_offset + slot * sizeof(*cpu_ptd);
+ struct ptd_le32 ptd;
+
+ ptd.dw0 = dw_to_le32(cpu_ptd->dw0);
+ ptd.dw1 = dw_to_le32(cpu_ptd->dw1);
+ ptd.dw2 = dw_to_le32(cpu_ptd->dw2);
+ ptd.dw3 = dw_to_le32(cpu_ptd->dw3);
+ ptd.dw4 = dw_to_le32(cpu_ptd->dw4);
+ ptd.dw5 = dw_to_le32(cpu_ptd->dw5);
+ ptd.dw6 = dw_to_le32(cpu_ptd->dw6);
+ ptd.dw7 = dw_to_le32(cpu_ptd->dw7);
+
+ isp1763_mem_write(hcd, dst_offset, (u16 *)&ptd.dw0,
+ 8 * sizeof(ptd.dw0));
}
-static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
+static void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
{
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
- &ptd->dw1, 7*sizeof(ptd->dw1));
- /* Make sure dw0 gets written last (after other dw's and after payload)
- since it contains the enable bit */
+ u32 dst_offset = ptd_offset + slot * sizeof(*ptd);
+
+ /*
+ * Make sure dw0 gets written last (after other dw's and after payload)
+ * since it contains the enable bit
+ */
+ isp1760_mem_write(base, dst_offset + sizeof(ptd->dw0),
+ (__force u32 *)&ptd->dw1, 7 * sizeof(ptd->dw1));
wmb();
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
- sizeof(ptd->dw0));
+ isp1760_mem_write(base, dst_offset, (__force u32 *)&ptd->dw0,
+ sizeof(ptd->dw0));
}
+static void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_ptd_write(priv->base, ptd_offset, slot, ptd);
+
+ isp1763_ptd_write(hcd, ptd_offset, slot, ptd);
+}
/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
static void init_memory(struct isp1760_hcd *priv)
{
- int i, curr;
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int i, j, curr;
u32 payload_addr;
payload_addr = PAYLOAD_OFFSET;
- for (i = 0; i < BLOCK_1_NUM; i++) {
- priv->memory_pool[i].start = payload_addr;
- priv->memory_pool[i].size = BLOCK_1_SIZE;
- priv->memory_pool[i].free = 1;
- payload_addr += priv->memory_pool[i].size;
- }
-
- curr = i;
- for (i = 0; i < BLOCK_2_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
- }
- curr = i;
- for (i = 0; i < BLOCK_3_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
+ for (i = 0, curr = 0; i < ARRAY_SIZE(mem->blocks); i++) {
+ for (j = 0; j < mem->blocks[i]; j++, curr++) {
+ priv->memory_pool[curr + j].start = payload_addr;
+ priv->memory_pool[curr + j].size = mem->blocks_size[i];
+ priv->memory_pool[curr + j].free = 1;
+ payload_addr += priv->memory_pool[curr + j].size;
+ }
}
- WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+ WARN_ON(payload_addr - priv->memory_pool[0].start >
+ mem->payload_area_size);
}
static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int i;
WARN_ON(qtd->payload_addr);
@@ -344,7 +612,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
if (!qtd->length)
return;
- for (i = 0; i < BLOCKS; i++) {
+ for (i = 0; i < mem->payload_blocks; i++) {
if (priv->memory_pool[i].size >= qtd->length &&
priv->memory_pool[i].free) {
priv->memory_pool[i].free = 0;
@@ -357,12 +625,13 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int i;
if (!qtd->payload_addr)
return;
- for (i = 0; i < BLOCKS; i++) {
+ for (i = 0; i < mem->payload_blocks; i++) {
if (priv->memory_pool[i].start == qtd->payload_addr) {
WARN_ON(priv->memory_pool[i].free);
priv->memory_pool[i].free = 1;
@@ -377,34 +646,15 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
qtd->payload_addr = 0;
}
-static int handshake(struct usb_hcd *hcd, u32 reg,
- u32 mask, u32 done, int usec)
-{
- u32 result;
- int ret;
-
- ret = readl_poll_timeout_atomic(hcd->regs + reg, result,
- ((result & mask) == done ||
- result == U32_MAX), 1, usec);
- if (result == U32_MAX)
- return -ENODEV;
-
- return ret;
-}
-
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 command = reg_read32(hcd->regs, HC_USBCMD);
-
- command |= CMD_RESET;
- reg_write32(hcd->regs, HC_USBCMD, command);
hcd->state = HC_STATE_HALT;
priv->next_statechange = jiffies;
- return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000);
+ return isp1760_hcd_set_and_wait_swap(hcd, CMD_RESET, 250 * 1000);
}
static struct isp1760_qh *qh_alloc(gfp_t flags)
@@ -432,8 +682,9 @@ static void qh_free(struct isp1760_qh *qh)
/* one-time init, only for memory state */
static int priv_init(struct usb_hcd *hcd)
{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 hcc_params;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 isoc_cache;
+ u32 isoc_thres;
int i;
spin_lock_init(&priv->lock);
@@ -447,13 +698,20 @@ static int priv_init(struct usb_hcd *hcd)
*/
priv->periodic_size = DEFAULT_I_TDPS;
+ if (priv->is_isp1763) {
+ priv->i_thresh = 2;
+ return 0;
+ }
+
/* controllers may cache some of the periodic schedule ... */
- hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
+ isoc_cache = isp1760_hcd_read(hcd, HCC_ISOC_CACHE);
+ isoc_thres = isp1760_hcd_read(hcd, HCC_ISOC_THRES);
+
/* full frame cache */
- if (HCC_ISOC_CACHE(hcc_params))
+ if (isoc_cache)
priv->i_thresh = 8;
else /* N microframes cached */
- priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+ priv->i_thresh = 2 + isoc_thres;
return 0;
}
@@ -461,15 +719,24 @@ static int priv_init(struct usb_hcd *hcd)
static int isp1760_hc_setup(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 atx_reset;
int result;
- u32 scratch, hwmode;
+ u32 scratch;
+ u32 pattern;
+
+ if (priv->is_isp1763)
+ pattern = 0xcafe;
+ else
+ pattern = 0xdeadcafe;
+
+ isp1760_hcd_write(hcd, HC_SCRATCH, pattern);
- reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
/* Change bus pattern */
- scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
- if (scratch != 0xdeadbabe) {
- dev_err(hcd->self.controller, "Scratch test failed.\n");
+ scratch = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ dev_err(hcd->self.controller, "Scratch test 0x%08x\n", scratch);
+ scratch = isp1760_hcd_read(hcd, HC_SCRATCH);
+ if (scratch != pattern) {
+ dev_err(hcd->self.controller, "Scratch test failed. 0x%08x\n", scratch);
return -ENODEV;
}
@@ -481,10 +748,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
* the host controller through the EHCI USB Command register. The device
* has been reset in core code anyway, so this shouldn't matter.
*/
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
+ isp1760_hcd_clear(hcd, INT_BUF_FILL);
+ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
result = ehci_reset(hcd);
if (result)
@@ -493,14 +763,26 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
/* Step 11 passed */
/* ATL reset */
- hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
+ if (priv->is_isp1763)
+ atx_reset = SW_RESET_RESET_ATX;
+ else
+ atx_reset = ALL_ATX_RESET;
+
+ isp1760_hcd_set(hcd, atx_reset);
mdelay(10);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
+ isp1760_hcd_clear(hcd, atx_reset);
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
+ if (priv->is_isp1763) {
+ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
+ isp1760_hcd_set(hcd, HW_SW_SEL_HC_DC_CLEAR);
+ isp1760_hcd_set(hcd, HW_HC_2_DIS_CLEAR);
+ mdelay(10);
- priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
+ isp1760_hcd_set(hcd, HW_INTF_LOCK);
+ }
+
+ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
return priv_init(hcd);
}
@@ -553,7 +835,7 @@ static void create_ptd_atl(struct isp1760_qh *qh,
ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
/* DW1 */
- ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
+ ptd->dw1 = TO_DW((usb_pipeendpoint(qtd->urb->pipe) >> 1));
ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
@@ -575,7 +857,7 @@ static void create_ptd_atl(struct isp1760_qh *qh,
/* SE bit for Split INT transfers */
if (usb_pipeint(qtd->urb->pipe) &&
(qtd->urb->dev->speed == USB_SPEED_LOW))
- ptd->dw1 |= 2 << 16;
+ ptd->dw1 |= DW1_SE_USB_LOSPEED;
rl = 0;
nak = 0;
@@ -647,14 +929,14 @@ static void transform_add_int(struct isp1760_qh *qh,
* that number come from? 0xff seems to work fine...
*/
/* ptd->dw5 = 0x1c; */
- ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
+ ptd->dw5 = TO_DW(0xff); /* Execute Complete Split on any uFrame */
}
period = period >> 1;/* Ensure equal or shorter period than requested */
period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
- ptd->dw2 |= period;
- ptd->dw4 = usof;
+ ptd->dw2 |= TO_DW(period);
+ ptd->dw4 = TO_DW(usof);
}
static void create_ptd_int(struct isp1760_qh *qh,
@@ -720,41 +1002,45 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
struct ptd *ptd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int skip_map;
- WARN_ON((slot < 0) || (slot > 31));
+ WARN_ON((slot < 0) || (slot > mem->slot_num - 1));
WARN_ON(qtd->length && !qtd->payload_addr);
WARN_ON(slots[slot].qtd);
WARN_ON(slots[slot].qh);
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+ if (priv->is_isp1763)
+ ndelay(100);
+
/* Make sure done map has not triggered from some unlinked transfer */
if (ptd_offset == ATL_PTD_OFFSET) {
- priv->atl_done_map |= reg_read32(hcd->regs,
- HC_ATL_PTD_DONEMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP,
+ skip_map | (1 << slot));
+ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
priv->atl_done_map &= ~(1 << slot);
} else {
- priv->int_done_map |= reg_read32(hcd->regs,
- HC_INT_PTD_DONEMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP,
+ skip_map | (1 << slot));
+ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
priv->int_done_map &= ~(1 << slot);
}
+ skip_map &= ~(1 << slot);
qh->slot = slot;
qtd->status = QTD_XFER_STARTED;
slots[slot].timestamp = jiffies;
slots[slot].qtd = qtd;
slots[slot].qh = qh;
- ptd_write(hcd->regs, ptd_offset, slot, ptd);
+ ptd_write(hcd, ptd_offset, slot, ptd);
- if (ptd_offset == ATL_PTD_OFFSET) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
- } else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
- }
+ if (ptd_offset == ATL_PTD_OFFSET)
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
+ else
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
}
static int is_short_bulk(struct isp1760_qtd *qtd)
@@ -766,9 +1052,9 @@ static int is_short_bulk(struct isp1760_qtd *qtd)
static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct list_head *urb_list)
{
- int last_qtd;
struct isp1760_qtd *qtd, *qtd_next;
struct urb_listitem *urb_listitem;
+ int last_qtd;
list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
if (qtd->status < QTD_XFER_COMPLETE)
@@ -783,9 +1069,9 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
if (qtd->actual_length) {
switch (qtd->packet_type) {
case IN_PID:
- mem_reads8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer,
- qtd->actual_length);
+ mem_read(hcd, qtd->payload_addr,
+ qtd->data_buffer,
+ qtd->actual_length);
fallthrough;
case OUT_PID:
qtd->urb->actual_length +=
@@ -829,6 +1115,8 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int slot_num = mem->slot_num;
int ptd_offset;
struct isp1760_slotinfo *slots;
int curr_slot, free_slot;
@@ -855,7 +1143,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
}
free_slot = -1;
- for (curr_slot = 0; curr_slot < 32; curr_slot++) {
+ for (curr_slot = 0; curr_slot < slot_num; curr_slot++) {
if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
free_slot = curr_slot;
if (slots[curr_slot].qh == qh)
@@ -870,11 +1158,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
if ((qtd->length) && (!qtd->payload_addr))
break;
- if ((qtd->length) &&
- ((qtd->packet_type == SETUP_PID) ||
- (qtd->packet_type == OUT_PID))) {
- mem_writes8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, qtd->length);
+ if (qtd->length && (qtd->packet_type == SETUP_PID ||
+ qtd->packet_type == OUT_PID)) {
+ mem_write(hcd, qtd->payload_addr,
+ qtd->data_buffer, qtd->length);
}
qtd->status = QTD_PAYLOAD_ALLOC;
@@ -887,7 +1174,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
"available for transfer\n", __func__);
*/
/* Start xfer for this endpoint if not already done */
- if ((curr_slot > 31) && (free_slot > -1)) {
+ if ((curr_slot > slot_num - 1) && (free_slot > -1)) {
if (usb_pipeint(qtd->urb->pipe))
create_ptd_int(qh, qtd, &ptd);
else
@@ -977,10 +1264,10 @@ static void schedule_ptds(struct usb_hcd *hcd)
static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
struct urb *urb)
{
- __dw dw4;
+ u32 dw4;
int i;
- dw4 = ptd->dw4;
+ dw4 = TO_U32(ptd->dw4);
dw4 >>= 8;
/* FIXME: ISP1761 datasheet does not say what to do with these. Do we
@@ -1074,9 +1361,9 @@ static void handle_done_ptds(struct usb_hcd *hcd)
int modified;
int skip_map;
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
priv->int_done_map &= ~skip_map;
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
priv->atl_done_map &= ~skip_map;
modified = priv->int_done_map || priv->atl_done_map;
@@ -1094,7 +1381,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
continue;
}
ptd_offset = INT_PTD_OFFSET;
- ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, INT_PTD_OFFSET, slot, &ptd);
state = check_int_transfer(hcd, &ptd,
slots[slot].qtd->urb);
} else {
@@ -1109,7 +1396,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
continue;
}
ptd_offset = ATL_PTD_OFFSET;
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
state = check_atl_transfer(hcd, &ptd,
slots[slot].qtd->urb);
}
@@ -1134,7 +1421,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
qtd->status = QTD_XFER_COMPLETE;
if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
- is_short_bulk(qtd))
+ is_short_bulk(qtd))
qtd = NULL;
else
qtd = list_entry(qtd->qtd_list.next,
@@ -1202,25 +1489,30 @@ static void handle_done_ptds(struct usb_hcd *hcd)
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 imask;
irqreturn_t irqret = IRQ_NONE;
+ u32 int_reg;
+ u32 imask;
spin_lock(&priv->lock);
if (!(hcd->state & HC_STATE_RUNNING))
goto leave;
- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+ imask = isp1760_hcd_read(hcd, HC_INTERRUPT);
if (unlikely(!imask))
goto leave;
- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
- priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
- priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+ int_reg = priv->is_isp1763 ? ISP1763_HC_INTERRUPT :
+ ISP176x_HC_INTERRUPT;
+ isp1760_reg_write(priv->regs, int_reg, imask);
+
+ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
+ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
handle_done_ptds(hcd);
irqret = IRQ_HANDLED;
+
leave:
spin_unlock(&priv->lock);
@@ -1261,17 +1553,18 @@ static void errata2_function(struct timer_list *unused)
{
struct usb_hcd *hcd = errata2_timer_hcd;
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int slot;
struct ptd ptd;
unsigned long spinflags;
spin_lock_irqsave(&priv->lock, spinflags);
- for (slot = 0; slot < 32; slot++)
+ for (slot = 0; slot < mem->slot_num; slot++)
if (priv->atl_slots[slot].qh && time_after(jiffies,
priv->atl_slots[slot].timestamp +
msecs_to_jiffies(SLOT_TIMEOUT))) {
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
if (!FROM_DW0_VALID(ptd.dw0) &&
!FROM_DW3_ACTIVE(ptd.dw3))
priv->atl_done_map |= 1 << slot;
@@ -1286,35 +1579,120 @@ static void errata2_function(struct timer_list *unused)
add_timer(&errata2_timer);
}
+static int isp1763_run(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+ u32 chipid_h;
+ u32 chipid_l;
+ u32 chip_rev;
+ u32 ptd_atl_int;
+ u32 ptd_iso;
+
+ hcd->uses_new_polling = 1;
+ hcd->state = HC_STATE_RUNNING;
+
+ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
+ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
+ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
+ chipid_h, chipid_l, chip_rev);
+
+ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
+ isp1760_hcd_clear(hcd, INT_BUF_FILL);
+ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+ ndelay(100);
+ isp1760_hcd_clear(hcd, HC_ATL_PTD_DONEMAP);
+ isp1760_hcd_clear(hcd, HC_INT_PTD_DONEMAP);
+ isp1760_hcd_clear(hcd, HC_ISO_PTD_DONEMAP);
+
+ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
+ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(7));
+ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(15));
+ mdelay(10);
+
+ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
+
+ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
+
+ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
+
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
+
+ ptd_atl_int = 0x8000;
+ ptd_iso = 0x0001;
+
+ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
+
+ isp1760_hcd_set(hcd, ATL_BUF_FILL);
+ isp1760_hcd_set(hcd, INT_BUF_FILL);
+
+ isp1760_hcd_clear(hcd, CMD_LRESET);
+ isp1760_hcd_clear(hcd, CMD_RESET);
+
+ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+ down_write(&ehci_cf_port_reset_rwsem);
+ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
static int isp1760_run(struct usb_hcd *hcd)
{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
int retval;
- u32 temp;
- u32 command;
- u32 chipid;
+ u32 chipid_h;
+ u32 chipid_l;
+ u32 chip_rev;
+ u32 ptd_atl_int;
+ u32 ptd_iso;
+
+ /*
+ * ISP1763 have some differences in the setup and order to enable
+ * the ports, disable otg, setup buffers, and ATL, INT, ISO status.
+ * So, just handle it a separate sequence.
+ */
+ if (priv->is_isp1763)
+ return isp1763_run(hcd);
hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING;
/* Set PTD interrupt AND & OR maps */
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
+
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
+
/* step 23 passed */
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~(CMD_LRESET|CMD_RESET);
- command |= CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
+ isp1760_hcd_clear(hcd, CMD_LRESET);
+ isp1760_hcd_clear(hcd, CMD_RESET);
- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
if (retval)
return retval;
@@ -1324,9 +1702,8 @@ static int isp1760_run(struct usb_hcd *hcd)
* the semaphore while doing so.
*/
down_write(&ehci_cf_port_reset_rwsem);
- reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
- retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
up_write(&ehci_cf_port_reset_rwsem);
if (retval)
return retval;
@@ -1336,21 +1713,28 @@ static int isp1760_run(struct usb_hcd *hcd)
errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
add_timer(&errata2_timer);
- chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
- chipid & 0xffff, chipid >> 16);
+ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
+ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
+ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
+ chipid_h, chipid_l, chip_rev);
/* PTD Register Init Part 2, Step 28 */
/* Setup registers controlling PTD checking */
- reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
- ATL_BUF_FILL | INT_BUF_FILL);
+ ptd_atl_int = 0x80000000;
+ ptd_iso = 0x00000001;
+
+ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+
+ isp1760_hcd_set(hcd, ATL_BUF_FILL);
+ isp1760_hcd_set(hcd, INT_BUF_FILL);
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
@@ -1363,8 +1747,6 @@ static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
{
qtd->data_buffer = databuffer;
- if (len > MAX_PAYLOAD_SIZE)
- len = MAX_PAYLOAD_SIZE;
qtd->length = len;
return qtd->length;
@@ -1388,6 +1770,8 @@ static void qtd_list_free(struct list_head *qtd_list)
static void packetize_urb(struct usb_hcd *hcd,
struct urb *urb, struct list_head *head, gfp_t flags)
{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
struct isp1760_qtd *qtd;
void *buf;
int len, maxpacketsize;
@@ -1440,6 +1824,10 @@ static void packetize_urb(struct usb_hcd *hcd,
qtd = qtd_alloc(flags, urb, packet_type);
if (!qtd)
goto cleanup;
+
+ if (len > mem->blocks_size[ISP176x_BLOCK_NUM - 1])
+ len = mem->blocks_size[ISP176x_BLOCK_NUM - 1];
+
this_qtd_len = qtd_fill(qtd, buf, len);
list_add_tail(&qtd->qtd_list, head);
@@ -1584,15 +1972,16 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
/* We need to forcefully reclaim the slot since some transfers never
return, e.g. interrupt transfers and NAKed bulk transfers. */
if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
+ ndelay(100);
priv->atl_slots[qh->slot].qh = NULL;
priv->atl_slots[qh->slot].qtd = NULL;
} else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
priv->int_slots[qh->slot].qh = NULL;
priv->int_slots[qh->slot].qtd = NULL;
}
@@ -1705,8 +2094,7 @@ out:
static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp, status = 0;
- u32 mask;
+ u32 status = 0;
int retval = 1;
unsigned long flags;
@@ -1716,17 +2104,13 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
/* init status to no-changes */
buf[0] = 0;
- mask = PORT_CSC;
spin_lock_irqsave(&priv->lock, flags);
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- if (temp & PORT_OWNER) {
- if (temp & PORT_CSC) {
- temp &= ~PORT_CSC;
- reg_write32(hcd->regs, HC_PORTSC1, temp);
- goto done;
- }
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER) &&
+ isp1760_hcd_is_set(hcd, PORT_CSC)) {
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ goto done;
}
/*
@@ -1735,11 +2119,9 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
* high-speed device is switched over to the companion
* controller by the user.
*/
-
- if ((temp & mask) != 0
- || ((temp & PORT_RESUME) != 0
- && time_after_eq(jiffies,
- priv->reset_done))) {
+ if (isp1760_hcd_is_set(hcd, PORT_CSC) ||
+ (isp1760_hcd_is_set(hcd, PORT_RESUME) &&
+ time_after_eq(jiffies, priv->reset_done))) {
buf [0] |= 1 << (0 + 1);
status = STS_PCD;
}
@@ -1752,9 +2134,11 @@ done:
static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
struct usb_hub_descriptor *desc)
{
- int ports = HCS_N_PORTS(priv->hcs_params);
+ int ports;
u16 temp;
+ ports = isp1760_hcd_n_ports(priv->hcd);
+
desc->bDescriptorType = USB_DT_HUB;
/* priv 1.0, 2.3.9 says 20ms max */
desc->bPwrOn2PwrGood = 10;
@@ -1770,7 +2154,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
/* per-port overcurrent reporting */
temp = HUB_CHAR_INDV_PORT_OCPM;
- if (HCS_PPC(priv->hcs_params))
+ if (isp1760_hcd_ppc_is_set(priv->hcd))
/* per-port power control */
temp |= HUB_CHAR_INDV_PORT_LPSM;
else
@@ -1781,38 +2165,37 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-static int check_reset_complete(struct usb_hcd *hcd, int index,
- int port_status)
+static void check_reset_complete(struct usb_hcd *hcd, int index)
{
- if (!(port_status & PORT_CONNECT))
- return port_status;
+ if (!(isp1760_hcd_is_set(hcd, PORT_CONNECT)))
+ return;
/* if reset finished and it's still not enabled -- handoff */
- if (!(port_status & PORT_PE)) {
-
+ if (!isp1760_hcd_is_set(hcd, PORT_PE)) {
dev_info(hcd->self.controller,
- "port %d full speed --> companion\n",
- index + 1);
+ "port %d full speed --> companion\n", index + 1);
- port_status |= PORT_OWNER;
- port_status &= ~PORT_RWC_BITS;
- reg_write32(hcd->regs, HC_PORTSC1, port_status);
+ isp1760_hcd_set(hcd, PORT_OWNER);
- } else
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ } else {
dev_info(hcd->self.controller, "port %d high speed\n",
- index + 1);
+ index + 1);
+ }
- return port_status;
+ return;
}
static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
u16 wValue, u16 wIndex, char *buf, u16 wLength)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int ports = HCS_N_PORTS(priv->hcs_params);
- u32 temp, status;
+ u32 status;
unsigned long flags;
int retval = 0;
+ int ports;
+
+ ports = isp1760_hcd_n_ports(hcd);
/*
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -1837,7 +2220,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
/*
* Even if OWNER is set, so the port is owned by the
@@ -1848,22 +2230,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
+ isp1760_hcd_clear(hcd, PORT_PE);
break;
case USB_PORT_FEAT_C_ENABLE:
/* XXX error? */
break;
case USB_PORT_FEAT_SUSPEND:
- if (temp & PORT_RESET)
+ if (isp1760_hcd_is_set(hcd, PORT_RESET))
goto error;
- if (temp & PORT_SUSPEND) {
- if ((temp & PORT_PE) == 0)
+ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND)) {
+ if (!isp1760_hcd_is_set(hcd, PORT_PE))
goto error;
/* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_RESUME);
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ isp1760_hcd_set(hcd, PORT_RESUME);
+
priv->reset_done = jiffies +
msecs_to_jiffies(USB_RESUME_TIMEOUT);
}
@@ -1872,12 +2254,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
/* we auto-clear this feature */
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~PORT_POWER);
+ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_clear(hcd, PORT_POWER);
break;
case USB_PORT_FEAT_C_CONNECTION:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
+ isp1760_hcd_set(hcd, PORT_CSC);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
/* XXX error ?*/
@@ -1888,7 +2269,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
default:
goto error;
}
- reg_read32(hcd->regs, HC_USBCMD);
+ isp1760_hcd_read(hcd, CMD_RUN);
break;
case GetHubDescriptor:
isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
@@ -1903,15 +2284,13 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
goto error;
wIndex--;
status = 0;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
/* wPortChange bits */
- if (temp & PORT_CSC)
+ if (isp1760_hcd_is_set(hcd, PORT_CSC))
status |= USB_PORT_STAT_C_CONNECTION << 16;
-
/* whoever resumes must GetPortStatus to complete it!! */
- if (temp & PORT_RESUME) {
+ if (isp1760_hcd_is_set(hcd, PORT_RESUME)) {
dev_err(hcd->self.controller, "Port resume should be skipped.\n");
/* Remote Wakeup received? */
@@ -1930,44 +2309,39 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
priv->reset_done = 0;
/* stop resume signaling */
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~(PORT_RWC_BITS | PORT_RESUME));
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESUME, 0, 2000 /* 2msec */);
+ isp1760_hcd_clear(hcd, PORT_CSC);
+
+ retval = isp1760_hcd_clear_and_wait(hcd,
+ PORT_RESUME, 2000);
if (retval != 0) {
dev_err(hcd->self.controller,
"port %d resume error %d\n",
wIndex + 1, retval);
goto error;
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
}
/* whoever resets must GetPortStatus to complete it!! */
- if ((temp & PORT_RESET)
- && time_after_eq(jiffies,
- priv->reset_done)) {
+ if (isp1760_hcd_is_set(hcd, PORT_RESET) &&
+ time_after_eq(jiffies, priv->reset_done)) {
status |= USB_PORT_STAT_C_RESET << 16;
priv->reset_done = 0;
/* force reset to complete */
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESET, 0, 750);
+ retval = isp1760_hcd_clear_and_wait(hcd, PORT_RESET,
+ 750);
if (retval != 0) {
dev_err(hcd->self.controller, "port %d reset error %d\n",
- wIndex + 1, retval);
+ wIndex + 1, retval);
goto error;
}
/* see what we found out */
- temp = check_reset_complete(hcd, wIndex,
- reg_read32(hcd->regs, HC_PORTSC1));
+ check_reset_complete(hcd, wIndex);
}
/*
* Even if OWNER is set, there's no harm letting hub_wq
@@ -1975,21 +2349,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
* for PORT_POWER anyway).
*/
- if (temp & PORT_OWNER)
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
dev_err(hcd->self.controller, "PORT_OWNER is set\n");
- if (temp & PORT_CONNECT) {
+ if (isp1760_hcd_is_set(hcd, PORT_CONNECT)) {
status |= USB_PORT_STAT_CONNECTION;
/* status may be from integrated TT */
status |= USB_PORT_STAT_HIGH_SPEED;
}
- if (temp & PORT_PE)
+ if (isp1760_hcd_is_set(hcd, PORT_PE))
status |= USB_PORT_STAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
+ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND) &&
+ isp1760_hcd_is_set(hcd, PORT_RESUME))
status |= USB_PORT_STAT_SUSPEND;
- if (temp & PORT_RESET)
+ if (isp1760_hcd_is_set(hcd, PORT_RESET))
status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER)
+ if (isp1760_hcd_is_set(hcd, PORT_POWER))
status |= USB_PORT_STAT_POWER;
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
@@ -2009,41 +2384,40 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- if (temp & PORT_OWNER)
+
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
break;
-/* temp &= ~PORT_RWC_BITS; */
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
+ isp1760_hcd_set(hcd, PORT_PE);
break;
case USB_PORT_FEAT_SUSPEND:
- if ((temp & PORT_PE) == 0
- || (temp & PORT_RESET) != 0)
+ if (!isp1760_hcd_is_set(hcd, PORT_PE) ||
+ isp1760_hcd_is_set(hcd, PORT_RESET))
goto error;
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
+ isp1760_hcd_set(hcd, PORT_SUSPEND);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_POWER);
+ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_set(hcd, PORT_POWER);
break;
case USB_PORT_FEAT_RESET:
- if (temp & PORT_RESUME)
+ if (isp1760_hcd_is_set(hcd, PORT_RESUME))
goto error;
/* line status bits may report this as low speed,
* which can be fine if this root hub has a
* transaction translator built in.
*/
- if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
- && PORT_USB11(temp)) {
- temp |= PORT_OWNER;
+ if ((isp1760_hcd_is_set(hcd, PORT_CONNECT) &&
+ !isp1760_hcd_is_set(hcd, PORT_PE)) &&
+ (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) {
+ isp1760_hcd_set(hcd, PORT_OWNER);
} else {
- temp |= PORT_RESET;
- temp &= ~PORT_PE;
+ isp1760_hcd_set(hcd, PORT_RESET);
+ isp1760_hcd_clear(hcd, PORT_PE);
/*
* caller must wait, then call GetPortStatus
@@ -2052,12 +2426,10 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
priv->reset_done = jiffies +
msecs_to_jiffies(50);
}
- reg_write32(hcd->regs, HC_PORTSC1, temp);
break;
default:
goto error;
}
- reg_read32(hcd->regs, HC_USBCMD);
break;
default:
@@ -2074,14 +2446,13 @@ static int isp1760_get_frame(struct usb_hcd *hcd)
struct isp1760_hcd *priv = hcd_to_priv(hcd);
u32 fr;
- fr = reg_read32(hcd->regs, HC_FRINDEX);
+ fr = isp1760_hcd_read(hcd, HC_FRINDEX);
return (fr >> 3) % priv->periodic_size;
}
static void isp1760_stop(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp;
del_timer(&errata2_timer);
@@ -2092,24 +2463,19 @@ static void isp1760_stop(struct usb_hcd *hcd)
spin_lock_irq(&priv->lock);
ehci_reset(hcd);
/* Disable IRQ */
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
spin_unlock_irq(&priv->lock);
- reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
+ isp1760_hcd_clear(hcd, FLAG_CF);
}
static void isp1760_shutdown(struct usb_hcd *hcd)
{
- u32 command, temp;
-
isp1760_stop(hcd);
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
+ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
+
+ isp1760_hcd_clear(hcd, CMD_RUN);
}
static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
@@ -2182,10 +2548,11 @@ void isp1760_deinit_kmem_cache(void)
kmem_cache_destroy(urb_listitem_cachep);
}
-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
- struct resource *mem, int irq, unsigned long irqflags,
+int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ int irq, unsigned long irqflags,
struct device *dev)
{
+ const struct isp1760_memory_layout *mem_layout = priv->memory_layout;
struct usb_hcd *hcd;
int ret;
@@ -2197,10 +2564,23 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
priv->hcd = hcd;
+ priv->atl_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->atl_slots) {
+ ret = -ENOMEM;
+ goto put_hcd;
+ }
+
+ priv->int_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->int_slots) {
+ ret = -ENOMEM;
+ goto free_atl_slots;
+ }
+
init_memory(priv);
hcd->irq = irq;
- hcd->regs = regs;
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
@@ -2209,13 +2589,17 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
ret = usb_add_hcd(hcd, irq, irqflags);
if (ret)
- goto error;
+ goto free_int_slots;
device_wakeup_enable(hcd->self.controller);
return 0;
-error:
+free_int_slots:
+ kfree(priv->int_slots);
+free_atl_slots:
+ kfree(priv->atl_slots);
+put_hcd:
usb_put_hcd(hcd);
return ret;
}
@@ -2227,4 +2611,6 @@ void isp1760_hcd_unregister(struct isp1760_hcd *priv)
usb_remove_hcd(priv->hcd);
usb_put_hcd(priv->hcd);
+ kfree(priv->atl_slots);
+ kfree(priv->int_slots);
}
diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
index f1bb2deb1ccf..ee3063a34de3 100644
--- a/drivers/usb/isp1760/isp1760-hcd.h
+++ b/drivers/usb/isp1760/isp1760-hcd.h
@@ -3,30 +3,15 @@
#define _ISP1760_HCD_H_
#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include "isp1760-regs.h"
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
struct usb_hcd;
-/*
- * 60kb divided in:
- * - 32 blocks @ 256 bytes
- * - 20 blocks @ 1024 bytes
- * - 4 blocks @ 8192 bytes
- */
-
-#define BLOCK_1_NUM 32
-#define BLOCK_2_NUM 20
-#define BLOCK_3_NUM 4
-
-#define BLOCK_1_SIZE 256
-#define BLOCK_2_SIZE 1024
-#define BLOCK_3_SIZE 8192
-#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
-#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
-#define PAYLOAD_AREA_SIZE 0xf000
-
struct isp1760_slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
@@ -34,6 +19,18 @@ struct isp1760_slotinfo {
};
/* chip memory management */
+#define ISP176x_BLOCK_MAX (32 + 20 + 4)
+#define ISP176x_BLOCK_NUM 3
+
+struct isp1760_memory_layout {
+ unsigned int blocks[ISP176x_BLOCK_NUM];
+ unsigned int blocks_size[ISP176x_BLOCK_NUM];
+
+ unsigned int slot_num;
+ unsigned int payload_blocks;
+ unsigned int payload_area_size;
+};
+
struct isp1760_memory_chunk {
unsigned int start;
unsigned int size;
@@ -48,16 +45,22 @@ enum isp1760_queue_head_types {
};
struct isp1760_hcd {
-#ifdef CONFIG_USB_ISP1760_HCD
struct usb_hcd *hcd;
- u32 hcs_params;
+ void __iomem *base;
+
+ struct regmap *regs;
+ struct regmap_field *fields[HC_FIELD_MAX];
+
+ bool is_isp1763;
+ const struct isp1760_memory_layout *memory_layout;
+
spinlock_t lock;
- struct isp1760_slotinfo atl_slots[32];
+ struct isp1760_slotinfo *atl_slots;
int atl_done_map;
- struct isp1760_slotinfo int_slots[32];
+ struct isp1760_slotinfo *int_slots;
int int_done_map;
- struct isp1760_memory_chunk memory_pool[BLOCKS];
+ struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX];
struct list_head qh_list[QH_END];
/* periodic schedule support */
@@ -66,20 +69,18 @@ struct isp1760_hcd {
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
-#endif
};
#ifdef CONFIG_USB_ISP1760_HCD
-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
- struct resource *mem, int irq, unsigned long irqflags,
- struct device *dev);
+int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ int irq, unsigned long irqflags, struct device *dev);
void isp1760_hcd_unregister(struct isp1760_hcd *priv);
int isp1760_init_kmem_once(void);
void isp1760_deinit_kmem_cache(void);
#else
static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
- void __iomem *regs, struct resource *mem,
+ struct resource *mem,
int irq, unsigned long irqflags,
struct device *dev)
{
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
index ccd30f835888..7cc349c0b2ad 100644
--- a/drivers/usb/isp1760/isp1760-if.c
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -7,6 +7,7 @@
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
*
*/
@@ -16,8 +17,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
@@ -75,9 +76,9 @@ static int isp1761_pci_init(struct pci_dev *dev)
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
- writel(0xface, iobase + HC_SCRATCH_REG);
+ writel(0xface, iobase + ISP176x_HC_SCRATCH);
udelay(100);
- reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
+ reg_data = readl(iobase + ISP176x_HC_SCRATCH) & 0x0000ffff;
retry_count--;
}
@@ -209,13 +210,21 @@ static int isp1760_plat_probe(struct platform_device *pdev)
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
- /* Some systems wire up only 16 of the 32 data lines */
+ if (of_device_is_compatible(dp, "nxp,usb-isp1763"))
+ devflags |= ISP1760_FLAG_ISP1763;
+
+ /*
+ * Some systems wire up only 8 of 16 data lines or
+ * 16 of the 32 data lines
+ */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+ else if (bus_width == 8)
+ devflags |= ISP1760_FLAG_BUS_WIDTH_8;
- if (of_property_read_bool(dp, "port1-otg"))
- devflags |= ISP1760_FLAG_OTG_EN;
+ if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL)
+ devflags |= ISP1760_FLAG_PERIPHERAL_EN;
if (of_property_read_bool(dp, "analog-oc"))
devflags |= ISP1760_FLAG_ANALOG_OC;
@@ -225,22 +234,9 @@ static int isp1760_plat_probe(struct platform_device *pdev)
if (of_property_read_bool(dp, "dreq-polarity"))
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
- } else if (dev_get_platdata(&pdev->dev)) {
- struct isp1760_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
-
- if (pdata->is_isp1761)
- devflags |= ISP1760_FLAG_ISP1761;
- if (pdata->bus_width_16)
- devflags |= ISP1760_FLAG_BUS_WIDTH_16;
- if (pdata->port1_otg)
- devflags |= ISP1760_FLAG_OTG_EN;
- if (pdata->analog_oc)
- devflags |= ISP1760_FLAG_ANALOG_OC;
- if (pdata->dack_polarity_high)
- devflags |= ISP1760_FLAG_DACK_POL_HIGH;
- if (pdata->dreq_polarity_high)
- devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+ } else {
+ pr_err("isp1760: no platform data\n");
+ return -ENXIO;
}
ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
@@ -263,6 +259,7 @@ static int isp1760_plat_remove(struct platform_device *pdev)
static const struct of_device_id isp1760_of_match[] = {
{ .compatible = "nxp,usb-isp1760", },
{ .compatible = "nxp,usb-isp1761", },
+ { .compatible = "nxp,usb-isp1763", },
{ },
};
MODULE_DEVICE_TABLE(of, isp1760_of_match);
diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
index fedc4f5cded0..94ea60c20b2a 100644
--- a/drivers/usb/isp1760/isp1760-regs.h
+++ b/drivers/usb/isp1760/isp1760-regs.h
@@ -2,226 +2,291 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
-#ifndef _ISP1760_REGS_H_
-#define _ISP1760_REGS_H_
+#ifndef _ISP176x_REGS_H_
+#define _ISP176x_REGS_H_
/* -----------------------------------------------------------------------------
* Host Controller
*/
+/* ISP1760/31 */
/* EHCI capability registers */
-#define HC_CAPLENGTH 0x000
-#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
+#define ISP176x_HC_VERSION 0x002
+#define ISP176x_HC_HCSPARAMS 0x004
+#define ISP176x_HC_HCCPARAMS 0x008
-#define HC_HCSPARAMS 0x004
-#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
-#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
+/* EHCI operational registers */
+#define ISP176x_HC_USBCMD 0x020
+#define ISP176x_HC_USBSTS 0x024
+#define ISP176x_HC_FRINDEX 0x02c
+
+#define ISP176x_HC_CONFIGFLAG 0x060
+#define ISP176x_HC_PORTSC1 0x064
+
+#define ISP176x_HC_ISO_PTD_DONEMAP 0x130
+#define ISP176x_HC_ISO_PTD_SKIPMAP 0x134
+#define ISP176x_HC_ISO_PTD_LASTPTD 0x138
+#define ISP176x_HC_INT_PTD_DONEMAP 0x140
+#define ISP176x_HC_INT_PTD_SKIPMAP 0x144
+#define ISP176x_HC_INT_PTD_LASTPTD 0x148
+#define ISP176x_HC_ATL_PTD_DONEMAP 0x150
+#define ISP176x_HC_ATL_PTD_SKIPMAP 0x154
+#define ISP176x_HC_ATL_PTD_LASTPTD 0x158
-#define HC_HCCPARAMS 0x008
-#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
+/* Configuration Register */
+#define ISP176x_HC_HW_MODE_CTRL 0x300
+#define ISP176x_HC_CHIP_ID 0x304
+#define ISP176x_HC_SCRATCH 0x308
+#define ISP176x_HC_RESET 0x30c
+#define ISP176x_HC_BUFFER_STATUS 0x334
+#define ISP176x_HC_MEMORY 0x33c
+/* Interrupt Register */
+#define ISP176x_HC_INTERRUPT 0x310
+#define ISP176x_HC_INTERRUPT_ENABLE 0x314
+#define ISP176x_HC_ISO_IRQ_MASK_OR 0x318
+#define ISP176x_HC_INT_IRQ_MASK_OR 0x31c
+#define ISP176x_HC_ATL_IRQ_MASK_OR 0x320
+#define ISP176x_HC_ISO_IRQ_MASK_AND 0x324
+#define ISP176x_HC_INT_IRQ_MASK_AND 0x328
+#define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c
+
+#define ISP176x_HC_OTG_CTRL_SET 0x374
+#define ISP176x_HC_OTG_CTRL_CLEAR 0x376
+
+enum isp176x_host_controller_fields {
+ /* HC_PORTSC1 */
+ PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
+ PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
+ /* HC_HCSPARAMS */
+ HCS_PPC, HCS_N_PORTS,
+ /* HC_HCCPARAMS */
+ HCC_ISOC_CACHE, HCC_ISOC_THRES,
+ /* HC_USBCMD */
+ CMD_LRESET, CMD_RESET, CMD_RUN,
+ /* HC_USBSTS */
+ STS_PCD,
+ /* HC_FRINDEX */
+ HC_FRINDEX,
+ /* HC_CONFIGFLAG */
+ FLAG_CF,
+ /* ISO/INT/ATL PTD */
+ HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD,
+ HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD,
+ HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD,
+ /* HC_HW_MODE_CTRL */
+ ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA,
+ HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT,
+ HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
+ /* HC_CHIP_ID */
+ HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV,
+ /* HC_SCRATCH */
+ HC_SCRATCH,
+ /* HC_RESET */
+ SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
+ /* HC_BUFFER_STATUS */
+ ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL,
+ /* HC_MEMORY */
+ MEM_BANK_SEL, MEM_START_ADDR,
+ /* HC_DATA */
+ HC_DATA,
+ /* HC_INTERRUPT */
+ HC_INTERRUPT,
+ /* HC_INTERRUPT_ENABLE */
+ HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE,
+ /* INTERRUPT MASKS */
+ HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR,
+ HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND,
+ /* HW_OTG_CTRL_SET */
+ HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
+ HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS,
+ /* HW_OTG_CTRL_CLR */
+ HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
+ HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
+ HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR,
+ /* Last element */
+ HC_FIELD_MAX,
+};
+
+/* ISP1763 */
/* EHCI operational registers */
-#define HC_USBCMD 0x020
-#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
-#define CMD_RESET (1 << 1) /* reset HC not bus */
-#define CMD_RUN (1 << 0) /* start/stop HC */
-
-#define HC_USBSTS 0x024
-#define STS_PCD (1 << 2) /* port change detect */
-
-#define HC_FRINDEX 0x02c
-
-#define HC_CONFIGFLAG 0x060
-#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
-
-#define HC_PORTSC1 0x064
-#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
-#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
-#define PORT_RESET (1 << 8) /* reset port */
-#define PORT_SUSPEND (1 << 7) /* suspend port */
-#define PORT_RESUME (1 << 6) /* resume it */
-#define PORT_PE (1 << 2) /* port enable */
-#define PORT_CSC (1 << 1) /* connect status change */
-#define PORT_CONNECT (1 << 0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC)
-
-#define HC_ISO_PTD_DONEMAP_REG 0x130
-#define HC_ISO_PTD_SKIPMAP_REG 0x134
-#define HC_ISO_PTD_LASTPTD_REG 0x138
-#define HC_INT_PTD_DONEMAP_REG 0x140
-#define HC_INT_PTD_SKIPMAP_REG 0x144
-#define HC_INT_PTD_LASTPTD_REG 0x148
-#define HC_ATL_PTD_DONEMAP_REG 0x150
-#define HC_ATL_PTD_SKIPMAP_REG 0x154
-#define HC_ATL_PTD_LASTPTD_REG 0x158
+#define ISP1763_HC_USBCMD 0x8c
+#define ISP1763_HC_USBSTS 0x90
+#define ISP1763_HC_FRINDEX 0x98
+
+#define ISP1763_HC_CONFIGFLAG 0x9c
+#define ISP1763_HC_PORTSC1 0xa0
+
+#define ISP1763_HC_ISO_PTD_DONEMAP 0xa4
+#define ISP1763_HC_ISO_PTD_SKIPMAP 0xa6
+#define ISP1763_HC_ISO_PTD_LASTPTD 0xa8
+#define ISP1763_HC_INT_PTD_DONEMAP 0xaa
+#define ISP1763_HC_INT_PTD_SKIPMAP 0xac
+#define ISP1763_HC_INT_PTD_LASTPTD 0xae
+#define ISP1763_HC_ATL_PTD_DONEMAP 0xb0
+#define ISP1763_HC_ATL_PTD_SKIPMAP 0xb2
+#define ISP1763_HC_ATL_PTD_LASTPTD 0xb4
/* Configuration Register */
-#define HC_HW_MODE_CTRL 0x300
-#define ALL_ATX_RESET (1 << 31)
-#define HW_ANA_DIGI_OC (1 << 15)
-#define HW_DEV_DMA (1 << 11)
-#define HW_COMN_IRQ (1 << 10)
-#define HW_COMN_DMA (1 << 9)
-#define HW_DATA_BUS_32BIT (1 << 8)
-#define HW_DACK_POL_HIGH (1 << 6)
-#define HW_DREQ_POL_HIGH (1 << 5)
-#define HW_INTR_HIGH_ACT (1 << 2)
-#define HW_INTR_EDGE_TRIG (1 << 1)
-#define HW_GLOBAL_INTR_EN (1 << 0)
-
-#define HC_CHIP_ID_REG 0x304
-#define HC_SCRATCH_REG 0x308
-
-#define HC_RESET_REG 0x30c
-#define SW_RESET_RESET_HC (1 << 1)
-#define SW_RESET_RESET_ALL (1 << 0)
-
-#define HC_BUFFER_STATUS_REG 0x334
-#define ISO_BUF_FILL (1 << 2)
-#define INT_BUF_FILL (1 << 1)
-#define ATL_BUF_FILL (1 << 0)
-
-#define HC_MEMORY_REG 0x33c
-#define ISP_BANK(x) ((x) << 16)
-
-#define HC_PORT1_CTRL 0x374
-#define PORT1_POWER (3 << 3)
-#define PORT1_INIT1 (1 << 7)
-#define PORT1_INIT2 (1 << 23)
-#define HW_OTG_CTRL_SET 0x374
-#define HW_OTG_CTRL_CLR 0x376
-#define HW_OTG_DISABLE (1 << 10)
-#define HW_OTG_SE0_EN (1 << 9)
-#define HW_BDIS_ACON_EN (1 << 8)
-#define HW_SW_SEL_HC_DC (1 << 7)
-#define HW_VBUS_CHRG (1 << 6)
-#define HW_VBUS_DISCHRG (1 << 5)
-#define HW_VBUS_DRV (1 << 4)
-#define HW_SEL_CP_EXT (1 << 3)
-#define HW_DM_PULLDOWN (1 << 2)
-#define HW_DP_PULLDOWN (1 << 1)
-#define HW_DP_PULLUP (1 << 0)
+#define ISP1763_HC_HW_MODE_CTRL 0xb6
+#define ISP1763_HC_CHIP_REV 0x70
+#define ISP1763_HC_CHIP_ID 0x72
+#define ISP1763_HC_SCRATCH 0x78
+#define ISP1763_HC_RESET 0xb8
+#define ISP1763_HC_BUFFER_STATUS 0xba
+#define ISP1763_HC_MEMORY 0xc4
+#define ISP1763_HC_DATA 0xc6
/* Interrupt Register */
-#define HC_INTERRUPT_REG 0x310
-
-#define HC_INTERRUPT_ENABLE 0x314
-#define HC_ISO_INT (1 << 9)
-#define HC_ATL_INT (1 << 8)
-#define HC_INTL_INT (1 << 7)
-#define HC_EOT_INT (1 << 3)
-#define HC_SOT_INT (1 << 1)
-#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
-
-#define HC_ISO_IRQ_MASK_OR_REG 0x318
-#define HC_INT_IRQ_MASK_OR_REG 0x31c
-#define HC_ATL_IRQ_MASK_OR_REG 0x320
-#define HC_ISO_IRQ_MASK_AND_REG 0x324
-#define HC_INT_IRQ_MASK_AND_REG 0x328
-#define HC_ATL_IRQ_MASK_AND_REG 0x32c
+#define ISP1763_HC_INTERRUPT 0xd4
+#define ISP1763_HC_INTERRUPT_ENABLE 0xd6
+#define ISP1763_HC_ISO_IRQ_MASK_OR 0xd8
+#define ISP1763_HC_INT_IRQ_MASK_OR 0xda
+#define ISP1763_HC_ATL_IRQ_MASK_OR 0xdc
+#define ISP1763_HC_ISO_IRQ_MASK_AND 0xde
+#define ISP1763_HC_INT_IRQ_MASK_AND 0xe0
+#define ISP1763_HC_ATL_IRQ_MASK_AND 0xe2
+
+#define ISP1763_HC_OTG_CTRL_SET 0xe4
+#define ISP1763_HC_OTG_CTRL_CLEAR 0xe6
/* -----------------------------------------------------------------------------
* Peripheral Controller
*/
-/* Initialization Registers */
-#define DC_ADDRESS 0x0200
-#define DC_DEVEN (1 << 7)
-
-#define DC_MODE 0x020c
-#define DC_DMACLKON (1 << 9)
-#define DC_VBUSSTAT (1 << 8)
-#define DC_CLKAON (1 << 7)
-#define DC_SNDRSU (1 << 6)
-#define DC_GOSUSP (1 << 5)
-#define DC_SFRESET (1 << 4)
-#define DC_GLINTENA (1 << 3)
-#define DC_WKUPCS (1 << 2)
-
-#define DC_INTCONF 0x0210
-#define DC_CDBGMOD_ACK_NAK (0 << 6)
-#define DC_CDBGMOD_ACK (1 << 6)
-#define DC_CDBGMOD_ACK_1NAK (2 << 6)
-#define DC_DDBGMODIN_ACK_NAK (0 << 4)
-#define DC_DDBGMODIN_ACK (1 << 4)
-#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
-#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
-#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
-#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
-#define DC_INTLVL (1 << 1)
-#define DC_INTPOL (1 << 0)
-
-#define DC_DEBUG 0x0212
-#define DC_INTENABLE 0x0214
#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
-#define DC_IEP0SETUP (1 << 8)
-#define DC_IEVBUS (1 << 7)
-#define DC_IEDMA (1 << 6)
-#define DC_IEHS_STA (1 << 5)
-#define DC_IERESM (1 << 4)
-#define DC_IESUSP (1 << 3)
-#define DC_IEPSOF (1 << 2)
-#define DC_IESOF (1 << 1)
-#define DC_IEBRST (1 << 0)
+
+#define ISP176x_DC_CDBGMOD_ACK BIT(6)
+#define ISP176x_DC_DDBGMODIN_ACK BIT(4)
+#define ISP176x_DC_DDBGMODOUT_ACK BIT(2)
+
+#define ISP176x_DC_IEP0SETUP BIT(8)
+#define ISP176x_DC_IEVBUS BIT(7)
+#define ISP176x_DC_IEHS_STA BIT(5)
+#define ISP176x_DC_IERESM BIT(4)
+#define ISP176x_DC_IESUSP BIT(3)
+#define ISP176x_DC_IEBRST BIT(0)
+
+#define ISP176x_DC_ENDPTYP_ISOC 0x01
+#define ISP176x_DC_ENDPTYP_BULK 0x02
+#define ISP176x_DC_ENDPTYP_INTERRUPT 0x03
+
+/* Initialization Registers */
+#define ISP176x_DC_ADDRESS 0x0200
+#define ISP176x_DC_MODE 0x020c
+#define ISP176x_DC_INTCONF 0x0210
+#define ISP176x_DC_DEBUG 0x0212
+#define ISP176x_DC_INTENABLE 0x0214
+
+/* Data Flow Registers */
+#define ISP176x_DC_EPMAXPKTSZ 0x0204
+#define ISP176x_DC_EPTYPE 0x0208
+
+#define ISP176x_DC_BUFLEN 0x021c
+#define ISP176x_DC_BUFSTAT 0x021e
+#define ISP176x_DC_DATAPORT 0x0220
+
+#define ISP176x_DC_CTRLFUNC 0x0228
+#define ISP176x_DC_EPINDEX 0x022c
+
+/* DMA Registers */
+#define ISP176x_DC_DMACMD 0x0230
+#define ISP176x_DC_DMATXCOUNT 0x0234
+#define ISP176x_DC_DMACONF 0x0238
+#define ISP176x_DC_DMAHW 0x023c
+#define ISP176x_DC_DMAINTREASON 0x0250
+#define ISP176x_DC_DMAINTEN 0x0254
+#define ISP176x_DC_DMAEP 0x0258
+#define ISP176x_DC_DMABURSTCOUNT 0x0264
+
+/* General Registers */
+#define ISP176x_DC_INTERRUPT 0x0218
+#define ISP176x_DC_CHIPID 0x0270
+#define ISP176x_DC_FRAMENUM 0x0274
+#define ISP176x_DC_SCRATCH 0x0278
+#define ISP176x_DC_UNLOCKDEV 0x027c
+#define ISP176x_DC_INTPULSEWIDTH 0x0280
+#define ISP176x_DC_TESTMODE 0x0284
+
+enum isp176x_device_controller_fields {
+ /* DC_ADDRESS */
+ DC_DEVEN, DC_DEVADDR,
+ /* DC_MODE */
+ DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA,
+ /* DC_INTCONF */
+ DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL,
+ /* DC_INTENABLE */
+ DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3,
+ DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0,
+ DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST,
+ /* DC_EPINDEX */
+ DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR,
+ /* DC_CTRLFUNC */
+ DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL,
+ /* DC_BUFLEN */
+ DC_BUFLEN,
+ /* DC_EPMAXPKTSZ */
+ DC_FFOSZ,
+ /* DC_EPTYPE */
+ DC_EPENABLE, DC_ENDPTYP,
+ /* DC_FRAMENUM */
+ DC_FRAMENUM, DC_UFRAMENUM,
+ /* DC_CHIP_ID */
+ DC_CHIP_ID_HIGH, DC_CHIP_ID_LOW,
+ /* DC_SCRATCH */
+ DC_SCRATCH,
+ /* Last element */
+ DC_FIELD_MAX,
+};
+
+/* ISP1763 */
+/* Initialization Registers */
+#define ISP1763_DC_ADDRESS 0x00
+#define ISP1763_DC_MODE 0x0c
+#define ISP1763_DC_INTCONF 0x10
+#define ISP1763_DC_INTENABLE 0x14
/* Data Flow Registers */
-#define DC_EPINDEX 0x022c
-#define DC_EP0SETUP (1 << 5)
-#define DC_ENDPIDX(n) ((n) << 1)
-#define DC_EPDIR (1 << 0)
-
-#define DC_CTRLFUNC 0x0228
-#define DC_CLBUF (1 << 4)
-#define DC_VENDP (1 << 3)
-#define DC_DSEN (1 << 2)
-#define DC_STATUS (1 << 1)
-#define DC_STALL (1 << 0)
-
-#define DC_DATAPORT 0x0220
-#define DC_BUFLEN 0x021c
-#define DC_DATACOUNT_MASK 0xffff
-#define DC_BUFSTAT 0x021e
-#define DC_EPMAXPKTSZ 0x0204
-
-#define DC_EPTYPE 0x0208
-#define DC_NOEMPKT (1 << 4)
-#define DC_EPENABLE (1 << 3)
-#define DC_DBLBUF (1 << 2)
-#define DC_ENDPTYP_ISOC (1 << 0)
-#define DC_ENDPTYP_BULK (2 << 0)
-#define DC_ENDPTYP_INTERRUPT (3 << 0)
+#define ISP1763_DC_EPMAXPKTSZ 0x04
+#define ISP1763_DC_EPTYPE 0x08
+
+#define ISP1763_DC_BUFLEN 0x1c
+#define ISP1763_DC_BUFSTAT 0x1e
+#define ISP1763_DC_DATAPORT 0x20
+
+#define ISP1763_DC_CTRLFUNC 0x28
+#define ISP1763_DC_EPINDEX 0x2c
/* DMA Registers */
-#define DC_DMACMD 0x0230
-#define DC_DMATXCOUNT 0x0234
-#define DC_DMACONF 0x0238
-#define DC_DMAHW 0x023c
-#define DC_DMAINTREASON 0x0250
-#define DC_DMAINTEN 0x0254
-#define DC_DMAEP 0x0258
-#define DC_DMABURSTCOUNT 0x0264
+#define ISP1763_DC_DMACMD 0x30
+#define ISP1763_DC_DMATXCOUNT 0x34
+#define ISP1763_DC_DMACONF 0x38
+#define ISP1763_DC_DMAHW 0x3c
+#define ISP1763_DC_DMAINTREASON 0x50
+#define ISP1763_DC_DMAINTEN 0x54
+#define ISP1763_DC_DMAEP 0x58
+#define ISP1763_DC_DMABURSTCOUNT 0x64
/* General Registers */
-#define DC_INTERRUPT 0x0218
-#define DC_CHIPID 0x0270
-#define DC_FRAMENUM 0x0274
-#define DC_SCRATCH 0x0278
-#define DC_UNLOCKDEV 0x027c
-#define DC_INTPULSEWIDTH 0x0280
-#define DC_TESTMODE 0x0284
+#define ISP1763_DC_INTERRUPT 0x18
+#define ISP1763_DC_CHIPID_LOW 0x70
+#define ISP1763_DC_CHIPID_HIGH 0x72
+#define ISP1763_DC_FRAMENUM 0x74
+#define ISP1763_DC_SCRATCH 0x78
+#define ISP1763_DC_UNLOCKDEV 0x7c
+#define ISP1763_DC_INTPULSEWIDTH 0x80
+#define ISP1763_DC_TESTMODE 0x84
#endif
diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
index 1714b2258b54..a78da59d6417 100644
--- a/drivers/usb/isp1760/isp1760-udc.c
+++ b/drivers/usb/isp1760/isp1760-udc.c
@@ -2,10 +2,12 @@
/*
* Driver for the NXP ISP1761 device controller
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#include <linux/interrupt.h>
@@ -45,16 +47,62 @@ static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
return container_of(req, struct isp1760_request, req);
}
-static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
+static u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field)
{
- return isp1760_read32(udc->regs, reg);
+ return isp1760_field_read(udc->fields, field);
}
-static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
+static void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val)
{
- isp1760_write32(udc->regs, reg, val);
+ isp1760_field_write(udc->fields, field, val);
}
+static u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg)
+{
+ __le32 val;
+
+ regmap_raw_read(udc->regs, reg, &val, 4);
+
+ return le32_to_cpu(val);
+}
+
+static u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg)
+{
+ __le16 val;
+
+ regmap_raw_read(udc->regs, reg, &val, 2);
+
+ return le16_to_cpu(val);
+}
+
+static void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val)
+{
+ __le32 val_le = cpu_to_le32(val);
+
+ regmap_raw_write(udc->regs, reg, &val_le, 4);
+}
+
+static void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val)
+{
+ __le16 val_le = cpu_to_le16(val);
+
+ regmap_raw_write(udc->regs, reg, &val_le, 2);
+}
+
+static void isp1760_udc_set(struct isp1760_udc *udc, u32 field)
+{
+ isp1760_udc_write(udc, field, 0xFFFFFFFF);
+}
+
+static void isp1760_udc_clear(struct isp1760_udc *udc, u32 field)
+{
+ isp1760_udc_write(udc, field, 0);
+}
+
+static bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field)
+{
+ return !!isp1760_udc_read(udc, field);
+}
/* -----------------------------------------------------------------------------
* Endpoint Management
*/
@@ -75,16 +123,21 @@ static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
return NULL;
}
-static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
+static void __isp1760_udc_select_ep(struct isp1760_udc *udc,
+ struct isp1760_ep *ep, int dir)
{
- isp1760_udc_write(ep->udc, DC_EPINDEX,
- DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
- (dir == USB_DIR_IN ? DC_EPDIR : 0));
+ isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK);
+
+ if (dir == USB_DIR_IN)
+ isp1760_udc_set(udc, DC_EPDIR);
+ else
+ isp1760_udc_clear(udc, DC_EPDIR);
}
/**
* isp1760_udc_select_ep - Select an endpoint for register access
* @ep: The endpoint
+ * @udc: Reference to the device controller
*
* The ISP1761 endpoint registers are banked. This function selects the target
* endpoint for banked register access. The selection remains valid until the
@@ -93,9 +146,10 @@ static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
*
* Called with the UDC spinlock held.
*/
-static void isp1760_udc_select_ep(struct isp1760_ep *ep)
+static void isp1760_udc_select_ep(struct isp1760_udc *udc,
+ struct isp1760_ep *ep)
{
- __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
+ __isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK);
}
/* Called with the UDC spinlock held. */
@@ -108,9 +162,13 @@ static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
* the direction opposite to the data stage data packets, we thus need
* to select the OUT/IN endpoint for IN/OUT transfers.
*/
- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
- (dir == USB_DIR_IN ? 0 : DC_EPDIR));
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
+ if (dir == USB_DIR_IN)
+ isp1760_udc_clear(udc, DC_EPDIR);
+ else
+ isp1760_udc_set(udc, DC_EPDIR);
+
+ isp1760_udc_write(udc, DC_ENDPIDX, 1);
+ isp1760_udc_set(udc, DC_STATUS);
/*
* The hardware will terminate the request automatically and go back to
@@ -157,10 +215,10 @@ static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
spin_lock_irqsave(&udc->lock, flags);
/* Stall both the IN and OUT endpoints. */
- __isp1760_udc_select_ep(ep, USB_DIR_OUT);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_OUT);
+ isp1760_udc_set(udc, DC_STALL);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
+ isp1760_udc_set(udc, DC_STALL);
/* A protocol stall completes the control transaction. */
udc->ep0_state = ISP1760_CTRL_SETUP;
@@ -181,8 +239,8 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
u32 *buf;
int i;
- isp1760_udc_select_ep(ep);
- len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+ isp1760_udc_select_ep(udc, ep);
+ len = isp1760_udc_read(udc, DC_BUFLEN);
dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
__func__, len, req->req.actual, req->req.length);
@@ -198,7 +256,7 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
* datasheet doesn't clearly document how this should be
* handled.
*/
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
return false;
}
@@ -209,9 +267,9 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
* the next packet might be removed from the FIFO.
*/
for (i = len; i > 2; i -= 4, ++buf)
- *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
+ *buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
if (i > 0)
- *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
+ *(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT);
req->req.actual += len;
@@ -253,7 +311,7 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
__func__, req->packet_size, req->req.actual,
req->req.length);
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
if (req->packet_size)
isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
@@ -265,14 +323,14 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
* the FIFO for this kind of conditions, but doesn't seem to work.
*/
for (i = req->packet_size; i > 2; i -= 4, ++buf)
- isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
+ isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf);
if (i > 0)
- writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
+ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf);
if (ep->addr == 0)
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ isp1760_udc_set(udc, DC_DSEN);
if (!req->packet_size)
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
+ isp1760_udc_set(udc, DC_VENDP);
}
static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
@@ -408,19 +466,24 @@ static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
return -EINVAL;
}
- isp1760_udc_select_ep(ep);
- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+ isp1760_udc_select_ep(udc, ep);
+
+ if (halt)
+ isp1760_udc_set(udc, DC_STALL);
+ else
+ isp1760_udc_clear(udc, DC_STALL);
if (ep->addr == 0) {
/* When halting the control endpoint, stall both IN and OUT. */
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
+ if (halt)
+ isp1760_udc_set(udc, DC_STALL);
+ else
+ isp1760_udc_clear(udc, DC_STALL);
} else if (!halt) {
/* Reset the data PID by cycling the endpoint enable bit. */
- u16 eptype = isp1760_udc_read(udc, DC_EPTYPE);
-
- isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE);
- isp1760_udc_write(udc, DC_EPTYPE, eptype);
+ isp1760_udc_clear(udc, DC_EPENABLE);
+ isp1760_udc_set(udc, DC_EPENABLE);
/*
* Disabling the endpoint emptied the transmit FIFO, fill it
@@ -479,12 +542,14 @@ static int isp1760_udc_get_status(struct isp1760_udc *udc,
return -EINVAL;
}
- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR);
+ isp1760_udc_set(udc, DC_EPDIR);
+ isp1760_udc_write(udc, DC_ENDPIDX, 1);
+
isp1760_udc_write(udc, DC_BUFLEN, 2);
- writew(cpu_to_le16(status), udc->regs + DC_DATAPORT);
+ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ isp1760_udc_set(udc, DC_DSEN);
dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
@@ -508,7 +573,8 @@ static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
USB_STATE_DEFAULT);
- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr);
+ isp1760_udc_write(udc, DC_DEVADDR, addr);
+ isp1760_udc_set(udc, DC_DEVEN);
spin_lock(&udc->lock);
isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
@@ -650,9 +716,9 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
spin_lock(&udc->lock);
- isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP);
+ isp1760_udc_set(udc, DC_EP0SETUP);
- count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+ count = isp1760_udc_read(udc, DC_BUFLEN);
if (count != sizeof(req)) {
spin_unlock(&udc->lock);
@@ -663,8 +729,8 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
return;
}
- req.data[0] = isp1760_udc_read(udc, DC_DATAPORT);
- req.data[1] = isp1760_udc_read(udc, DC_DATAPORT);
+ req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
+ req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
if (udc->ep0_state != ISP1760_CTRL_SETUP) {
spin_unlock(&udc->lock);
@@ -732,13 +798,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_ISOC:
- type = DC_ENDPTYP_ISOC;
+ type = ISP176x_DC_ENDPTYP_ISOC;
break;
case USB_ENDPOINT_XFER_BULK:
- type = DC_ENDPTYP_BULK;
+ type = ISP176x_DC_ENDPTYP_BULK;
break;
case USB_ENDPOINT_XFER_INT:
- type = DC_ENDPTYP_INTERRUPT;
+ type = ISP176x_DC_ENDPTYP_INTERRUPT;
break;
case USB_ENDPOINT_XFER_CONTROL:
default:
@@ -755,10 +821,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
uep->halted = false;
uep->wedged = false;
- isp1760_udc_select_ep(uep);
- isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket);
+ isp1760_udc_select_ep(udc, uep);
+
+ isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket);
isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
- isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type);
+
+ isp1760_udc_write(udc, DC_ENDPTYP, type);
+ isp1760_udc_set(udc, DC_EPENABLE);
spin_unlock_irqrestore(&udc->lock, flags);
@@ -786,8 +855,9 @@ static int isp1760_ep_disable(struct usb_ep *ep)
uep->desc = NULL;
uep->maxpacket = 0;
- isp1760_udc_select_ep(uep);
- isp1760_udc_write(udc, DC_EPTYPE, 0);
+ isp1760_udc_select_ep(udc, uep);
+ isp1760_udc_clear(udc, DC_EPENABLE);
+ isp1760_udc_clear(udc, DC_ENDPTYP);
/* TODO Synchronize with the IRQ handler */
@@ -864,8 +934,8 @@ static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
case ISP1760_CTRL_DATA_OUT:
list_add_tail(&req->queue, &uep->queue);
- __isp1760_udc_select_ep(uep, USB_DIR_OUT);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ __isp1760_udc_select_ep(udc, uep, USB_DIR_OUT);
+ isp1760_udc_set(udc, DC_DSEN);
break;
case ISP1760_CTRL_STATUS:
@@ -1025,14 +1095,14 @@ static void isp1760_ep_fifo_flush(struct usb_ep *ep)
spin_lock_irqsave(&udc->lock, flags);
- isp1760_udc_select_ep(uep);
+ isp1760_udc_select_ep(udc, uep);
/*
* Set the CLBUF bit twice to flush both buffers in case double
* buffering is enabled.
*/
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
spin_unlock_irqrestore(&udc->lock, flags);
}
@@ -1082,6 +1152,10 @@ static void isp1760_udc_disconnect(struct isp1760_udc *udc)
static void isp1760_udc_init_hw(struct isp1760_udc *udc)
{
+ u32 intconf = udc->is_isp1763 ? ISP1763_DC_INTCONF : ISP176x_DC_INTCONF;
+ u32 intena = udc->is_isp1763 ? ISP1763_DC_INTENABLE :
+ ISP176x_DC_INTENABLE;
+
/*
* The device controller currently shares its interrupt with the host
* controller, the DC_IRQ polarity and signaling mode are ignored. Set
@@ -1091,19 +1165,22 @@ static void isp1760_udc_init_hw(struct isp1760_udc *udc)
* ACK tokens only (and NYET for the out pipe). The default
* configuration also generates an interrupt on the first NACK token.
*/
- isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK |
- DC_DDBGMODOUT_ACK_NYET);
-
- isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) |
- DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) |
- DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) |
- DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP |
- DC_IEHS_STA | DC_IEBRST);
+ isp1760_reg_write(udc->regs, intconf,
+ ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK |
+ ISP176x_DC_DDBGMODOUT_ACK);
+
+ isp1760_reg_write(udc->regs, intena, DC_IEPRXTX(7) |
+ DC_IEPRXTX(6) | DC_IEPRXTX(5) | DC_IEPRXTX(4) |
+ DC_IEPRXTX(3) | DC_IEPRXTX(2) | DC_IEPRXTX(1) |
+ DC_IEPRXTX(0) | ISP176x_DC_IEP0SETUP |
+ ISP176x_DC_IEVBUS | ISP176x_DC_IERESM |
+ ISP176x_DC_IESUSP | ISP176x_DC_IEHS_STA |
+ ISP176x_DC_IEBRST);
if (udc->connected)
isp1760_set_pullup(udc->isp, true);
- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN);
+ isp1760_udc_set(udc, DC_DEVEN);
}
static void isp1760_udc_reset(struct isp1760_udc *udc)
@@ -1152,7 +1229,7 @@ static int isp1760_udc_get_frame(struct usb_gadget *gadget)
{
struct isp1760_udc *udc = gadget_to_udc(gadget);
- return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1);
+ return isp1760_udc_read(udc, DC_FRAMENUM);
}
static int isp1760_udc_wakeup(struct usb_gadget *gadget)
@@ -1219,7 +1296,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
/* DMA isn't supported yet, don't enable the DMA clock. */
- isp1760_udc_write(udc, DC_MODE, DC_GLINTENA);
+ isp1760_udc_set(udc, DC_GLINTENA);
isp1760_udc_init_hw(udc);
@@ -1232,13 +1309,14 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
static int isp1760_udc_stop(struct usb_gadget *gadget)
{
struct isp1760_udc *udc = gadget_to_udc(gadget);
+ u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
unsigned long flags;
dev_dbg(udc->isp->dev, "%s\n", __func__);
del_timer_sync(&udc->vbus_timer);
- isp1760_udc_write(udc, DC_MODE, 0);
+ isp1760_reg_write(udc->regs, mode_reg, 0);
spin_lock_irqsave(&udc->lock, flags);
udc->driver = NULL;
@@ -1260,15 +1338,30 @@ static const struct usb_gadget_ops isp1760_udc_ops = {
* Interrupt Handling
*/
+static u32 isp1760_udc_irq_get_status(struct isp1760_udc *udc)
+{
+ u32 status;
+
+ if (udc->is_isp1763) {
+ status = isp1760_reg_read(udc->regs, ISP1763_DC_INTERRUPT)
+ & isp1760_reg_read(udc->regs, ISP1763_DC_INTENABLE);
+ isp1760_reg_write(udc->regs, ISP1763_DC_INTERRUPT, status);
+ } else {
+ status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT)
+ & isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE);
+ isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status);
+ }
+
+ return status;
+}
+
static irqreturn_t isp1760_udc_irq(int irq, void *dev)
{
struct isp1760_udc *udc = dev;
unsigned int i;
u32 status;
- status = isp1760_udc_read(udc, DC_INTERRUPT)
- & isp1760_udc_read(udc, DC_INTENABLE);
- isp1760_udc_write(udc, DC_INTERRUPT, status);
+ status = isp1760_udc_irq_get_status(udc);
if (status & DC_IEVBUS) {
dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
@@ -1313,7 +1406,7 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev)
dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
spin_lock(&udc->lock);
- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ if (!isp1760_udc_is_set(udc, DC_VBUSSTAT))
isp1760_udc_disconnect(udc);
else
isp1760_udc_suspend(udc);
@@ -1335,7 +1428,7 @@ static void isp1760_udc_vbus_poll(struct timer_list *t)
spin_lock_irqsave(&udc->lock, flags);
- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT)))
isp1760_udc_disconnect(udc);
else if (udc->gadget.state >= USB_STATE_POWERED)
mod_timer(&udc->vbus_timer,
@@ -1403,6 +1496,7 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc)
static int isp1760_udc_init(struct isp1760_udc *udc)
{
+ u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
u16 scratch;
u32 chipid;
@@ -1413,7 +1507,8 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
* and scratch register contents must match the expected values.
*/
isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
- chipid = isp1760_udc_read(udc, DC_CHIPID);
+ chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16;
+ chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW);
scratch = isp1760_udc_read(udc, DC_SCRATCH);
if (scratch != 0xbabe) {
@@ -1423,15 +1518,16 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
return -ENODEV;
}
- if (chipid != 0x00011582 && chipid != 0x00158210) {
+ if (chipid != 0x00011582 && chipid != 0x00158210 &&
+ chipid != 0x00176320) {
dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
return -ENODEV;
}
/* Reset the device controller. */
- isp1760_udc_write(udc, DC_MODE, DC_SFRESET);
+ isp1760_udc_set(udc, DC_SFRESET);
usleep_range(10000, 11000);
- isp1760_udc_write(udc, DC_MODE, 0);
+ isp1760_reg_write(udc->regs, mode_reg, 0);
usleep_range(10000, 11000);
return 0;
@@ -1445,7 +1541,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
udc->irq = -1;
udc->isp = isp;
- udc->regs = isp->regs;
spin_lock_init(&udc->lock);
timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0);
diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h
index d2df650d54e9..22044e86bc0e 100644
--- a/drivers/usb/isp1760/isp1760-udc.h
+++ b/drivers/usb/isp1760/isp1760-udc.h
@@ -2,10 +2,12 @@
/*
* Driver for the NXP ISP1761 device controller
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP1760_UDC_H_
@@ -17,6 +19,8 @@
#include <linux/timer.h>
#include <linux/usb/gadget.h>
+#include "isp1760-regs.h"
+
struct isp1760_device;
struct isp1760_udc;
@@ -48,7 +52,7 @@ struct isp1760_ep {
* struct isp1760_udc - UDC state information
* irq: IRQ number
* irqname: IRQ name (as passed to request_irq)
- * regs: Base address of the UDC registers
+ * regs: regmap for UDC registers
* driver: Gadget driver
* gadget: Gadget device
* lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
@@ -59,12 +63,13 @@ struct isp1760_ep {
* connected: Tracks gadget driver bus connection state
*/
struct isp1760_udc {
-#ifdef CONFIG_USB_ISP1761_UDC
struct isp1760_device *isp;
int irq;
char *irqname;
- void __iomem *regs;
+
+ struct regmap *regs;
+ struct regmap_field *fields[DC_FIELD_MAX];
struct usb_gadget_driver *driver;
struct usb_gadget gadget;
@@ -79,9 +84,9 @@ struct isp1760_udc {
u16 ep0_length;
bool connected;
+ bool is_isp1763;
unsigned int devstatus;
-#endif
};
#ifdef CONFIG_USB_ISP1761_UDC
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 8a3d9c0c8d8b..e5a8fcdbb78e 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2098,7 +2098,6 @@ more:{
} else
d += sprintf(d, " ..");
bytes_read += 1;
- continue;
}
goto more;
} else if (packet_bytes > 1) {
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index aef0a0bba25a..5546b868b08b 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -10,6 +10,7 @@
#ifndef __MTU3_H__
#define __MTU3_H__
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/extcon.h>
@@ -21,6 +22,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
+#include <linux/usb/role.h>
struct mtu3;
struct mtu3_ep;
@@ -88,6 +90,8 @@ struct mtu3_request;
*/
#define EP0_RESPONSE_BUF 6
+#define BULK_CLKS_CNT 4
+
/* device operated link and speed got from DEVICE_CONF register */
enum mtu3_speed {
MTU3_SPEED_INACTIVE = 0,
@@ -192,13 +196,9 @@ struct mtu3_gpd_ring {
/**
* @vbus: vbus 5V used by host mode
* @edev: external connector used to detect vbus and iddig changes
-* @vbus_nb: notifier for vbus detection
-* @vbus_work : work of vbus detection notifier, used to avoid sleep in
-* notifier callback which is atomic context
-* @vbus_event : event of vbus detecion notifier
* @id_nb : notifier for iddig(idpin) detection
-* @id_work : work of iddig detection notifier
-* @id_event : event of iddig detecion notifier
+* @dr_work : work for drd mode switch, used to avoid sleep in atomic context
+* @desired_role : role desired to switch
* @role_sw : use USB Role Switch to support dual-role switch, can't use
* extcon at the same time, and extcon is deprecated.
* @role_sw_used : true when the USB Role Switch is used.
@@ -209,12 +209,9 @@ struct mtu3_gpd_ring {
struct otg_switch_mtk {
struct regulator *vbus;
struct extcon_dev *edev;
- struct notifier_block vbus_nb;
- struct work_struct vbus_work;
- unsigned long vbus_event;
struct notifier_block id_nb;
- struct work_struct id_work;
- unsigned long id_event;
+ struct work_struct dr_work;
+ enum usb_role desired_role;
struct usb_role_switch *role_sw;
bool role_sw_used;
bool is_u3_drd;
@@ -225,10 +222,6 @@ struct otg_switch_mtk {
* @mac_base: register base address of device MAC, exclude xHCI's
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
- * @sys_clk: system clock of mtu3, shared by device/host IP
- * @ref_clk: reference clock
- * @mcu_clk: mcu_bus_ck clock for AHB bus etc
- * @dma_clk: dma_bus_ck clock for AXI bus etc
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
@@ -250,10 +243,7 @@ struct ssusb_mtk {
int num_phys;
/* common power & clock */
struct regulator *vusb33;
- struct clk *sys_clk;
- struct clk *ref_clk;
- struct clk *mcu_clk;
- struct clk *dma_clk;
+ struct clk_bulk_data clks[BULK_CLKS_CNT];
/* otg */
struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
@@ -422,11 +412,9 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
int interval, int burst, int mult);
void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep);
void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set);
-void mtu3_ep0_setup(struct mtu3 *mtu);
void mtu3_start(struct mtu3 *mtu);
void mtu3_stop(struct mtu3 *mtu);
void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
-void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed);
int mtu3_gadget_setup(struct mtu3 *mtu);
void mtu3_gadget_cleanup(struct mtu3 *mtu);
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index b3b459937566..562f4357831e 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -207,7 +207,7 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
}
-void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
+static void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
{
void __iomem *mbase = mtu->mac_base;
@@ -334,6 +334,10 @@ void mtu3_start(struct mtu3 *mtu)
mtu3_readl(mbase, U3D_DEVICE_CONTROL));
mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+ if (mtu->is_u3_ip)
+ mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN);
+
+ mtu3_clrbits(mtu->ippc_base, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN);
mtu3_csr_init(mtu);
mtu3_set_speed(mtu, mtu->speed);
@@ -356,6 +360,11 @@ void mtu3_stop(struct mtu3 *mtu)
mtu3_dev_on_off(mtu, 0);
mtu->is_active = 0;
+
+ if (mtu->is_u3_ip)
+ mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN);
+
+ mtu3_setbits(mtu->ippc_base, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN);
mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
}
@@ -536,7 +545,7 @@ static void get_ep_fifo_config(struct mtu3 *mtu)
rx_fifo->base, rx_fifo->limit);
}
-void mtu3_ep0_setup(struct mtu3 *mtu)
+static void mtu3_ep0_setup(struct mtu3 *mtu)
{
u32 maxpacket = mtu->g.ep0->maxpacket;
u32 csr;
@@ -921,16 +930,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
device_init_wakeup(dev, true);
+ /* power down device IP for power saving by default */
+ mtu3_stop(mtu);
+
ret = mtu3_gadget_setup(mtu);
if (ret) {
dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
goto gadget_err;
}
- /* init as host mode, power down device IP for power saving */
- if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
- mtu3_stop(mtu);
-
ssusb_dev_debugfs_init(ssusb);
dev_dbg(dev, " %s() done...\n", __func__);
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index 7537bfd651af..d27de647c86a 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -30,6 +30,7 @@ static const struct debugfs_reg32 mtu3_ippc_regs[] = {
dump_register(SSUSB_IP_PW_CTRL1),
dump_register(SSUSB_IP_PW_CTRL2),
dump_register(SSUSB_IP_PW_CTRL3),
+ dump_register(SSUSB_IP_PW_STS1),
dump_register(SSUSB_OTG_STS),
dump_register(SSUSB_IP_XHCI_CAP),
dump_register(SSUSB_IP_DEV_CAP),
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 04f666e85731..318fbc618137 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -7,8 +7,6 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
-#include <linux/usb/role.h>
-
#include "mtu3.h"
#include "mtu3_dr.h"
#include "mtu3_debug.h"
@@ -16,27 +14,9 @@
#define USB2_PORT 2
#define USB3_PORT 3
-enum mtu3_vbus_id_state {
- MTU3_ID_FLOAT = 1,
- MTU3_ID_GROUND,
- MTU3_VBUS_OFF,
- MTU3_VBUS_VALID,
-};
-
-static char *mailbox_state_string(enum mtu3_vbus_id_state state)
+static inline struct ssusb_mtk *otg_sx_to_ssusb(struct otg_switch_mtk *otg_sx)
{
- switch (state) {
- case MTU3_ID_FLOAT:
- return "ID_FLOAT";
- case MTU3_ID_GROUND:
- return "ID_GROUND";
- case MTU3_VBUS_OFF:
- return "VBUS_OFF";
- case MTU3_VBUS_VALID:
- return "VBUS_VALID";
- default:
- return "UNKNOWN";
- }
+ return container_of(otg_sx, struct ssusb_mtk, otg_switch);
}
static void toggle_opstate(struct ssusb_mtk *ssusb)
@@ -123,8 +103,7 @@ static void switch_port_to_device(struct ssusb_mtk *ssusb)
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct regulator *vbus = otg_sx->vbus;
int ret;
@@ -147,99 +126,72 @@ int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
return 0;
}
-/*
- * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
- * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
- */
-static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
- enum mtu3_vbus_id_state status)
+static void ssusb_mode_sw_work(struct work_struct *work)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct otg_switch_mtk *otg_sx =
+ container_of(work, struct otg_switch_mtk, dr_work);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct mtu3 *mtu = ssusb->u3d;
+ enum usb_role desired_role = otg_sx->desired_role;
+ enum usb_role current_role;
+
+ current_role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+
+ if (desired_role == USB_ROLE_NONE)
+ desired_role = USB_ROLE_HOST;
- dev_dbg(ssusb->dev, "mailbox %s\n", mailbox_state_string(status));
- mtu3_dbg_trace(ssusb->dev, "mailbox %s", mailbox_state_string(status));
+ if (current_role == desired_role)
+ return;
+
+ dev_dbg(ssusb->dev, "set role : %s\n", usb_role_string(desired_role));
+ mtu3_dbg_trace(ssusb->dev, "set role : %s", usb_role_string(desired_role));
- switch (status) {
- case MTU3_ID_GROUND:
+ switch (desired_role) {
+ case USB_ROLE_HOST:
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ mtu3_stop(mtu);
switch_port_to_host(ssusb);
ssusb_set_vbus(otg_sx, 1);
ssusb->is_host = true;
break;
- case MTU3_ID_FLOAT:
+ case USB_ROLE_DEVICE:
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
ssusb->is_host = false;
ssusb_set_vbus(otg_sx, 0);
switch_port_to_device(ssusb);
- break;
- case MTU3_VBUS_OFF:
- mtu3_stop(mtu);
- pm_relax(ssusb->dev);
- break;
- case MTU3_VBUS_VALID:
- /* avoid suspend when works as device */
- pm_stay_awake(ssusb->dev);
mtu3_start(mtu);
break;
+ case USB_ROLE_NONE:
default:
- dev_err(ssusb->dev, "invalid state\n");
+ dev_err(ssusb->dev, "invalid role\n");
}
}
-static void ssusb_id_work(struct work_struct *work)
+static void ssusb_set_mode(struct otg_switch_mtk *otg_sx, enum usb_role role)
{
- struct otg_switch_mtk *otg_sx =
- container_of(work, struct otg_switch_mtk, id_work);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
- if (otg_sx->id_event)
- ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
- else
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
-}
-
-static void ssusb_vbus_work(struct work_struct *work)
-{
- struct otg_switch_mtk *otg_sx =
- container_of(work, struct otg_switch_mtk, vbus_work);
+ if (ssusb->dr_mode != USB_DR_MODE_OTG)
+ return;
- if (otg_sx->vbus_event)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- else
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ otg_sx->desired_role = role;
+ queue_work(system_freezable_wq, &otg_sx->dr_work);
}
-/*
- * @ssusb_id_notifier is called in atomic context, but @ssusb_set_mailbox
- * may sleep, so use work queue here
- */
static int ssusb_id_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct otg_switch_mtk *otg_sx =
container_of(nb, struct otg_switch_mtk, id_nb);
- otg_sx->id_event = event;
- schedule_work(&otg_sx->id_work);
-
- return NOTIFY_DONE;
-}
-
-static int ssusb_vbus_notifier(struct notifier_block *nb,
- unsigned long event, void *ptr)
-{
- struct otg_switch_mtk *otg_sx =
- container_of(nb, struct otg_switch_mtk, vbus_nb);
-
- otg_sx->vbus_event = event;
- schedule_work(&otg_sx->vbus_work);
+ ssusb_set_mode(otg_sx, event ? USB_ROLE_HOST : USB_ROLE_DEVICE);
return NOTIFY_DONE;
}
static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct extcon_dev *edev = otg_sx->edev;
int ret;
@@ -247,14 +199,6 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
if (!edev)
return 0;
- otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
- ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
- &otg_sx->vbus_nb);
- if (ret < 0) {
- dev_err(ssusb->dev, "failed to register notifier for USB\n");
- return ret;
- }
-
otg_sx->id_nb.notifier_call = ssusb_id_notifier;
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
&otg_sx->id_nb);
@@ -263,15 +207,12 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
return ret;
}
- dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
- extcon_get_state(edev, EXTCON_USB),
- extcon_get_state(edev, EXTCON_USB_HOST));
+ ret = extcon_get_state(edev, EXTCON_USB_HOST);
+ dev_dbg(ssusb->dev, "EXTCON_USB_HOST: %d\n", ret);
/* default as host, switch to device mode if needed */
- if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
- if (extcon_get_state(edev, EXTCON_USB) == true)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ if (!ret)
+ ssusb_set_mode(otg_sx, USB_ROLE_DEVICE);
return 0;
}
@@ -286,15 +227,7 @@ void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host) {
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
- ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
- } else {
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- }
+ ssusb_set_mode(otg_sx, to_host ? USB_ROLE_HOST : USB_ROLE_DEVICE);
}
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
@@ -323,13 +256,9 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
{
struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
- bool to_host = false;
-
- if (role == USB_ROLE_HOST)
- to_host = true;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host ^ ssusb->is_host)
- ssusb_mode_switch(ssusb, to_host);
+ ssusb_set_mode(otg_sx, role);
return 0;
}
@@ -337,18 +266,14 @@ static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
static enum usb_role ssusb_role_sw_get(struct usb_role_switch *sw)
{
struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
- enum usb_role role;
-
- role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
- return role;
+ return ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
}
static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
{
struct usb_role_switch_desc role_sx_desc = { 0 };
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
if (!otg_sx->role_sw_used)
return 0;
@@ -367,8 +292,7 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
int ret = 0;
- INIT_WORK(&otg_sx->id_work, ssusb_id_work);
- INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work);
+ INIT_WORK(&otg_sx->dr_work, ssusb_mode_sw_work);
if (otg_sx->manual_drd_enabled)
ssusb_dr_debugfs_init(ssusb);
@@ -384,7 +308,6 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- cancel_work_sync(&otg_sx->id_work);
- cancel_work_sync(&otg_sx->vbus_work);
+ cancel_work_sync(&otg_sx->dr_work);
usb_role_switch_unregister(otg_sx->role_sw);
}
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 38f17d66d5bc..5e21ba05ebf0 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -577,7 +577,7 @@ mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
dev_dbg(mtu->dev, "%s %s\n", __func__, usb_speed_string(speed));
spin_lock_irqsave(&mtu->lock, flags);
- mtu3_set_speed(mtu, speed);
+ mtu->speed = speed;
spin_unlock_irqrestore(&mtu->lock, flags);
}
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index 0a8cd446cf1b..93a1a4c11e1e 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -213,8 +213,6 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
static void ssusb_host_setup(struct ssusb_mtk *ssusb)
{
- struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
-
host_ports_num_get(ssusb);
/*
@@ -222,9 +220,7 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
* if support OTG, gadget driver will switch port0 to device mode
*/
ssusb_host_enable(ssusb);
-
- if (otg_sx->manual_drd_enabled)
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
/* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1);
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 7786a95a874e..c0615f6e5cce 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -5,7 +5,6 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
-#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
@@ -101,54 +100,6 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
phy_power_off(ssusb->phys[i]);
}
-static int ssusb_clks_enable(struct ssusb_mtk *ssusb)
-{
- int ret;
-
- ret = clk_prepare_enable(ssusb->sys_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable sys_clk\n");
- goto sys_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->ref_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable ref_clk\n");
- goto ref_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->mcu_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable mcu_clk\n");
- goto mcu_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->dma_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable dma_clk\n");
- goto dma_clk_err;
- }
-
- return 0;
-
-dma_clk_err:
- clk_disable_unprepare(ssusb->mcu_clk);
-mcu_clk_err:
- clk_disable_unprepare(ssusb->ref_clk);
-ref_clk_err:
- clk_disable_unprepare(ssusb->sys_clk);
-sys_clk_err:
- return ret;
-}
-
-static void ssusb_clks_disable(struct ssusb_mtk *ssusb)
-{
- clk_disable_unprepare(ssusb->dma_clk);
- clk_disable_unprepare(ssusb->mcu_clk);
- clk_disable_unprepare(ssusb->ref_clk);
- clk_disable_unprepare(ssusb->sys_clk);
-}
-
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
{
int ret = 0;
@@ -159,7 +110,7 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
goto vusb33_err;
}
- ret = ssusb_clks_enable(ssusb);
+ ret = clk_bulk_prepare_enable(BULK_CLKS_CNT, ssusb->clks);
if (ret)
goto clks_err;
@@ -180,7 +131,7 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err:
ssusb_phy_exit(ssusb);
phy_init_err:
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
clks_err:
regulator_disable(ssusb->vusb33);
vusb33_err:
@@ -189,7 +140,7 @@ vusb33_err:
static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
{
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
regulator_disable(ssusb->vusb33);
ssusb_phy_power_off(ssusb);
ssusb_phy_exit(ssusb);
@@ -215,6 +166,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ struct clk_bulk_data *clks = ssusb->clks;
struct device *dev = &pdev->dev;
int i;
int ret;
@@ -225,23 +177,13 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->vusb33);
}
- ssusb->sys_clk = devm_clk_get(dev, "sys_ck");
- if (IS_ERR(ssusb->sys_clk)) {
- dev_err(dev, "failed to get sys clock\n");
- return PTR_ERR(ssusb->sys_clk);
- }
-
- ssusb->ref_clk = devm_clk_get_optional(dev, "ref_ck");
- if (IS_ERR(ssusb->ref_clk))
- return PTR_ERR(ssusb->ref_clk);
-
- ssusb->mcu_clk = devm_clk_get_optional(dev, "mcu_ck");
- if (IS_ERR(ssusb->mcu_clk))
- return PTR_ERR(ssusb->mcu_clk);
-
- ssusb->dma_clk = devm_clk_get_optional(dev, "dma_ck");
- if (IS_ERR(ssusb->dma_clk))
- return PTR_ERR(ssusb->dma_clk);
+ clks[0].id = "sys_ck";
+ clks[1].id = "ref_ck";
+ clks[2].id = "mcu_ck";
+ clks[3].id = "dma_ck";
+ ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks);
+ if (ret)
+ return ret;
ssusb->num_phys = of_count_phandle_with_args(node,
"phys", "#phy-cells");
@@ -299,11 +241,14 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
of_property_read_bool(node, "enable-manual-drd");
otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch");
- if (!otg_sx->role_sw_used && of_property_read_bool(node, "extcon")) {
+ if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled)
+ goto out;
+
+ if (of_property_read_bool(node, "extcon")) {
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) {
- dev_err(ssusb->dev, "couldn't get extcon device\n");
- return PTR_ERR(otg_sx->edev);
+ return dev_err_probe(dev, PTR_ERR(otg_sx->edev),
+ "couldn't get extcon device\n");
}
}
@@ -461,7 +406,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
ssusb_host_disable(ssusb, true);
ssusb_phy_power_off(ssusb);
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
ssusb_wakeup_set(ssusb, true);
return 0;
@@ -478,7 +423,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0;
ssusb_wakeup_set(ssusb, false);
- ret = ssusb_clks_enable(ssusb);
+ ret = clk_bulk_prepare_enable(BULK_CLKS_CNT, ssusb->clks);
if (ret)
goto clks_err;
@@ -491,7 +436,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0;
phy_err:
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
clks_err:
return ret;
}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4c8f0112481f..f7b1d5993f8c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -480,9 +480,7 @@ int musb_set_host(struct musb *musb)
devctl = musb_read_devctl(musb);
if (!(devctl & MUSB_DEVCTL_BDEVICE)) {
- dev_info(musb->controller,
- "%s: already in host mode: %02x\n",
- __func__, devctl);
+ trace_musb_state(musb, devctl, "Already in host mode");
goto init_data;
}
@@ -499,6 +497,9 @@ int musb_set_host(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Host mode set");
+
init_data:
musb->is_active = 1;
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
@@ -526,10 +527,7 @@ int musb_set_peripheral(struct musb *musb)
devctl = musb_read_devctl(musb);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- dev_info(musb->controller,
- "%s: already in peripheral mode: %02x\n",
- __func__, devctl);
-
+ trace_musb_state(musb, devctl, "Already in peripheral mode");
goto init_data;
}
@@ -546,6 +544,9 @@ int musb_set_peripheral(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Peripheral mode set");
+
init_data:
musb->is_active = 0;
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
@@ -1984,6 +1985,21 @@ ATTRIBUTE_GROUPS(musb);
#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION)
+static bool musb_state_needs_recheck(struct musb *musb, u8 devctl,
+ const char *desc)
+{
+ if (musb->quirk_retries && !musb->flush_irq_work) {
+ trace_musb_state(musb, devctl, desc);
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(1000));
+ musb->quirk_retries--;
+
+ return true;
+ }
+
+ return false;
+}
+
/*
* Check the musb devctl session bit to determine if we want to
* allow PM runtime for the device. In general, we want to keep things
@@ -2004,35 +2020,21 @@ static void musb_pm_runtime_check_session(struct musb *musb)
MUSB_DEVCTL_HR;
switch (devctl & ~s) {
case MUSB_QUIRK_B_DISCONNECT_99:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
- }
+ musb_state_needs_recheck(musb, devctl,
+ "Poll devctl in case of suspend after disconnect");
break;
case MUSB_QUIRK_B_INVALID_VBUS_91:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on invalid vbus, assume no session");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on invalid vbus, assume no session"))
return;
- }
fallthrough;
case MUSB_QUIRK_A_DISCONNECT_19:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on possible host mode disconnect");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on possible host mode disconnect"))
return;
- }
if (!musb->session)
break;
- musb_dbg(musb, "Allow PM on possible host mode disconnect");
+ trace_musb_state(musb, devctl, "Allow PM on possible host mode disconnect");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
musb->session = false;
@@ -2048,14 +2050,23 @@ static void musb_pm_runtime_check_session(struct musb *musb)
/* Block PM or allow PM? */
if (s) {
- musb_dbg(musb, "Block PM on active session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Block PM on active session");
error = pm_runtime_get_sync(musb->controller);
if (error < 0)
dev_err(musb->controller, "Could not enable: %i\n",
error);
musb->quirk_retries = 3;
+
+ /*
+ * We can get a spurious MUSB_INTR_SESSREQ interrupt on start-up
+ * in B-peripheral mode with nothing connected and the session
+ * bit clears silently. Check status again in 3 seconds.
+ */
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(3000));
} else {
- musb_dbg(musb, "Allow PM with no session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Allow PM with no session");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
}
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ef374d4dd94a..98c0f4c1bffd 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -611,7 +611,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* mode 0 only. So we do not get endpoint interrupts due to DMA
* completion. We only get interrupts from DMA controller.
*
- * We could operate in DMA mode 1 if we knew the size of the tranfer
+ * We could operate in DMA mode 1 if we knew the size of the transfer
* in advance. For mass storage class, request->length = what the host
* sends, so that'd work. But for pretty much everything else,
* request->length is routinely more than what the host sends. For
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 30c5e7de0761..9ff7d891b4b7 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -563,10 +563,9 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
ep->rx_reinit = 0;
}
-static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
- struct musb_hw_ep *hw_ep, struct musb_qh *qh,
- struct urb *urb, u32 offset,
- u32 *length, u8 *mode)
+static void musb_tx_dma_set_mode_mentor(struct musb_hw_ep *hw_ep,
+ struct musb_qh *qh,
+ u32 *length, u8 *mode)
{
struct dma_channel *channel = hw_ep->tx_channel;
void __iomem *epio = hw_ep->regs;
@@ -602,12 +601,8 @@ static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
musb_writew(epio, MUSB_TXCSR, csr);
}
-static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
- struct musb_hw_ep *hw_ep,
- struct musb_qh *qh,
+static void musb_tx_dma_set_mode_cppi_tusb(struct musb_hw_ep *hw_ep,
struct urb *urb,
- u32 offset,
- u32 *length,
u8 *mode)
{
struct dma_channel *channel = hw_ep->tx_channel;
@@ -630,11 +625,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
u8 mode;
if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb))
- musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset,
+ musb_tx_dma_set_mode_mentor(hw_ep, qh,
&length, &mode);
else if (is_cppi_enabled(hw_ep->musb) || tusb_dma_omap(hw_ep->musb))
- musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, offset,
- &length, &mode);
+ musb_tx_dma_set_mode_cppi_tusb(hw_ep, urb, &mode);
else
return false;
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
index 4804d4d85c15..63298bd233e0 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -61,10 +61,6 @@ extern void musb_host_tx(struct musb *, u8);
extern void musb_host_rx(struct musb *, u8);
extern void musb_root_disconnect(struct musb *musb);
extern void musb_host_free(struct musb *);
-extern void musb_host_cleanup(struct musb *);
-extern void musb_host_tx(struct musb *, u8);
-extern void musb_host_rx(struct musb *, u8);
-extern void musb_root_disconnect(struct musb *musb);
extern void musb_host_resume_root_hub(struct musb *musb);
extern void musb_host_poke_root_hub(struct musb *musb);
extern int musb_port_suspend(struct musb *musb, bool do_suspend);
diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h
index 380ebc77eab1..ec28b5716796 100644
--- a/drivers/usb/musb/musb_trace.h
+++ b/drivers/usb/musb/musb_trace.h
@@ -37,6 +37,23 @@ TRACE_EVENT(musb_log,
TP_printk("%s: %s", __get_str(name), __get_str(msg))
);
+TRACE_EVENT(musb_state,
+ TP_PROTO(struct musb *musb, u8 devctl, const char *desc),
+ TP_ARGS(musb, devctl, desc),
+ TP_STRUCT__entry(
+ __string(name, dev_name(musb->controller))
+ __field(u8, devctl)
+ __string(desc, desc)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(musb->controller));
+ __entry->devctl = devctl;
+ __assign_str(desc, desc);
+ ),
+ TP_printk("%s: devctl: %02x %s", __get_str(name), __entry->devctl,
+ __get_str(desc))
+);
+
DECLARE_EVENT_CLASS(musb_regb,
TP_PROTO(void *caller, const void __iomem *addr,
unsigned int offset, u8 data),
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 4232f1ce3fbf..640a46f0d118 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -33,6 +33,8 @@ struct omap2430_glue {
enum musb_vbus_id_status status;
struct work_struct omap_musb_mailbox_work;
struct device *control_otghs;
+ unsigned int is_runtime_suspended:1;
+ unsigned int needs_resume:1;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
@@ -459,6 +461,8 @@ static int omap2430_runtime_suspend(struct device *dev)
phy_power_off(musb->phy);
phy_exit(musb->phy);
+ glue->is_runtime_suspended = 1;
+
return 0;
}
@@ -480,12 +484,40 @@ static int omap2430_runtime_resume(struct device *dev)
/* Wait for musb to get oriented. Otherwise we can get babble */
usleep_range(200000, 250000);
+ glue->is_runtime_suspended = 0;
+
return 0;
}
+static int omap2430_suspend(struct device *dev)
+{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+
+ if (glue->is_runtime_suspended)
+ return 0;
+
+ glue->needs_resume = 1;
+
+ return omap2430_runtime_suspend(dev);
+}
+
+static int omap2430_resume(struct device *dev)
+{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+
+ if (!glue->needs_resume)
+ return 0;
+
+ glue->needs_resume = 0;
+
+ return omap2430_runtime_resume(dev);
+}
+
static const struct dev_pm_ops omap2430_pm_ops = {
.runtime_suspend = omap2430_runtime_suspend,
.runtime_resume = omap2430_runtime_resume,
+ .suspend = omap2430_suspend,
+ .resume = omap2430_resume,
};
#define DEV_PM_OPS (&omap2430_pm_ops)
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 02bb7ddd4bd6..f3e9b3b6ac3e 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -555,7 +555,7 @@ pullup:
case OTG_STATE_A_PERIPHERAL:
if (otg_ctrl & OTG_PULLUP)
goto pullup;
- /* FALLTHROUGH */
+ fallthrough;
// case OTG_STATE_B_WAIT_ACON:
default:
pulldown:
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
index 6cf6fbd39237..ad3d57f1c273 100644
--- a/drivers/usb/phy/phy-isp1301.c
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -142,24 +142,17 @@ static struct i2c_driver isp1301_driver = {
module_i2c_driver(isp1301_driver);
-static int match(struct device *dev, const void *data)
-{
- const struct device_node *node = (const struct device_node *)data;
- return (dev->of_node == node) &&
- (dev->driver == &isp1301_driver.driver);
-}
-
struct i2c_client *isp1301_get_client(struct device_node *node)
{
- if (node) { /* reference of ISP1301 I2C node via DT */
- struct device *dev = bus_find_device(&i2c_bus_type, NULL,
- node, match);
- if (!dev)
- return NULL;
- return to_i2c_client(dev);
- } else { /* non-DT: only one ISP1301 chip supported */
- return isp1301_i2c_client;
- }
+ struct i2c_client *client;
+
+ /* reference of ISP1301 I2C node via DT */
+ client = of_find_i2c_device_by_node(node);
+ if (client)
+ return client;
+
+ /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
}
EXPORT_SYMBOL_GPL(isp1301_get_client);
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index a48452a6172b..c0f432d509aa 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -58,12 +58,12 @@
#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
#define USB_PHY_VBUS_SENSORS 0x404
-#define B_SESS_VLD_WAKEUP_EN BIT(6)
-#define B_VBUS_VLD_WAKEUP_EN BIT(14)
+#define B_SESS_VLD_WAKEUP_EN BIT(14)
#define A_SESS_VLD_WAKEUP_EN BIT(22)
#define A_VBUS_VLD_WAKEUP_EN BIT(30)
#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VBUS_WAKEUP_STS BIT(10)
#define VBUS_WAKEUP_WAKEUP_EN BIT(30)
#define USB1_LEGACY_CTRL 0x410
@@ -544,7 +544,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN);
- val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN);
+ val &= ~(B_SESS_VLD_WAKEUP_EN);
writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
@@ -642,6 +642,15 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
void __iomem *base = phy->regs;
u32 val;
+ /*
+ * Give hardware time to settle down after VBUS disconnection,
+ * otherwise PHY will immediately wake up from suspend.
+ */
+ if (phy->wakeup_enabled && phy->mode != USB_DR_MODE_HOST)
+ readl_relaxed_poll_timeout(base + USB_PHY_VBUS_WAKEUP_ID,
+ val, !(val & VBUS_WAKEUP_STS),
+ 5000, 100000);
+
utmi_phy_clk_disable(phy);
/* PHY won't resume if reset is asserted */
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index b47285f023cf..83ed5089475a 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -42,6 +42,12 @@ static const char *const usb_chger_type[] = {
[ACA_TYPE] = "USB_CHARGER_ACA_TYPE",
};
+static const char *const usb_chger_state[] = {
+ [USB_CHARGER_DEFAULT] = "USB_CHARGER_DEFAULT",
+ [USB_CHARGER_PRESENT] = "USB_CHARGER_PRESENT",
+ [USB_CHARGER_ABSENT] = "USB_CHARGER_ABSENT",
+};
+
static struct usb_phy *__usb_find_phy(struct list_head *list,
enum usb_phy_type type)
{
@@ -74,6 +80,18 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
return ERR_PTR(-EPROBE_DEFER);
}
+static struct usb_phy *__device_to_usb_phy(struct device *dev)
+{
+ struct usb_phy *usb_phy;
+
+ list_for_each_entry(usb_phy, &phy_list, head) {
+ if (usb_phy->dev == dev)
+ break;
+ }
+
+ return usb_phy;
+}
+
static void usb_phy_set_default_current(struct usb_phy *usb_phy)
{
usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN;
@@ -105,9 +123,6 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy)
static void usb_phy_notify_charger_work(struct work_struct *work)
{
struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work);
- char uchger_state[50] = { 0 };
- char uchger_type[50] = { 0 };
- char *envp[] = { uchger_state, uchger_type, NULL };
unsigned int min, max;
switch (usb_phy->chg_state) {
@@ -115,15 +130,11 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
usb_phy_get_charger_current(usb_phy, &min, &max);
atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy);
- snprintf(uchger_state, ARRAY_SIZE(uchger_state),
- "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT");
break;
case USB_CHARGER_ABSENT:
usb_phy_set_default_current(usb_phy);
atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy);
- snprintf(uchger_state, ARRAY_SIZE(uchger_state),
- "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT");
break;
default:
dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n",
@@ -131,9 +142,30 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
return;
}
+ kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE);
+}
+
+static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_phy *usb_phy;
+ char uchger_state[50] = { 0 };
+ char uchger_type[50] = { 0 };
+
+ usb_phy = __device_to_usb_phy(dev);
+
+ snprintf(uchger_state, ARRAY_SIZE(uchger_state),
+ "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]);
+
snprintf(uchger_type, ARRAY_SIZE(uchger_type),
"USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]);
- kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp);
+
+ if (add_uevent_var(env, uchger_state))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, uchger_type))
+ return -ENOMEM;
+
+ return 0;
}
static void __usb_phy_get_charger_type(struct usb_phy *usb_phy)
@@ -661,6 +693,11 @@ out:
}
EXPORT_SYMBOL_GPL(usb_add_phy);
+static struct device_type usb_phy_dev_type = {
+ .name = "usb_phy",
+ .uevent = usb_phy_uevent,
+};
+
/**
* usb_add_phy_dev - declare the USB PHY
* @x: the USB phy to be used; or NULL
@@ -684,6 +721,8 @@ int usb_add_phy_dev(struct usb_phy *x)
if (ret)
return ret;
+ x->dev->type = &usb_phy_dev_type;
+
ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
spin_lock_irqsave(&phy_lock, flags);
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index 33b637d0d8d9..dfaed7eee94f 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -214,6 +214,15 @@ static const char * const usb_roles[] = {
[USB_ROLE_DEVICE] = "device",
};
+const char *usb_role_string(enum usb_role role)
+{
+ if (role < 0 || role >= ARRAY_SIZE(usb_roles))
+ return "unknown";
+
+ return usb_roles[role];
+}
+EXPORT_SYMBOL_GPL(usb_role_string);
+
static ssize_t
role_show(struct device *dev, struct device_attribute *attr, char *buf)
{
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fcb812bc832c..09b845d0da41 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -247,9 +247,9 @@ struct cp210x_serial_private {
#ifdef CONFIG_GPIOLIB
struct gpio_chip gc;
bool gpio_registered;
- u8 gpio_pushpull;
- u8 gpio_altfunc;
- u8 gpio_input;
+ u16 gpio_pushpull;
+ u16 gpio_altfunc;
+ u16 gpio_input;
#endif
u8 partnum;
u32 fw_version;
@@ -534,6 +534,48 @@ struct cp210x_single_port_config {
#define CP2104_GPIO1_RXLED_MODE BIT(1)
#define CP2104_GPIO2_RS485_MODE BIT(2)
+struct cp210x_quad_port_state {
+ __le16 gpio_mode_pb0;
+ __le16 gpio_mode_pb1;
+ __le16 gpio_mode_pb2;
+ __le16 gpio_mode_pb3;
+ __le16 gpio_mode_pb4;
+
+ __le16 gpio_lowpower_pb0;
+ __le16 gpio_lowpower_pb1;
+ __le16 gpio_lowpower_pb2;
+ __le16 gpio_lowpower_pb3;
+ __le16 gpio_lowpower_pb4;
+
+ __le16 gpio_latch_pb0;
+ __le16 gpio_latch_pb1;
+ __le16 gpio_latch_pb2;
+ __le16 gpio_latch_pb3;
+ __le16 gpio_latch_pb4;
+};
+
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0x49 bytes
+ * on a CP2108 chip.
+ *
+ * See https://www.silabs.com/documents/public/application-notes/an978-cp210x-usb-to-uart-api-specification.pdf
+ */
+struct cp210x_quad_port_config {
+ struct cp210x_quad_port_state reset_state;
+ struct cp210x_quad_port_state suspend_state;
+ u8 ipdelay_ifc[4];
+ u8 enhancedfxn_ifc[4];
+ u8 enhancedfxn_device;
+ u8 extclkfreq[4];
+} __packed;
+
+#define CP2108_EF_IFC_GPIO_TXLED 0x01
+#define CP2108_EF_IFC_GPIO_RXLED 0x02
+#define CP2108_EF_IFC_GPIO_RS485 0x04
+#define CP2108_EF_IFC_GPIO_RS485_LOGIC 0x08
+#define CP2108_EF_IFC_GPIO_CLOCK 0x10
+#define CP2108_EF_IFC_DYNAMIC_SUSPEND 0x40
+
/* CP2102N configuration array indices */
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2
#define CP210X_2NCONFIG_GPIO_MODE_IDX 581
@@ -546,13 +588,25 @@ struct cp210x_single_port_config {
#define CP2102N_QFN20_GPIO1_RS485_MODE BIT(4)
#define CP2102N_QFN20_GPIO0_CLK_MODE BIT(6)
-/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x02 bytes
+ * for CP2102N, CP2103, CP2104 and CP2105.
+ */
struct cp210x_gpio_write {
u8 mask;
u8 state;
};
/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x04 bytes
+ * for CP2108.
+ */
+struct cp210x_gpio_write16 {
+ __le16 mask;
+ __le16 state;
+};
+
+/*
* Helper to get interface number when we only have struct usb_serial.
*/
static u8 cp210x_interface_num(struct usb_serial *serial)
@@ -1434,52 +1488,84 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct usb_serial *serial = gpiochip_get_data(gc);
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
- u8 req_type = REQTYPE_DEVICE_TO_HOST;
+ u8 req_type;
+ u16 mask;
int result;
- u8 buf;
-
- if (priv->partnum == CP210X_PARTNUM_CP2105)
- req_type = REQTYPE_INTERFACE_TO_HOST;
+ int len;
result = usb_autopm_get_interface(serial->interface);
if (result)
return result;
- result = cp210x_read_vendor_block(serial, req_type,
- CP210X_READ_LATCH, &buf, sizeof(buf));
+ switch (priv->partnum) {
+ case CP210X_PARTNUM_CP2105:
+ req_type = REQTYPE_INTERFACE_TO_HOST;
+ len = 1;
+ break;
+ case CP210X_PARTNUM_CP2108:
+ req_type = REQTYPE_INTERFACE_TO_HOST;
+ len = 2;
+ break;
+ default:
+ req_type = REQTYPE_DEVICE_TO_HOST;
+ len = 1;
+ break;
+ }
+
+ mask = 0;
+ result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH,
+ &mask, len);
+
usb_autopm_put_interface(serial->interface);
+
if (result < 0)
return result;
- return !!(buf & BIT(gpio));
+ le16_to_cpus(&mask);
+
+ return !!(mask & BIT(gpio));
}
static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct usb_serial *serial = gpiochip_get_data(gc);
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct cp210x_gpio_write16 buf16;
struct cp210x_gpio_write buf;
+ u16 mask, state;
+ u16 wIndex;
int result;
if (value == 1)
- buf.state = BIT(gpio);
+ state = BIT(gpio);
else
- buf.state = 0;
+ state = 0;
- buf.mask = BIT(gpio);
+ mask = BIT(gpio);
result = usb_autopm_get_interface(serial->interface);
if (result)
goto out;
- if (priv->partnum == CP210X_PARTNUM_CP2105) {
+ switch (priv->partnum) {
+ case CP210X_PARTNUM_CP2105:
+ buf.mask = (u8)mask;
+ buf.state = (u8)state;
result = cp210x_write_vendor_block(serial,
REQTYPE_HOST_TO_INTERFACE,
CP210X_WRITE_LATCH, &buf,
sizeof(buf));
- } else {
- u16 wIndex = buf.state << 8 | buf.mask;
-
+ break;
+ case CP210X_PARTNUM_CP2108:
+ buf16.mask = cpu_to_le16(mask);
+ buf16.state = cpu_to_le16(state);
+ result = cp210x_write_vendor_block(serial,
+ REQTYPE_HOST_TO_INTERFACE,
+ CP210X_WRITE_LATCH, &buf16,
+ sizeof(buf16));
+ break;
+ default:
+ wIndex = state << 8 | mask;
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
CP210X_VENDOR_SPECIFIC,
@@ -1487,6 +1573,7 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
CP210X_WRITE_LATCH,
wIndex,
NULL, 0, USB_CTRL_SET_TIMEOUT);
+ break;
}
usb_autopm_put_interface(serial->interface);
@@ -1696,6 +1783,61 @@ static int cp2104_gpioconf_init(struct usb_serial *serial)
return 0;
}
+static int cp2108_gpio_init(struct usb_serial *serial)
+{
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct cp210x_quad_port_config config;
+ u16 gpio_latch;
+ int result;
+ u8 i;
+
+ result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
+ CP210X_GET_PORTCONFIG, &config,
+ sizeof(config));
+ if (result < 0)
+ return result;
+
+ priv->gc.ngpio = 16;
+ priv->gpio_pushpull = le16_to_cpu(config.reset_state.gpio_mode_pb1);
+ gpio_latch = le16_to_cpu(config.reset_state.gpio_latch_pb1);
+
+ /*
+ * Mark all pins which are not in GPIO mode.
+ *
+ * Refer to table 9.1 "GPIO Mode alternate Functions" in the datasheet:
+ * https://www.silabs.com/documents/public/data-sheets/cp2108-datasheet.pdf
+ *
+ * Alternate functions of GPIO0 to GPIO3 are determine by enhancedfxn_ifc[0]
+ * and the similarly for the other pins; enhancedfxn_ifc[1]: GPIO4 to GPIO7,
+ * enhancedfxn_ifc[2]: GPIO8 to GPIO11, enhancedfxn_ifc[3]: GPIO12 to GPIO15.
+ */
+ for (i = 0; i < 4; i++) {
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_TXLED)
+ priv->gpio_altfunc |= BIT(i * 4);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RXLED)
+ priv->gpio_altfunc |= BIT((i * 4) + 1);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RS485)
+ priv->gpio_altfunc |= BIT((i * 4) + 2);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_CLOCK)
+ priv->gpio_altfunc |= BIT((i * 4) + 3);
+ }
+
+ /*
+ * Like CP2102N, CP2108 has also no strict input and output pin
+ * modes. Do the same input mode emulation as CP2102N.
+ */
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ /*
+ * Set direction to "input" iff pin is open-drain and reset
+ * value is 1.
+ */
+ if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
+ priv->gpio_input |= BIT(i);
+ }
+
+ return 0;
+}
+
static int cp2102n_gpioconf_init(struct usb_serial *serial)
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
@@ -1812,6 +1954,15 @@ static int cp210x_gpio_init(struct usb_serial *serial)
case CP210X_PARTNUM_CP2105:
result = cp2105_gpioconf_init(serial);
break;
+ case CP210X_PARTNUM_CP2108:
+ /*
+ * The GPIOs are not tied to any specific port so only register
+ * once for interface 0.
+ */
+ if (cp210x_interface_num(serial) != 0)
+ return 0;
+ result = cp2108_gpio_init(serial);
+ break;
case CP210X_PARTNUM_CP2102N_QFN28:
case CP210X_PARTNUM_CP2102N_QFN24:
case CP210X_PARTNUM_CP2102N_QFN20:
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index cf389224d528..51e5aac3bf4c 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -53,7 +53,7 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
-static int cyberjack_write_room(struct tty_struct *tty);
+static unsigned int cyberjack_write_room(struct tty_struct *tty);
static void cyberjack_read_int_callback(struct urb *urb);
static void cyberjack_read_bulk_callback(struct urb *urb);
static void cyberjack_write_bulk_callback(struct urb *urb);
@@ -240,7 +240,7 @@ static int cyberjack_write(struct tty_struct *tty,
return count;
}
-static int cyberjack_write_room(struct tty_struct *tty)
+static unsigned int cyberjack_write_room(struct tty_struct *tty)
{
/* FIXME: .... */
return CYBERJACK_LOCAL_BUF_SIZE;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 55f23df03e0b..6b18990258c3 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -122,14 +122,14 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
-static int cypress_write_room(struct tty_struct *tty);
+static unsigned int cypress_write_room(struct tty_struct *tty);
static void cypress_earthmate_init_termios(struct tty_struct *tty);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
static int cypress_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int cypress_chars_in_buffer(struct tty_struct *tty);
+static unsigned int cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
static void cypress_set_dead(struct usb_serial_port *port);
@@ -789,18 +789,18 @@ send:
/* returns how much space is available in the soft buffer */
-static int cypress_write_room(struct tty_struct *tty)
+static unsigned int cypress_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
room = kfifo_avail(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
@@ -955,18 +955,18 @@ static void cypress_set_termios(struct tty_struct *tty,
/* returns amount of data still left in soft buffer */
-static int cypress_chars_in_buffer(struct tty_struct *tty)
+static unsigned int cypress_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
chars = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 8b2f06539f2c..af65eb863d70 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -223,8 +223,8 @@ static int digi_tiocmset(struct tty_struct *tty, unsigned int set,
static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void digi_write_bulk_callback(struct urb *urb);
-static int digi_write_room(struct tty_struct *tty);
-static int digi_chars_in_buffer(struct tty_struct *tty);
+static unsigned int digi_write_room(struct tty_struct *tty);
+static unsigned int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void digi_close(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
@@ -372,7 +372,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
int len;
struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev,
"digi_write_oob_command: TOP: port=%d, count=%d\n",
@@ -430,7 +430,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
@@ -511,8 +511,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
unsigned char *data = oob_port->write_urb->transfer_buffer;
- unsigned long flags = 0;
-
+ unsigned long flags;
dev_dbg(&port->dev,
"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
@@ -577,7 +576,7 @@ static int digi_transmit_idle(struct usb_serial_port *port,
int ret;
unsigned char buf[2];
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 0;
@@ -887,7 +886,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
int ret, data_len, new_len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
@@ -1020,12 +1019,12 @@ static void digi_write_bulk_callback(struct urb *urb)
tty_port_tty_wakeup(&port->port);
}
-static int digi_write_room(struct tty_struct *tty)
+static unsigned int digi_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
- int room;
- unsigned long flags = 0;
+ unsigned long flags;
+ unsigned int room;
spin_lock_irqsave(&priv->dp_port_lock, flags);
@@ -1035,27 +1034,28 @@ static int digi_write_room(struct tty_struct *tty)
room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
- dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room);
+ dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room);
return room;
}
-static int digi_chars_in_buffer(struct tty_struct *tty)
+static unsigned int digi_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int chars;
- if (priv->dp_write_urb_in_use) {
- dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
- priv->dp_port_num, port->bulk_out_size - 2);
- /* return(port->bulk_out_size - 2); */
- return 256;
- } else {
- dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
- priv->dp_port_num, priv->dp_out_buf_len);
- return priv->dp_out_buf_len;
- }
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
+ if (priv->dp_write_urb_in_use)
+ chars = port->bulk_out_size - 2;
+ else
+ chars = priv->dp_out_buf_len;
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ dev_dbg(&port->dev, "%s: port=%d, chars=%d\n", __func__,
+ priv->dp_port_num, chars);
+ return chars;
}
static void digi_dtr_rts(struct usb_serial_port *port, int on)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 50e8bdc77e71..756d1ac7e96f 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1113,7 +1113,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int garmin_write_room(struct tty_struct *tty)
+static unsigned int garmin_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
/*
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index d10aa3d2ee49..15b6dee3a8e5 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -230,11 +230,11 @@ int usb_serial_generic_write(struct tty_struct *tty,
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write);
-int usb_serial_generic_write_room(struct tty_struct *tty)
+unsigned int usb_serial_generic_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- int room;
+ unsigned int room;
if (!port->bulk_out_size)
return 0;
@@ -243,15 +243,15 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
+unsigned int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- int chars;
+ unsigned int chars;
if (!port->bulk_out_size)
return 0;
@@ -260,7 +260,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
spin_unlock_irqrestore(&port->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index e6fe3882bf69..ea4edf5eed27 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1351,33 +1351,21 @@ exit_send:
/*****************************************************************************
* edge_write_room
* this function is called by the tty driver when it wants to know how
- * many bytes of data we can accept for a specific port. If successful,
- * we return the amount of room that we have for this port (the txCredits)
- * otherwise we return a negative error number.
+ * many bytes of data we can accept for a specific port.
*****************************************************************************/
-static int edge_write_room(struct tty_struct *tty)
+static unsigned int edge_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int room;
+ unsigned int room;
unsigned long flags;
- if (edge_port == NULL)
- return 0;
- if (edge_port->closePending)
- return 0;
-
- if (!edge_port->open) {
- dev_dbg(&port->dev, "%s - port not opened\n", __func__);
- return 0;
- }
-
/* total of both buffers is still txCredit */
spin_lock_irqsave(&edge_port->ep_lock, flags);
room = edge_port->txCredits - edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
@@ -1387,33 +1375,20 @@ static int edge_write_room(struct tty_struct *tty)
* this function is called by the tty driver when it wants to know how
* many bytes of data we currently have outstanding in the port (data that
* has been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return a negative error number.
*****************************************************************************/
-static int edge_chars_in_buffer(struct tty_struct *tty)
+static unsigned int edge_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int num_chars;
+ unsigned int num_chars;
unsigned long flags;
- if (edge_port == NULL)
- return 0;
- if (edge_port->closePending)
- return 0;
-
- if (!edge_port->open) {
- dev_dbg(&port->dev, "%s - port not opened\n", __func__);
- return 0;
- }
-
spin_lock_irqsave(&edge_port->ep_lock, flags);
num_chars = edge_port->maxTxCredits - edge_port->txCredits +
edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, num_chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, num_chars);
}
return num_chars;
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 39503fdccebf..84b848d2794e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2067,11 +2067,11 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
tty_wakeup(tty);
}
-static int edge_write_room(struct tty_struct *tty)
+static unsigned int edge_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
if (edge_port == NULL)
@@ -2083,15 +2083,15 @@ static int edge_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-static int edge_chars_in_buffer(struct tty_struct *tty)
+static unsigned int edge_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
if (edge_port == NULL)
return 0;
@@ -2100,7 +2100,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 172261a908d8..7b44dbea95cd 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -47,7 +47,7 @@ static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int ir_write_room(struct tty_struct *tty);
+static unsigned int ir_write_room(struct tty_struct *tty);
static void ir_write_bulk_callback(struct urb *urb);
static void ir_process_read_urb(struct urb *urb);
static void ir_set_termios(struct tty_struct *tty,
@@ -339,10 +339,10 @@ static void ir_write_bulk_callback(struct urb *urb)
usb_serial_port_softint(port);
}
-static int ir_write_room(struct tty_struct *tty)
+static unsigned int ir_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int count = 0;
+ unsigned int count = 0;
if (port->bulk_out_size == 0)
return 0;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index b04a029e3657..87b89c99d517 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1453,13 +1453,13 @@ static void usa67_glocont_callback(struct urb *urb)
}
}
-static int keyspan_write_room(struct tty_struct *tty)
+static unsigned int keyspan_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
int flip;
- int data_len;
+ unsigned int data_len;
struct urb *this_urb;
p_priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index a9bc546626ab..4ed8b8b0a361 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -53,7 +53,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
static void kobil_close(struct usb_serial_port *port);
static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int kobil_write_room(struct tty_struct *tty);
+static unsigned int kobil_write_room(struct tty_struct *tty);
static int kobil_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static int kobil_tiocmget(struct tty_struct *tty);
@@ -358,7 +358,7 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int kobil_write_room(struct tty_struct *tty)
+static unsigned int kobil_write_room(struct tty_struct *tty)
{
/* FIXME */
return 8;
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index f9ce9e7b9b80..30ab565e0738 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -109,9 +109,9 @@ static void metrousb_read_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
int throttled = 0;
int result = 0;
- unsigned long flags = 0;
dev_dbg(&port->dev, "%s\n", __func__);
@@ -171,7 +171,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
/* Set the private data information for the port. */
@@ -268,7 +268,7 @@ static void metrousb_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
/* Set the private information for the port to stop reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
@@ -281,7 +281,7 @@ static int metrousb_tiocmget(struct tty_struct *tty)
unsigned long control_state = 0;
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
@@ -296,7 +296,7 @@ static int metrousb_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
unsigned long control_state = 0;
dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
@@ -323,7 +323,7 @@ static void metrousb_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
/* Set the private information for the port to resume reading data. */
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 6ee83886e2c9..227f43d2bd56 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -945,27 +945,20 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
* this function is called by the tty driver when it wants to know how many
* bytes of data we currently have outstanding in the port (data that has
* been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return a negative error number.
*/
-static int mos7720_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mos7720_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
int i;
- int chars = 0;
- struct moschip_port *mos7720_port;
-
- mos7720_port = usb_get_serial_port_data(port);
- if (mos7720_port == NULL)
- return 0;
+ unsigned int chars = 0;
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i] &&
mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
chars += URB_TRANSFER_BUFFER_SIZE;
}
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
@@ -1030,20 +1023,14 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
* mos7720_write_room
* this function is called by the tty driver when it wants to know how many
* bytes of data we can accept for a specific port.
- * If successful, we return the amount of room that we have for this port
- * Otherwise we return a negative error number.
*/
-static int mos7720_write_room(struct tty_struct *tty)
+static unsigned int mos7720_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port;
- int room = 0;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+ unsigned int room = 0;
int i;
- mos7720_port = usb_get_serial_port_data(port);
- if (mos7720_port == NULL)
- return 0;
-
/* FIXME: Locking */
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i] &&
@@ -1051,7 +1038,7 @@ static int mos7720_write_room(struct tty_struct *tty)
room += URB_TRANSFER_BUFFER_SIZE;
}
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 28e4093794e0..d7fe33ca73e4 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -730,17 +730,14 @@ err:
* this function is called by the tty driver when it wants to know how many
* bytes of data we currently have outstanding in the port (data that has
* been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return zero.
*****************************************************************************/
-static int mos7840_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mos7840_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
int i;
- int chars = 0;
+ unsigned int chars = 0;
unsigned long flags;
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
@@ -751,7 +748,7 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
@@ -814,16 +811,14 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
* mos7840_write_room
* this function is called by the tty driver when it wants to know how many
* bytes of data we can accept for a specific port.
- * If successful, we return the amount of room that we have for this port
- * Otherwise we return a negative error number.
*****************************************************************************/
-static int mos7840_write_room(struct tty_struct *tty)
+static unsigned int mos7840_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
int i;
- int room = 0;
+ unsigned int room = 0;
unsigned long flags;
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
@@ -834,7 +829,7 @@ static int mos7840_write_room(struct tty_struct *tty)
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
- dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&mos7840_port->port->dev, "%s - returns %u\n", __func__, room);
return room;
}
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 40c713fae0c3..aed28c35caff 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -267,7 +267,7 @@ error_no_buffer:
return ret;
}
-static int opticon_write_room(struct tty_struct *tty)
+static unsigned int opticon_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct opticon_private *priv = usb_get_serial_port_data(port);
@@ -289,12 +289,12 @@ static int opticon_write_room(struct tty_struct *tty)
return 2048;
}
-static int opticon_chars_in_buffer(struct tty_struct *tty)
+static unsigned int opticon_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct opticon_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- int count;
+ unsigned int count;
spin_lock_irqsave(&priv->lock, flags);
count = priv->outstanding_bytes;
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 65cd0341fa78..a5caedbe72e2 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -126,8 +126,8 @@ static void oti6858_read_bulk_callback(struct urb *urb);
static void oti6858_write_bulk_callback(struct urb *urb);
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int oti6858_write_room(struct tty_struct *tty);
-static int oti6858_chars_in_buffer(struct tty_struct *tty);
+static unsigned int oti6858_write_room(struct tty_struct *tty);
+static unsigned int oti6858_chars_in_buffer(struct tty_struct *tty);
static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
@@ -363,10 +363,10 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
return count;
}
-static int oti6858_write_room(struct tty_struct *tty)
+static unsigned int oti6858_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
@@ -376,10 +376,10 @@ static int oti6858_write_room(struct tty_struct *tty)
return room;
}
-static int oti6858_chars_in_buffer(struct tty_struct *tty)
+static unsigned int oti6858_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 067690dac24c..971907f083a3 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -870,12 +870,12 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
}
-static int qt2_write_room(struct tty_struct *tty)
+static unsigned int qt2_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct qt2_port_private *port_priv;
- unsigned long flags = 0;
- int r;
+ unsigned long flags;
+ unsigned int r;
port_priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 54e16ffc30a0..4b49b7c33364 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -613,7 +613,7 @@ static void sierra_instat_callback(struct urb *urb)
}
}
-static int sierra_write_room(struct tty_struct *tty)
+static unsigned int sierra_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
@@ -632,19 +632,19 @@ static int sierra_write_room(struct tty_struct *tty)
return 2048;
}
-static int sierra_chars_in_buffer(struct tty_struct *tty)
+static unsigned int sierra_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- int chars;
+ unsigned int chars;
/* NOTE: This overcounts somewhat. */
spin_lock_irqsave(&portdata->lock, flags);
chars = portdata->outstanding_urbs * MAX_TRANSFER;
spin_unlock_irqrestore(&portdata->lock, flags);
- dev_dbg(&port->dev, "%s - %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 310db5abea9d..18c0bd853392 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -308,8 +308,8 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ti_close(struct usb_serial_port *port);
static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
-static int ti_write_room(struct tty_struct *tty);
-static int ti_chars_in_buffer(struct tty_struct *tty);
+static unsigned int ti_write_room(struct tty_struct *tty);
+static unsigned int ti_chars_in_buffer(struct tty_struct *tty);
static bool ti_tx_empty(struct usb_serial_port *port);
static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
@@ -813,34 +813,34 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int ti_write_room(struct tty_struct *tty)
+static unsigned int ti_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-static int ti_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ti_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index b5331d03092f..519101945769 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -11,13 +11,13 @@ extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
extern void usb_wwan_close(struct usb_serial_port *port);
extern int usb_wwan_port_probe(struct usb_serial_port *port);
extern void usb_wwan_port_remove(struct usb_serial_port *port);
-extern int usb_wwan_write_room(struct tty_struct *tty);
+extern unsigned int usb_wwan_write_room(struct tty_struct *tty);
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
+extern unsigned int usb_wwan_chars_in_buffer(struct tty_struct *tty);
#ifdef CONFIG_PM
extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message);
extern int usb_wwan_resume(struct usb_serial *serial);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 3eb72c59ede6..cb01283d4d15 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -278,12 +278,12 @@ static void usb_wwan_outdat_callback(struct urb *urb)
}
}
-int usb_wwan_write_room(struct tty_struct *tty)
+unsigned int usb_wwan_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_wwan_port_private *portdata;
int i;
- int data_len = 0;
+ unsigned int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
@@ -294,17 +294,17 @@ int usb_wwan_write_room(struct tty_struct *tty)
data_len += OUT_BUFLEN;
}
- dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
+ dev_dbg(&port->dev, "%s: %u\n", __func__, data_len);
return data_len;
}
EXPORT_SYMBOL(usb_wwan_write_room);
-int usb_wwan_chars_in_buffer(struct tty_struct *tty)
+unsigned int usb_wwan_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_wwan_port_private *portdata;
int i;
- int data_len = 0;
+ unsigned int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
@@ -316,7 +316,7 @@ int usb_wwan_chars_in_buffer(struct tty_struct *tty)
if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
- dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
+ dev_dbg(&port->dev, "%s: %u\n", __func__, data_len);
return data_len;
}
EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index b9429c9f65f6..aeef453aa658 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -517,8 +517,10 @@ typec_register_altmode(struct device *parent,
int ret;
alt = kzalloc(sizeof(*alt), GFP_KERNEL);
- if (!alt)
+ if (!alt) {
+ altmode_id_remove(parent, id);
return ERR_PTR(-ENOMEM);
+ }
alt->adev.svid = desc->svid;
alt->adev.mode = desc->mode;
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index 77dabd306ba8..c8340de0ed49 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -17,21 +17,12 @@
#include "class.h"
#include "mux.h"
-static bool dev_name_ends_with(struct device *dev, const char *suffix)
-{
- const char *name = dev_name(dev);
- const int name_len = strlen(name);
- const int suffix_len = strlen(suffix);
-
- if (suffix_len > name_len)
- return false;
-
- return strcmp(name + (name_len - suffix_len), suffix) == 0;
-}
-
static int switch_fwnode_match(struct device *dev, const void *fwnode)
{
- return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch");
+ if (!is_typec_switch(dev))
+ return 0;
+
+ return dev_fwnode(dev) == fwnode;
}
static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
@@ -39,9 +30,22 @@ static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
{
struct device *dev;
+ /*
+ * Device graph (OF graph) does not give any means to identify the
+ * device type or the device class of the remote port parent that @fwnode
+ * represents, so in order to identify the type or the class of @fwnode
+ * an additional device property is needed. With typec switches the
+ * property is named "orientation-switch" (@id). The value of the device
+ * property is ignored.
+ */
if (id && !fwnode_property_present(fwnode, id))
return NULL;
+ /*
+ * At this point we are sure that @fwnode is a typec switch in all
+ * cases. If the switch hasn't yet been registered for some reason, the
+ * function "defers probe" for now.
+ */
dev = class_find_device(&typec_mux_class, NULL, fwnode,
switch_fwnode_match);
@@ -90,7 +94,7 @@ static void typec_switch_release(struct device *dev)
kfree(to_typec_switch(dev));
}
-static const struct device_type typec_switch_dev_type = {
+const struct device_type typec_switch_dev_type = {
.name = "orientation_switch",
.release = typec_switch_release,
};
@@ -180,7 +184,10 @@ EXPORT_SYMBOL_GPL(typec_switch_get_drvdata);
static int mux_fwnode_match(struct device *dev, const void *fwnode)
{
- return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux");
+ if (!is_typec_mux(dev))
+ return 0;
+
+ return dev_fwnode(dev) == fwnode;
}
static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id,
@@ -295,7 +302,7 @@ static void typec_mux_release(struct device *dev)
kfree(to_typec_mux(dev));
}
-static const struct device_type typec_mux_dev_type = {
+const struct device_type typec_mux_dev_type = {
.name = "mode_switch",
.release = typec_mux_release,
};
diff --git a/drivers/usb/typec/mux.h b/drivers/usb/typec/mux.h
index 4fd9426ee44f..b1d6e837cb74 100644
--- a/drivers/usb/typec/mux.h
+++ b/drivers/usb/typec/mux.h
@@ -18,4 +18,10 @@ struct typec_mux {
#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev)
#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev)
+extern const struct device_type typec_switch_dev_type;
+extern const struct device_type typec_mux_dev_type;
+
+#define is_typec_switch(dev) ((dev)->type == &typec_switch_dev_type)
+#define is_typec_mux(dev) ((dev)->type == &typec_mux_dev_type)
+
#endif /* __USB_TYPEC_MUX__ */
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index ffa8aa12d5f1..2cdd22130834 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -83,8 +83,6 @@ enum {
/*
* Input Output Manager (IOM) PORT STATUS
*/
-#define IOM_PORT_STATUS_OFFSET 0x560
-
#define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK GENMASK(9, 6)
#define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT 6
#define IOM_PORT_STATUS_ACTIVITY_TYPE_USB 0x03
@@ -144,6 +142,7 @@ struct pmc_usb {
struct pmc_usb_port *port;
struct acpi_device *iom_adev;
void __iomem *iom_base;
+ u32 iom_port_status_offset;
};
static void update_port_status(struct pmc_usb_port *port)
@@ -153,7 +152,8 @@ static void update_port_status(struct pmc_usb_port *port)
/* SoC expects the USB Type-C port numbers to start with 0 */
port_num = port->usb3_port - 1;
- port->iom_status = readl(port->pmc->iom_base + IOM_PORT_STATUS_OFFSET +
+ port->iom_status = readl(port->pmc->iom_base +
+ port->pmc->iom_port_status_offset +
port_num * sizeof(u32));
}
@@ -559,14 +559,32 @@ static int is_memory(struct acpi_resource *res, void *data)
return !acpi_dev_resource_memory(res, &r);
}
+/* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */
+static const struct acpi_device_id iom_acpi_ids[] = {
+ /* TigerLake */
+ { "INTC1072", 0x560, },
+
+ /* AlderLake */
+ { "INTC1079", 0x160, },
+ {}
+};
+
static int pmc_usb_probe_iom(struct pmc_usb *pmc)
{
struct list_head resource_list;
struct resource_entry *rentry;
- struct acpi_device *adev;
+ static const struct acpi_device_id *dev_id;
+ struct acpi_device *adev = NULL;
int ret;
- adev = acpi_dev_get_first_match_dev("INTC1072", NULL, -1);
+ for (dev_id = &iom_acpi_ids[0]; dev_id->id[0]; dev_id++) {
+ if (acpi_dev_present(dev_id->id, NULL, -1)) {
+ pmc->iom_port_status_offset = (u32)dev_id->driver_data;
+ adev = acpi_dev_get_first_match_dev(dev_id->id, NULL, -1);
+ break;
+ }
+ }
+
if (!adev)
return -ENODEV;
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 25b480752266..9858716698df 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -21,8 +21,12 @@
#define PD_RETRY_COUNT_DEFAULT 3
#define PD_RETRY_COUNT_3_0_OR_HIGHER 2
#define AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV 3500
-#define AUTO_DISCHARGE_PD_HEADROOM_MV 850
-#define AUTO_DISCHARGE_PPS_HEADROOM_MV 1250
+#define VSINKPD_MIN_IR_DROP_MV 750
+#define VSRC_NEW_MIN_PERCENT 95
+#define VSRC_VALID_MIN_MV 500
+#define VPPS_NEW_MIN_PERCENT 95
+#define VPPS_VALID_MIN_MV 100
+#define VSINKDISCONNECT_PD_MIN_PERCENT 90
#define tcpc_presenting_rd(reg, cc) \
(!(TCPC_ROLE_CTRL_DRP & (reg)) && \
@@ -115,6 +119,33 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
return 0;
}
+static int tcpci_apply_rc(struct tcpc_dev *tcpc, enum typec_cc_status cc,
+ enum typec_cc_polarity polarity)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * APPLY_RC state is when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2 and vbus autodischarge on
+ * disconnect is disabled. Bail out when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2.
+ */
+ if (((reg & (TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT)) >>
+ TCPC_ROLE_CTRL_CC2_SHIFT) !=
+ ((reg & (TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT)) >>
+ TCPC_ROLE_CTRL_CC1_SHIFT))
+ return 0;
+
+ return regmap_update_bits(tcpci->regmap, TCPC_ROLE_CTRL, polarity == TYPEC_POLARITY_CC1 ?
+ TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT :
+ TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT,
+ TCPC_ROLE_CTRL_CC_OPEN);
+}
+
static int tcpci_start_toggling(struct tcpc_dev *tcpc,
enum typec_port_type port_type,
enum typec_cc_status cc)
@@ -324,11 +355,13 @@ static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum ty
threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
} else if (mode == TYPEC_PWR_MODE_PD) {
if (pps_active)
- threshold = (95 * requested_vbus_voltage_mv / 100) -
- AUTO_DISCHARGE_PD_HEADROOM_MV;
+ threshold = ((VPPS_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) -
+ VSINKPD_MIN_IR_DROP_MV - VPPS_VALID_MIN_MV) *
+ VSINKDISCONNECT_PD_MIN_PERCENT / 100;
else
- threshold = (95 * requested_vbus_voltage_mv / 100) -
- AUTO_DISCHARGE_PPS_HEADROOM_MV;
+ threshold = ((VSRC_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) -
+ VSINKPD_MIN_IR_DROP_MV - VSRC_VALID_MIN_MV) *
+ VSINKDISCONNECT_PD_MIN_PERCENT / 100;
} else {
/* 3.5V for non-pd sink */
threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
@@ -728,6 +761,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
tcpci->tcpc.get_vbus = tcpci_get_vbus;
tcpci->tcpc.set_vbus = tcpci_set_vbus;
tcpci->tcpc.set_cc = tcpci_set_cc;
+ tcpci->tcpc.apply_rc = tcpci_apply_rc;
tcpci->tcpc.get_cc = tcpci_get_cc;
tcpci->tcpc.set_polarity = tcpci_set_polarity;
tcpci->tcpc.set_vconn = tcpci_set_vconn;
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 63470cf7f4cd..5b22a1c931a9 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -776,6 +776,34 @@ static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
port->tcpc->set_cc(port->tcpc, cc);
}
+static int tcpm_enable_auto_vbus_discharge(struct tcpm_port *port, bool enable)
+{
+ int ret = 0;
+
+ if (port->tcpc->enable_auto_vbus_discharge) {
+ ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, enable);
+ tcpm_log_force(port, "%s vbus discharge ret:%d", enable ? "enable" : "disable",
+ ret);
+ if (!ret)
+ port->auto_vbus_discharge_enabled = enable;
+ }
+
+ return ret;
+}
+
+static void tcpm_apply_rc(struct tcpm_port *port)
+{
+ /*
+ * TCPCI: Move to APPLY_RC state to prevent disconnect during PR_SWAP
+ * when Vbus auto discharge on disconnect is enabled.
+ */
+ if (port->tcpc->enable_auto_vbus_discharge && port->tcpc->apply_rc) {
+ tcpm_log(port, "Apply_RC");
+ port->tcpc->apply_rc(port->tcpc, port->cc_req, port->polarity);
+ tcpm_enable_auto_vbus_discharge(port, false);
+ }
+}
+
/*
* Determine RP value to set based on maximum current supported
* by a port if configured as source.
@@ -2576,6 +2604,11 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
} else {
next_state = SNK_WAIT_CAPABILITIES;
}
+
+ /* Threshold was relaxed before sending Request. Restore it back. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
tcpm_set_state(port, next_state, 0);
break;
case SNK_NEGOTIATE_PPS_CAPABILITIES:
@@ -2589,6 +2622,11 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
port->send_discover)
port->vdm_sm_running = true;
+ /* Threshold was relaxed before sending Request. Restore it back. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
+
tcpm_set_state(port, SNK_READY, 0);
break;
case DR_SWAP_SEND:
@@ -3308,6 +3346,12 @@ static int tcpm_pd_send_request(struct tcpm_port *port)
if (ret < 0)
return ret;
+ /*
+ * Relax the threshold as voltage will be adjusted after Accept Message plus tSrcTransition.
+ * It is safer to modify the threshold here.
+ */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
+
memset(&msg, 0, sizeof(msg));
msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
port->pwr_role,
@@ -3405,6 +3449,9 @@ static int tcpm_pd_send_pps_request(struct tcpm_port *port)
if (ret < 0)
return ret;
+ /* Relax the threshold as voltage will be adjusted right after Accept Message. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
+
memset(&msg, 0, sizeof(msg));
msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
port->pwr_role,
@@ -3515,12 +3562,7 @@ static int tcpm_src_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- if (port->tcpc->enable_auto_vbus_discharge) {
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
- tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = true;
- }
+ tcpm_enable_auto_vbus_discharge(port, true);
ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
if (ret < 0)
@@ -3597,14 +3639,7 @@ static void tcpm_set_partner_usb_comm_capable(struct tcpm_port *port, bool capab
static void tcpm_reset_port(struct tcpm_port *port)
{
- int ret;
-
- if (port->tcpc->enable_auto_vbus_discharge) {
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false);
- tcpm_log_force(port, "Disable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = false;
- }
+ tcpm_enable_auto_vbus_discharge(port, false);
port->in_ams = false;
port->ams = NONE_AMS;
port->vdm_sm_running = false;
@@ -3672,13 +3707,7 @@ static int tcpm_snk_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- if (port->tcpc->enable_auto_vbus_discharge) {
- tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
- tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = true;
- }
+ tcpm_enable_auto_vbus_discharge(port, true);
ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
if (ret < 0)
@@ -4186,6 +4215,10 @@ static void run_state_machine(struct tcpm_port *port)
port->hard_reset_count = 0;
ret = tcpm_pd_send_request(port);
if (ret < 0) {
+ /* Restore back to the original state */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
/* Let the Source send capabilities again. */
tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
} else {
@@ -4196,6 +4229,10 @@ static void run_state_machine(struct tcpm_port *port)
case SNK_NEGOTIATE_PPS_CAPABILITIES:
ret = tcpm_pd_send_pps_request(port);
if (ret < 0) {
+ /* Restore back to the original state */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
port->pps_status = ret;
/*
* If this was called due to updates to sink
@@ -4515,6 +4552,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ready_state(port), 0);
break;
case PR_SWAP_START:
+ tcpm_apply_rc(port);
if (port->pwr_role == TYPEC_SOURCE)
tcpm_set_state(port, PR_SWAP_SRC_SNK_TRANSITION_OFF,
PD_T_SRC_TRANSITION);
@@ -4554,6 +4592,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_ON_PRS);
break;
case PR_SWAP_SRC_SNK_SINK_ON:
+ tcpm_enable_auto_vbus_discharge(port, true);
/* Set the vbus disconnect threshold for implicit contract */
tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
tcpm_set_state(port, SNK_STARTUP, 0);
@@ -4570,6 +4609,7 @@ static void run_state_machine(struct tcpm_port *port)
PD_T_PS_SOURCE_OFF);
break;
case PR_SWAP_SNK_SRC_SOURCE_ON:
+ tcpm_enable_auto_vbus_discharge(port, true);
tcpm_set_cc(port, tcpm_rp_cc(port));
tcpm_set_vbus(port, true);
/*
@@ -5198,6 +5238,10 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
tcpm_set_state(port, SNK_UNATTACHED, 0);
}
break;
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ case PR_SWAP_SNK_SRC_SOURCE_ON:
+ /* Do nothing, vsafe0v is expected during transition */
+ break;
default:
if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
tcpm_set_state(port, SNK_UNATTACHED, 0);
diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c
index 5d125339687a..20917d85d6f4 100644
--- a/drivers/usb/typec/tcpm/wcove.c
+++ b/drivers/usb/typec/tcpm/wcove.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* typec_wcove.c - WhiskeyCove PMIC USB Type-C PHY driver
*
* Copyright (C) 2017 Intel Corporation
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index b7d104c80d85..5ef5bd0e87cf 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1219,7 +1219,7 @@ static int ucsi_init(struct ucsi *ucsi)
goto err_reset;
}
- /* Allocate the connectors. Released in ucsi_unregister_ppm() */
+ /* Allocate the connectors. Released in ucsi_unregister() */
ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
sizeof(*ucsi->connector), GFP_KERNEL);
if (!ucsi->connector) {
@@ -1280,7 +1280,7 @@ void *ucsi_get_drvdata(struct ucsi *ucsi)
EXPORT_SYMBOL_GPL(ucsi_get_drvdata);
/**
- * ucsi_get_drvdata - Assign private driver data pointer
+ * ucsi_set_drvdata - Assign private driver data pointer
* @ucsi: UCSI interface
* @data: Private data pointer
*/