mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 18:23:53 +08:00
usb: changes for v5.3 merge window
The biggest part here is a set of patches removing unnecesary variables from several drivers. Meson-g12a's dwc3 glue implemented IRQ-based OTG/DRD role swap. Qcom's dwc3 glue added support for ACPI, mainly for the AArch64-based SoCs. DWC3 also got support for Intel Elkhart Lake platforms. -----BEGIN PGP SIGNATURE----- iQJRBAABCAA7FiEElLzh7wn96CXwjh2IzL64meEamQYFAl0UdeMdHGZlbGlwZS5i YWxiaUBsaW51eC5pbnRlbC5jb20ACgkQzL64meEamQbuBxAAqMp9nwVgYu9beeXP 1xEjfnc/OxA8oMPcbJVPiYseVowbrj5Ue3SK8XcDCeSDfEI09PNOqfpNtLXvjVie NxDMj1zj31Ggb0XfoweOZQHXXpq/6tlfqVJ/oXfkxQ92wuSlyKzkoA7ZuCxAy9ay p+E+/cSa1E5LGigI/XEyX2C9JuANd9vSM/CaA5Z2XbosThLK9svtHWlNRIPolIGB fUBRm3JVi1jLxAMfbu/8Ng05xYGIPnwi8JDcQ8swAdm5nENtuq9Z0eMm8EAxLdvn UwArRR14uI4Vgs69IH4R28tmM4MMsuUVnKv3nxOYcoqQ01u9dySiEYsT5x7RETLu GH7v4NMdTqTIfN8ECFLUfaE8+tLBx6MjFOBxNHIeu1tc+MrRzb7a7Z00dkpUlMkg jaddCfwbAx3CgJ77nDILBYnVRpaEzlKhZWrNkoSCUI1Ty0QlsnInUkhXtUuayi+R AjCBc1PBXPOc6FHx5ECQrA0HWBhC0MW23ncdAFxz1eqqJPYhNbPn5zPEaZ8nNvmz R1aUlxDi8FDyRvKbjmGoeRrLbiwzcu/9xiLZ13U4H/kPG4+1g+rx3F8ExIvWr1p+ XrCJCDdYKN+D9KxbO/5ERg38fARsynryXp4Yll4cLR7IWCQZykkVJ+MuLDwejNF1 itw69proXZUqZ3Voa9C5a1V/gCQ= =3HLl -----END PGP SIGNATURE----- Merge tag 'usb-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next Felipe writes: usb: changes for v5.3 merge window The biggest part here is a set of patches removing unnecesary variables from several drivers. Meson-g12a's dwc3 glue implemented IRQ-based OTG/DRD role swap. Qcom's dwc3 glue added support for ACPI, mainly for the AArch64-based SoCs. DWC3 also got support for Intel Elkhart Lake platforms. * tag 'usb-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (30 commits) usb: dwc3: remove unused @lock member of dwc3_ep struct usb: dwc3: pci: Add Support for Intel Elkhart Lake Devices usb: Replace snprintf with scnprintf in gether_get_ifname usb: gadget: ether: Fix race between gether_disconnect and rx_submit usb: gadget: storage: Remove warning message usb: dwc3: gadget: Add support for disabling U1 and U2 entries usb: gadget: send usb_gadget as an argument in get_config_params doc: dt: bindings: usb: dwc3: Update entries for disabling U1 and U2 usb: dwc3: qcom: Use of_clk_get_parent_count() usb: dwc3: Fix core validation in probe, move after clocks are enabled usb: dwc3: qcom: Improve error handling usb: dwc3: qcom: Start USB in 'host mode' on the SDM845 usb: dwc3: qcom: Add support for booting with ACPI soc: qcom: geni: Add support for ACPI Revert "usb: dwc2: host: Setting qtd to NULL after freeing it" usb: gadget: net2272: remove redundant assignments to pointer 's' usb: gadget: Zero ffs_io_data USB: omap_udc: Remove unneeded variable fotg210-udc: Remove unneeded variable usb: gadget: at91_udc: Remove unneeded variable ...
This commit is contained in:
commit
f254e65ad6
@ -42,6 +42,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
|
||||
- g-rx-fifo-size: size of rx fifo size in gadget mode.
|
||||
- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
|
||||
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
|
||||
- snps,need-phy-for-wake: If present indicates that the phy needs to be left
|
||||
on for remote wakeup during suspend.
|
||||
- snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when
|
||||
we detect a wakeup. This is due to a hardware errata.
|
||||
|
||||
@ -58,4 +60,5 @@ Example:
|
||||
clock-names = "otg";
|
||||
phys = <&usbphy>;
|
||||
phy-names = "usb2-phy";
|
||||
snps,need-phy-for-wake;
|
||||
};
|
||||
|
@ -64,6 +64,8 @@ Optional properties:
|
||||
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
|
||||
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
|
||||
disabling the suspend signal to the PHY.
|
||||
- snps,dis-u1-entry-quirk: set if link entering into U1 needs to be disabled.
|
||||
- snps,dis-u2-entry-quirk: set if link entering into U2 needs to be disabled.
|
||||
- snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
|
||||
in PHY P3 power state.
|
||||
- snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists
|
||||
|
@ -424,6 +424,7 @@
|
||||
|
||||
&usb_host1 {
|
||||
status = "okay";
|
||||
snps,need-phy-for-wake;
|
||||
};
|
||||
|
||||
&usb_otg {
|
||||
@ -432,6 +433,7 @@
|
||||
assigned-clocks = <&cru SCLK_USBPHY480M_SRC>;
|
||||
assigned-clock-parents = <&usbphy0>;
|
||||
dr_mode = "host";
|
||||
snps,need-phy-for-wake;
|
||||
};
|
||||
|
||||
&vopb {
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@ -450,6 +451,9 @@ int geni_se_resources_off(struct geni_se *se)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (has_acpi_companion(se->dev))
|
||||
return 0;
|
||||
|
||||
ret = pinctrl_pm_select_sleep_state(se->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -487,6 +491,9 @@ int geni_se_resources_on(struct geni_se *se)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (has_acpi_companion(se->dev))
|
||||
return 0;
|
||||
|
||||
ret = geni_se_clks_on(se);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -724,12 +731,14 @@ static int geni_se_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(wrapper->base))
|
||||
return PTR_ERR(wrapper->base);
|
||||
|
||||
wrapper->ahb_clks[0].id = "m-ahb";
|
||||
wrapper->ahb_clks[1].id = "s-ahb";
|
||||
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err getting AHB clks %d\n", ret);
|
||||
return ret;
|
||||
if (!has_acpi_companion(&pdev->dev)) {
|
||||
wrapper->ahb_clks[0].id = "m-ahb";
|
||||
wrapper->ahb_clks[1].id = "s-ahb";
|
||||
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err getting AHB clks %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, wrapper);
|
||||
|
@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
|
||||
* @hibernated: True if core is hibernated
|
||||
* @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
|
||||
* remote wakeup.
|
||||
* @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
|
||||
* @need_phy_for_wake: Quirk saying that we should keep the PHY on at
|
||||
* suspend if we need USB to wake us up.
|
||||
* @frame_number: Frame number read from the core. For both device
|
||||
* and host modes. The value ranges are from 0
|
||||
* to HFNUM_MAX_FRNUM.
|
||||
@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
|
||||
unsigned int ll_hw_enabled:1;
|
||||
unsigned int hibernated:1;
|
||||
unsigned int reset_phy_on_wake:1;
|
||||
unsigned int need_phy_for_wake:1;
|
||||
unsigned int phy_off_for_suspend:1;
|
||||
u16 frame_number;
|
||||
|
||||
struct phy *phy;
|
||||
@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
|
||||
int rem_wakeup, int reset);
|
||||
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
|
||||
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
|
||||
{ schedule_work(&hsotg->phy_reset_work); }
|
||||
#else
|
||||
@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
|
||||
static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
|
||||
int rem_wakeup, int reset)
|
||||
{ return 0; }
|
||||
static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
|
||||
{ return false; }
|
||||
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
|
||||
|
||||
#endif
|
||||
|
@ -4685,7 +4685,6 @@ fail2:
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
urb->hcpriv = NULL;
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
fail1:
|
||||
if (qh_allocated) {
|
||||
struct dwc2_qtd *qtd2, *qtd2_tmp;
|
||||
@ -5587,3 +5586,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
|
||||
dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
|
||||
{
|
||||
struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
|
||||
|
||||
/* If the controller isn't allowed to wakeup then we can power off. */
|
||||
if (!device_may_wakeup(dwc2->dev))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* We don't want to power off the PHY if something under the
|
||||
* root hub has wakeup enabled.
|
||||
*/
|
||||
if (usb_wakeup_enabled_descendants(root_hub))
|
||||
return false;
|
||||
|
||||
/* No reason to keep the PHY powered, so allow poweroff */
|
||||
return true;
|
||||
}
|
||||
|
@ -582,7 +582,6 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
|
||||
{
|
||||
list_del(&qtd->qtd_list_entry);
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
}
|
||||
|
||||
/* Descriptor DMA support functions */
|
||||
|
@ -76,6 +76,7 @@ static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->power_down = 0;
|
||||
p->phy_utmi_width = 8;
|
||||
}
|
||||
|
||||
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
|
||||
|
@ -438,6 +438,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
hsotg->need_phy_for_wake =
|
||||
of_property_read_bool(dev->dev.of_node,
|
||||
"snps,need-phy-for-wake");
|
||||
|
||||
/*
|
||||
* Reset before dwc2_get_hwparams() then it could get power-on real
|
||||
* reset value form registers.
|
||||
@ -469,6 +473,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
||||
hsotg->gadget_enabled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we need PHY for wakeup we must be wakeup capable.
|
||||
* When we have a device that can wake without the PHY we
|
||||
* can adjust this condition.
|
||||
*/
|
||||
if (hsotg->need_phy_for_wake)
|
||||
device_set_wakeup_capable(&dev->dev, true);
|
||||
|
||||
hsotg->reset_phy_on_wake =
|
||||
of_property_read_bool(dev->dev.of_node,
|
||||
"snps,reset-phy-on-wake");
|
||||
@ -507,13 +519,17 @@ error:
|
||||
static int __maybe_unused dwc2_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
bool is_device_mode = dwc2_is_device_mode(dwc2);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
if (is_device_mode)
|
||||
dwc2_hsotg_suspend(dwc2);
|
||||
|
||||
if (dwc2->ll_hw_enabled)
|
||||
if (dwc2->ll_hw_enabled &&
|
||||
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
|
||||
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
||||
dwc2->phy_off_for_suspend = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -523,11 +539,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
||||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2->ll_hw_enabled) {
|
||||
if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
|
||||
ret = __dwc2_lowlevel_hw_enable(dwc2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
dwc2->phy_off_for_suspend = false;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
ret = dwc2_hsotg_resume(dwc2);
|
||||
|
@ -128,7 +128,7 @@ config USB_DWC3_QCOM
|
||||
tristate "Qualcomm Platform"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on EXTCON || !EXTCON
|
||||
depends on OF
|
||||
depends on (OF || ACPI)
|
||||
default USB_DWC3
|
||||
help
|
||||
Some Qualcomm SoCs use DesignWare Core IP for USB2/3
|
||||
|
@ -1282,6 +1282,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
||||
"snps,dis_u2_susphy_quirk");
|
||||
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_enblslpm_quirk");
|
||||
dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
|
||||
"snps,dis-u1-entry-quirk");
|
||||
dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
|
||||
"snps,dis-u2-entry-quirk");
|
||||
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_rxdet_inp3_quirk");
|
||||
dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
|
||||
@ -1423,11 +1427,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
dwc->regs = regs;
|
||||
dwc->regs_size = resource_size(&dwc_res);
|
||||
|
||||
if (!dwc3_core_is_valid(dwc)) {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dwc3_get_properties(dwc);
|
||||
|
||||
dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
|
||||
@ -1460,6 +1459,12 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto unprepare_clks;
|
||||
|
||||
if (!dwc3_core_is_valid(dwc)) {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
ret = -ENODEV;
|
||||
goto disable_clks;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
dwc3_cache_hwparams(dwc);
|
||||
|
||||
@ -1525,6 +1530,7 @@ err1:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
disable_clks:
|
||||
clk_bulk_disable(dwc->num_clks, dwc->clks);
|
||||
unprepare_clks:
|
||||
clk_bulk_unprepare(dwc->num_clks, dwc->clks);
|
||||
|
@ -649,7 +649,6 @@ struct dwc3_event_buffer {
|
||||
* @cancelled_list: list of cancelled requests for this endpoint
|
||||
* @pending_list: list of pending requests for this endpoint
|
||||
* @started_list: list of started requests on this endpoint
|
||||
* @lock: spinlock for endpoint request queue traversal
|
||||
* @regs: pointer to first endpoint register
|
||||
* @trb_pool: array of transaction buffers
|
||||
* @trb_pool_dma: dma address of @trb_pool
|
||||
@ -677,7 +676,6 @@ struct dwc3_ep {
|
||||
struct list_head pending_list;
|
||||
struct list_head started_list;
|
||||
|
||||
spinlock_t lock;
|
||||
void __iomem *regs;
|
||||
|
||||
struct dwc3_trb *trb_pool;
|
||||
@ -1014,6 +1012,8 @@ struct dwc3_scratchpad_array {
|
||||
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
|
||||
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
|
||||
* disabling the suspend signal to the PHY.
|
||||
* @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
|
||||
* @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
|
||||
* @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
|
||||
* @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
|
||||
* in GUSB2PHYCFG, specify that USB2 PHY doesn't
|
||||
@ -1205,6 +1205,8 @@ struct dwc3 {
|
||||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
unsigned dis_u1_entry_quirk:1;
|
||||
unsigned dis_u2_entry_quirk:1;
|
||||
unsigned dis_rxdet_inp3_quirk:1;
|
||||
unsigned dis_u2_freeclk_exists_quirk:1;
|
||||
unsigned dis_del_phy_power_chg_quirk:1;
|
||||
|
@ -11,9 +11,7 @@
|
||||
* - Control registers for each USB2 Ports
|
||||
* - Control registers for the USB PHY layer
|
||||
* - SuperSpeed PHY can be enabled only if port is used
|
||||
*
|
||||
* TOFIX:
|
||||
* - Add dynamic OTG switching with ID change interrupt
|
||||
* - Dynamic OTG switching with ID change interrupt
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -348,6 +346,22 @@ static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
|
||||
USB_ROLE_HOST : USB_ROLE_DEVICE;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct dwc3_meson_g12a *priv = data;
|
||||
enum phy_mode otg_id;
|
||||
|
||||
otg_id = dwc3_meson_g12a_get_id(priv);
|
||||
if (otg_id != priv->otg_phy_mode) {
|
||||
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
|
||||
dev_warn(priv->dev, "Failed to switch OTG mode\n");
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct device *dwc3_meson_g12_find_child(struct device *dev,
|
||||
const char *compatible)
|
||||
{
|
||||
@ -374,7 +388,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
||||
void __iomem *base;
|
||||
struct resource *res;
|
||||
enum phy_mode otg_id;
|
||||
int ret, i;
|
||||
int ret, i, irq;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@ -436,6 +450,19 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
||||
/* Get dr_mode */
|
||||
priv->otg_mode = usb_get_dr_mode(dev);
|
||||
|
||||
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
||||
/* Ack irq before registering */
|
||||
regmap_update_bits(priv->regmap, USB_R5,
|
||||
USB_R5_ID_DIG_IRQ, 0);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
dwc3_meson_g12a_irq_thread,
|
||||
IRQF_ONESHOT, pdev->name, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwc3_meson_g12a_usb_init(priv);
|
||||
|
||||
/* Init PHYs */
|
||||
@ -460,7 +487,6 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
||||
|
||||
/* Setup OTG mode corresponding to the ID pin */
|
||||
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
||||
/* TOFIX Handle ID mode toggling via IRQ */
|
||||
otg_id = dwc3_meson_g12a_get_id(priv);
|
||||
if (otg_id != priv->otg_phy_mode) {
|
||||
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
|
||||
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
|
||||
#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
|
||||
#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
|
||||
|
||||
#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
|
||||
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
|
||||
@ -339,6 +340,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
|
||||
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
|
||||
(kernel_ulong_t) &dwc3_pci_amd_properties, },
|
||||
{ } /* Terminating Entry */
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Inspired by dwc3-of-simple.c
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
@ -38,6 +39,20 @@
|
||||
#define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
|
||||
#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
|
||||
|
||||
#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800
|
||||
#define SDM845_QSCRATCH_SIZE 0x400
|
||||
#define SDM845_DWC3_CORE_SIZE 0xcd00
|
||||
|
||||
struct dwc3_acpi_pdata {
|
||||
u32 qscratch_base_offset;
|
||||
u32 qscratch_base_size;
|
||||
u32 dwc3_core_base_size;
|
||||
int hs_phy_irq_index;
|
||||
int dp_hs_phy_irq_index;
|
||||
int dm_hs_phy_irq_index;
|
||||
int ss_phy_irq_index;
|
||||
};
|
||||
|
||||
struct dwc3_qcom {
|
||||
struct device *dev;
|
||||
void __iomem *qscratch_base;
|
||||
@ -56,6 +71,8 @@ struct dwc3_qcom {
|
||||
struct notifier_block vbus_nb;
|
||||
struct notifier_block host_nb;
|
||||
|
||||
const struct dwc3_acpi_pdata *acpi_pdata;
|
||||
|
||||
enum usb_dr_mode mode;
|
||||
bool is_suspended;
|
||||
bool pm_suspended;
|
||||
@ -300,12 +317,27 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
|
||||
PIPE_UTMI_CLK_DIS);
|
||||
}
|
||||
|
||||
static int dwc3_qcom_get_irq(struct platform_device *pdev,
|
||||
const char *name, int num)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (np)
|
||||
ret = platform_get_irq_byname(pdev, name);
|
||||
else
|
||||
ret = platform_get_irq(pdev, num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
|
||||
const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "hs_phy_irq");
|
||||
irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
|
||||
pdata ? pdata->hs_phy_irq_index : -1);
|
||||
if (irq > 0) {
|
||||
/* Keep wakeup interrupts disabled until suspend */
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
@ -320,7 +352,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
|
||||
qcom->hs_phy_irq = irq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "dp_hs_phy_irq");
|
||||
irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
|
||||
pdata ? pdata->dp_hs_phy_irq_index : -1);
|
||||
if (irq > 0) {
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
|
||||
@ -334,7 +367,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
|
||||
qcom->dp_hs_phy_irq = irq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "dm_hs_phy_irq");
|
||||
irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
|
||||
pdata ? pdata->dm_hs_phy_irq_index : -1);
|
||||
if (irq > 0) {
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
|
||||
@ -348,7 +382,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
|
||||
qcom->dm_hs_phy_irq = irq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "ss_phy_irq");
|
||||
irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
|
||||
pdata ? pdata->ss_phy_irq_index : -1);
|
||||
if (irq > 0) {
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
|
||||
@ -371,11 +406,14 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
|
||||
struct device_node *np = dev->of_node;
|
||||
int i;
|
||||
|
||||
qcom->num_clocks = count;
|
||||
|
||||
if (!count)
|
||||
if (!np || !count)
|
||||
return 0;
|
||||
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
qcom->num_clocks = count;
|
||||
|
||||
qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
|
||||
sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!qcom->clks)
|
||||
@ -409,12 +447,115 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
static const struct property_entry dwc3_qcom_acpi_properties[] = {
|
||||
PROPERTY_ENTRY_STRING("dr_mode", "host"),
|
||||
{}
|
||||
};
|
||||
|
||||
static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res, *child_res = NULL;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
|
||||
if (!qcom->dwc3)
|
||||
return -ENOMEM;
|
||||
|
||||
qcom->dwc3->dev.parent = dev;
|
||||
qcom->dwc3->dev.type = dev->type;
|
||||
qcom->dwc3->dev.dma_mask = dev->dma_mask;
|
||||
qcom->dwc3->dev.dma_parms = dev->dma_parms;
|
||||
qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
|
||||
|
||||
child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
|
||||
if (!child_res)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to get memory resource\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
child_res[0].flags = res->flags;
|
||||
child_res[0].start = res->start;
|
||||
child_res[0].end = child_res[0].start +
|
||||
qcom->acpi_pdata->dwc3_core_base_size;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
child_res[1].flags = IORESOURCE_IRQ;
|
||||
child_res[1].start = child_res[1].end = irq;
|
||||
|
||||
ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = platform_device_add_properties(qcom->dwc3,
|
||||
dwc3_qcom_acpi_properties);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add properties\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = platform_device_add(qcom->dwc3);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to add device\n");
|
||||
|
||||
out:
|
||||
kfree(child_res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_qcom_of_register_core(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
|
||||
struct device_node *np = pdev->dev.of_node, *dwc3_np;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
dwc3_np = of_get_child_by_name(np, "dwc3");
|
||||
if (!dwc3_np) {
|
||||
dev_err(dev, "failed to find dwc3 core child\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 core - %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qcom->dwc3 = of_find_device_by_node(dwc3_np);
|
||||
if (!qcom->dwc3) {
|
||||
dev_err(dev, "failed to get dwc3 platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
|
||||
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
|
||||
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
|
||||
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
|
||||
.hs_phy_irq_index = 1,
|
||||
.dp_hs_phy_irq_index = 4,
|
||||
.dm_hs_phy_irq_index = 3,
|
||||
.ss_phy_irq_index = 2
|
||||
};
|
||||
|
||||
static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwc3_qcom *qcom;
|
||||
struct resource *res;
|
||||
struct resource *res, *parent_res = NULL;
|
||||
int ret, i;
|
||||
bool ignore_pipe_clk;
|
||||
|
||||
@ -425,6 +566,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, qcom);
|
||||
qcom->dev = &pdev->dev;
|
||||
|
||||
if (has_acpi_companion(dev)) {
|
||||
qcom->acpi_pdata = acpi_device_get_match_data(dev);
|
||||
if (!qcom->acpi_pdata) {
|
||||
dev_err(&pdev->dev, "no supporting ACPI device data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
|
||||
if (IS_ERR(qcom->resets)) {
|
||||
ret = PTR_ERR(qcom->resets);
|
||||
@ -446,15 +595,28 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
goto reset_assert;
|
||||
}
|
||||
|
||||
ret = dwc3_qcom_clk_init(qcom, of_count_phandle_with_args(np,
|
||||
"clocks", "#clock-cells"));
|
||||
ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get clocks\n");
|
||||
goto reset_assert;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
qcom->qscratch_base = devm_ioremap_resource(dev, res);
|
||||
|
||||
if (np) {
|
||||
parent_res = res;
|
||||
} else {
|
||||
parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
|
||||
if (!parent_res)
|
||||
return -ENOMEM;
|
||||
|
||||
parent_res->start = res->start +
|
||||
qcom->acpi_pdata->qscratch_base_offset;
|
||||
parent_res->end = parent_res->start +
|
||||
qcom->acpi_pdata->qscratch_base_size;
|
||||
}
|
||||
|
||||
qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
|
||||
if (IS_ERR(qcom->qscratch_base)) {
|
||||
dev_err(dev, "failed to map qscratch, err=%d\n", ret);
|
||||
ret = PTR_ERR(qcom->qscratch_base);
|
||||
@ -462,13 +624,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = dwc3_qcom_setup_irq(pdev);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
dwc3_np = of_get_child_by_name(np, "dwc3");
|
||||
if (!dwc3_np) {
|
||||
dev_err(dev, "failed to find dwc3 core child\n");
|
||||
ret = -ENODEV;
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
@ -481,16 +638,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
if (ignore_pipe_clk)
|
||||
dwc3_qcom_select_utmi_clk(qcom);
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 core - %d\n", ret);
|
||||
goto clk_disable;
|
||||
}
|
||||
if (np)
|
||||
ret = dwc3_qcom_of_register_core(pdev);
|
||||
else
|
||||
ret = dwc3_qcom_acpi_register_core(pdev);
|
||||
|
||||
qcom->dwc3 = of_find_device_by_node(dwc3_np);
|
||||
if (!qcom->dwc3) {
|
||||
dev_err(&pdev->dev, "failed to get dwc3 platform device\n");
|
||||
ret = -ENODEV;
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
|
||||
goto depopulate;
|
||||
}
|
||||
|
||||
@ -514,7 +668,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
depopulate:
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
if (np)
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
else
|
||||
platform_device_put(pdev);
|
||||
clk_disable:
|
||||
for (i = qcom->num_clocks - 1; i >= 0; i--) {
|
||||
clk_disable_unprepare(qcom->clks[i]);
|
||||
@ -601,6 +758,12 @@ static const struct of_device_id dwc3_qcom_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
|
||||
|
||||
static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
|
||||
{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
|
||||
|
||||
static struct platform_driver dwc3_qcom_driver = {
|
||||
.probe = dwc3_qcom_probe,
|
||||
.remove = dwc3_qcom_remove,
|
||||
@ -608,6 +771,7 @@ static struct platform_driver dwc3_qcom_driver = {
|
||||
.name = "dwc3-qcom",
|
||||
.pm = &dwc3_qcom_dev_pm_ops,
|
||||
.of_match_table = dwc3_qcom_of_match,
|
||||
.acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -379,6 +379,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state,
|
||||
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
|
||||
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
|
||||
return -EINVAL;
|
||||
if (set && dwc->dis_u1_entry_quirk)
|
||||
return -EINVAL;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (set)
|
||||
@ -401,6 +403,8 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
|
||||
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
|
||||
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
|
||||
return -EINVAL;
|
||||
if (set && dwc->dis_u2_entry_quirk)
|
||||
return -EINVAL;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (set)
|
||||
@ -626,7 +630,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
* nothing is pending from application.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
|
||||
if (!dwc->dis_u1_entry_quirk)
|
||||
reg |= DWC3_DCTL_ACCEPTU1ENA;
|
||||
if (!dwc->dis_u2_entry_quirk)
|
||||
reg |= DWC3_DCTL_ACCEPTU2ENA;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
break;
|
||||
|
@ -2073,6 +2073,25 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_config_params(struct usb_gadget *g,
|
||||
struct usb_dcd_config_params *params)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
|
||||
/* U1 Device exit Latency */
|
||||
if (dwc->dis_u1_entry_quirk)
|
||||
params->bU1devExitLat = 0;
|
||||
else
|
||||
params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
|
||||
|
||||
/* U2 Device exit Latency */
|
||||
if (dwc->dis_u2_entry_quirk)
|
||||
params->bU2DevExitLat = 0;
|
||||
else
|
||||
params->bU2DevExitLat =
|
||||
cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_set_speed(struct usb_gadget *g,
|
||||
enum usb_device_speed speed)
|
||||
{
|
||||
@ -2142,6 +2161,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
|
||||
.udc_start = dwc3_gadget_start,
|
||||
.udc_stop = dwc3_gadget_stop,
|
||||
.udc_set_speed = dwc3_gadget_set_speed,
|
||||
.get_config_params = dwc3_gadget_config_params,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -2251,8 +2271,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
|
||||
dep->endpoint.comp_desc = NULL;
|
||||
}
|
||||
|
||||
spin_lock_init(&dep->lock);
|
||||
|
||||
if (num == 0)
|
||||
ret = dwc3_gadget_init_control_endpoint(dep);
|
||||
else if (direction)
|
||||
|
@ -48,6 +48,12 @@ struct dwc3;
|
||||
/* DEPXFERCFG parameter 0 */
|
||||
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
|
||||
|
||||
/* U1 Device exit Latency */
|
||||
#define DWC3_DEFAULT_U1_DEV_EXIT_LAT 0x0A /* Less then 10 microsec */
|
||||
|
||||
/* U2 Device exit Latency */
|
||||
#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
|
||||
|
@ -653,7 +653,7 @@ static int bos_desc(struct usb_composite_dev *cdev)
|
||||
|
||||
/* Get Controller configuration */
|
||||
if (cdev->gadget->ops->get_config_params) {
|
||||
cdev->gadget->ops->get_config_params(
|
||||
cdev->gadget->ops->get_config_params(cdev->gadget,
|
||||
&dcd_config_params);
|
||||
} else {
|
||||
dcd_config_params.bU1devExitLat =
|
||||
|
@ -997,7 +997,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
* earlier
|
||||
*/
|
||||
gadget = epfile->ffs->gadget;
|
||||
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
|
||||
|
||||
spin_lock_irq(&epfile->ffs->eps_lock);
|
||||
/* In the meantime, endpoint got disabled or changed. */
|
||||
@ -1012,6 +1011,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
*/
|
||||
if (io_data->read)
|
||||
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
|
||||
|
||||
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
data = ffs_alloc_buffer(io_data, data_len);
|
||||
@ -1182,11 +1183,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
|
||||
ENTER();
|
||||
|
||||
if (!is_sync_kiocb(kiocb)) {
|
||||
p = kmalloc(sizeof(io_data), GFP_KERNEL);
|
||||
p = kzalloc(sizeof(io_data), GFP_KERNEL);
|
||||
if (unlikely(!p))
|
||||
return -ENOMEM;
|
||||
p->aio = true;
|
||||
} else {
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->aio = false;
|
||||
}
|
||||
|
||||
@ -1218,11 +1220,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
|
||||
ENTER();
|
||||
|
||||
if (!is_sync_kiocb(kiocb)) {
|
||||
p = kmalloc(sizeof(io_data), GFP_KERNEL);
|
||||
p = kzalloc(sizeof(io_data), GFP_KERNEL);
|
||||
if (unlikely(!p))
|
||||
return -ENOMEM;
|
||||
p->aio = true;
|
||||
} else {
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->aio = false;
|
||||
}
|
||||
|
||||
|
@ -2293,8 +2293,7 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
static void fsg_disable(struct usb_function *f)
|
||||
{
|
||||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
fsg->common->new_fsg = NULL;
|
||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
||||
raise_exception(fsg->common, FSG_STATE_DISCONNECT);
|
||||
}
|
||||
|
||||
|
||||
@ -2307,6 +2306,7 @@ static void handle_exception(struct fsg_common *common)
|
||||
enum fsg_state old_state;
|
||||
struct fsg_lun *curlun;
|
||||
unsigned int exception_req_tag;
|
||||
struct fsg_dev *fsg;
|
||||
|
||||
/*
|
||||
* Clear the existing signals. Anything but SIGUSR1 is converted
|
||||
@ -2413,9 +2413,19 @@ static void handle_exception(struct fsg_common *common)
|
||||
break;
|
||||
|
||||
case FSG_STATE_CONFIG_CHANGE:
|
||||
do_set_interface(common, common->new_fsg);
|
||||
if (common->new_fsg)
|
||||
fsg = common->new_fsg;
|
||||
/*
|
||||
* Add a check here to double confirm if a disconnect event
|
||||
* occurs and common->new_fsg has been cleared.
|
||||
*/
|
||||
if (fsg) {
|
||||
do_set_interface(common, fsg);
|
||||
usb_composite_setup_continue(common->cdev);
|
||||
}
|
||||
break;
|
||||
|
||||
case FSG_STATE_DISCONNECT:
|
||||
do_set_interface(common, NULL);
|
||||
break;
|
||||
|
||||
case FSG_STATE_EXIT:
|
||||
@ -2989,8 +2999,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
DBG(fsg, "unbind\n");
|
||||
if (fsg->common->fsg == fsg) {
|
||||
fsg->common->new_fsg = NULL;
|
||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
||||
raise_exception(fsg->common, FSG_STATE_DISCONNECT);
|
||||
/* FIXME: make interruptible or killable somehow? */
|
||||
wait_event(common->fsg_wait, common->fsg != fsg);
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ enum fsg_state {
|
||||
FSG_STATE_ABORT_BULK_OUT,
|
||||
FSG_STATE_PROTOCOL_RESET,
|
||||
FSG_STATE_CONFIG_CHANGE,
|
||||
FSG_STATE_DISCONNECT,
|
||||
FSG_STATE_EXIT,
|
||||
FSG_STATE_TERMINATED
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ struct uac_rtd_params {
|
||||
|
||||
void *rbuf;
|
||||
|
||||
unsigned max_psize; /* MaxPacketSize of endpoint */
|
||||
unsigned int max_psize; /* MaxPacketSize of endpoint */
|
||||
struct uac_req *ureq;
|
||||
|
||||
spinlock_t lock;
|
||||
@ -78,7 +78,7 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
|
||||
|
||||
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
unsigned pending;
|
||||
unsigned int pending;
|
||||
unsigned long flags, flags2;
|
||||
unsigned int hw_ptr;
|
||||
int status = req->status;
|
||||
|
@ -186,11 +186,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
||||
out = dev->port_usb->out_ep;
|
||||
else
|
||||
out = NULL;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
return -ENOTCONN;
|
||||
|
||||
}
|
||||
|
||||
/* Padding up to RX_EXTRA handles minor disagreements with host.
|
||||
* Normally we use the USB "terminate on short read" convention;
|
||||
@ -214,6 +215,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
||||
|
||||
if (dev->port_usb->is_fixed)
|
||||
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags);
|
||||
if (skb == NULL) {
|
||||
@ -1004,9 +1006,9 @@ int gether_get_ifname(struct net_device *net, char *name, int len)
|
||||
int ret;
|
||||
|
||||
rtnl_lock();
|
||||
ret = snprintf(name, len, "%s\n", netdev_name(net));
|
||||
ret = scnprintf(name, len, "%s\n", netdev_name(net));
|
||||
rtnl_unlock();
|
||||
return ret < len ? ret : len;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_get_ifname);
|
||||
|
||||
|
@ -799,7 +799,6 @@ static int at91_wakeup(struct usb_gadget *gadget)
|
||||
{
|
||||
struct at91_udc *udc = to_udc(gadget);
|
||||
u32 glbstate;
|
||||
int status = -EINVAL;
|
||||
unsigned long flags;
|
||||
|
||||
DBG("%s\n", __func__ );
|
||||
@ -818,7 +817,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reinit == restore initial software state */
|
||||
|
@ -481,7 +481,6 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
|
||||
struct fotg210_ep *ep;
|
||||
struct fotg210_udc *fotg210;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
ep = container_of(_ep, struct fotg210_ep, ep);
|
||||
|
||||
@ -504,7 +503,7 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ep->fotg210->lock, flags);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fotg210_ep_set_halt(struct usb_ep *_ep, int value)
|
||||
|
@ -1178,11 +1178,6 @@ registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
|
||||
size = PAGE_SIZE;
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
if (dev->driver)
|
||||
s = dev->driver->driver.name;
|
||||
else
|
||||
s = "(none)";
|
||||
|
||||
/* Main Control Registers */
|
||||
t = scnprintf(next, size, "%s version %s,"
|
||||
"chiprev %02x, locctl %02x\n"
|
||||
|
@ -2103,7 +2103,6 @@ done:
|
||||
static int omap_udc_stop(struct usb_gadget *g)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status = -ENODEV;
|
||||
|
||||
if (udc->dc_clk != NULL)
|
||||
omap_udc_enable_clock(1);
|
||||
@ -2125,7 +2124,7 @@ static int omap_udc_stop(struct usb_gadget *g)
|
||||
if (udc->dc_clk != NULL)
|
||||
omap_udc_enable_clock(0);
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -351,6 +351,8 @@ struct renesas_usb3 {
|
||||
int disabled_count;
|
||||
|
||||
struct usb_request *ep0_req;
|
||||
|
||||
enum usb_role connection_state;
|
||||
u16 test_mode;
|
||||
u8 ep0_buf[USB3_EP0_BUF_SIZE];
|
||||
bool softconnect;
|
||||
@ -359,6 +361,7 @@ struct renesas_usb3 {
|
||||
bool extcon_usb; /* check vbus and set EXTCON_USB */
|
||||
bool forced_b_device;
|
||||
bool start_to_connect;
|
||||
bool role_sw_by_connector;
|
||||
};
|
||||
|
||||
#define gadget_to_renesas_usb3(_gadget) \
|
||||
@ -699,8 +702,11 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&usb3->lock, flags);
|
||||
usb3_set_mode_by_role_sw(usb3, host);
|
||||
usb3_vbus_out(usb3, a_dev);
|
||||
if (!usb3->role_sw_by_connector ||
|
||||
usb3->connection_state != USB_ROLE_NONE) {
|
||||
usb3_set_mode_by_role_sw(usb3, host);
|
||||
usb3_vbus_out(usb3, a_dev);
|
||||
}
|
||||
/* for A-Peripheral or forced B-device mode */
|
||||
if ((!host && a_dev) || usb3->start_to_connect)
|
||||
usb3_connect(usb3);
|
||||
@ -716,7 +722,8 @@ static void usb3_check_id(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3->extcon_host = usb3_is_a_device(usb3);
|
||||
|
||||
if (usb3->extcon_host && !usb3->forced_b_device)
|
||||
if ((!usb3->role_sw_by_connector && usb3->extcon_host &&
|
||||
!usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST)
|
||||
usb3_mode_config(usb3, true, true);
|
||||
else
|
||||
usb3_mode_config(usb3, false, false);
|
||||
@ -2343,14 +2350,65 @@ static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
|
||||
return cur_role;
|
||||
}
|
||||
|
||||
static int renesas_usb3_role_switch_set(struct device *dev,
|
||||
enum usb_role role)
|
||||
static void handle_ext_role_switch_states(struct device *dev,
|
||||
enum usb_role role)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
struct device *host = usb3->host_dev;
|
||||
enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
|
||||
|
||||
switch (role) {
|
||||
case USB_ROLE_NONE:
|
||||
usb3->connection_state = USB_ROLE_NONE;
|
||||
if (usb3->driver)
|
||||
usb3_disconnect(usb3);
|
||||
usb3_vbus_out(usb3, false);
|
||||
break;
|
||||
case USB_ROLE_DEVICE:
|
||||
if (usb3->connection_state == USB_ROLE_NONE) {
|
||||
usb3->connection_state = USB_ROLE_DEVICE;
|
||||
usb3_set_mode(usb3, false);
|
||||
if (usb3->driver)
|
||||
usb3_connect(usb3);
|
||||
} else if (cur_role == USB_ROLE_HOST) {
|
||||
device_release_driver(host);
|
||||
usb3_set_mode(usb3, false);
|
||||
if (usb3->driver)
|
||||
usb3_connect(usb3);
|
||||
}
|
||||
usb3_vbus_out(usb3, false);
|
||||
break;
|
||||
case USB_ROLE_HOST:
|
||||
if (usb3->connection_state == USB_ROLE_NONE) {
|
||||
if (usb3->driver)
|
||||
usb3_disconnect(usb3);
|
||||
|
||||
usb3->connection_state = USB_ROLE_HOST;
|
||||
usb3_set_mode(usb3, true);
|
||||
usb3_vbus_out(usb3, true);
|
||||
if (device_attach(host) < 0)
|
||||
dev_err(dev, "device_attach(host) failed\n");
|
||||
} else if (cur_role == USB_ROLE_DEVICE) {
|
||||
usb3_disconnect(usb3);
|
||||
/* Must set the mode before device_attach of the host */
|
||||
usb3_set_mode(usb3, true);
|
||||
/* This device_attach() might sleep */
|
||||
if (device_attach(host) < 0)
|
||||
dev_err(dev, "device_attach(host) failed\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_role_switch_states(struct device *dev,
|
||||
enum usb_role role)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
struct device *host = usb3->host_dev;
|
||||
enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
|
||||
device_release_driver(host);
|
||||
usb3_set_mode(usb3, false);
|
||||
@ -2361,6 +2419,20 @@ static int renesas_usb3_role_switch_set(struct device *dev,
|
||||
if (device_attach(host) < 0)
|
||||
dev_err(dev, "device_attach(host) failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int renesas_usb3_role_switch_set(struct device *dev,
|
||||
enum usb_role role)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
if (usb3->role_sw_by_connector)
|
||||
handle_ext_role_switch_states(dev, role);
|
||||
else
|
||||
handle_role_switch_states(dev, role);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
@ -2650,7 +2722,7 @@ static const unsigned int renesas_usb3_cable[] = {
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
|
||||
static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
|
||||
.set = renesas_usb3_role_switch_set,
|
||||
.get = renesas_usb3_role_switch_get,
|
||||
.allow_userspace_control = true,
|
||||
@ -2741,6 +2813,11 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
goto err_dev_create;
|
||||
|
||||
if (device_property_read_bool(&pdev->dev, "usb-role-switch")) {
|
||||
usb3->role_sw_by_connector = true;
|
||||
renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev);
|
||||
}
|
||||
|
||||
INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
|
||||
usb3->role_sw = usb_role_switch_register(&pdev->dev,
|
||||
&renesas_usb3_role_switch_desc);
|
||||
|
@ -310,7 +310,8 @@ struct usb_gadget_ops {
|
||||
int (*pullup) (struct usb_gadget *, int is_on);
|
||||
int (*ioctl)(struct usb_gadget *,
|
||||
unsigned code, unsigned long param);
|
||||
void (*get_config_params)(struct usb_dcd_config_params *);
|
||||
void (*get_config_params)(struct usb_gadget *,
|
||||
struct usb_dcd_config_params *);
|
||||
int (*udc_start)(struct usb_gadget *,
|
||||
struct usb_gadget_driver *);
|
||||
int (*udc_stop)(struct usb_gadget *);
|
||||
|
Loading…
Reference in New Issue
Block a user